diff --git a/src-docs/src/routes.js b/src-docs/src/routes.js
index e22299234fc..1b266d99632 100644
--- a/src-docs/src/routes.js
+++ b/src-docs/src/routes.js
@@ -1,4 +1,4 @@
-import React, { createElement } from 'react';
+import React, { createElement, Fragment } from 'react';
import { GuidePage, GuideSection } from './components';
@@ -263,7 +263,11 @@ const createExample = (example, customTitle) => {
let playgroundComponent;
if (playground) {
- playgroundComponent = playgroundCreator(playground());
+ if (Array.isArray(playground)) {
+ playgroundComponent = playground.map((elm, idx) => {
+ return {playgroundCreator(elm())};
+ });
+ } else playgroundComponent = playgroundCreator(playground());
}
const component = () => (
diff --git a/src-docs/src/services/playground/knobs.js b/src-docs/src/services/playground/knobs.js
index 37e724d726f..c79b328a8a4 100644
--- a/src-docs/src/services/playground/knobs.js
+++ b/src-docs/src/services/playground/knobs.js
@@ -1,5 +1,5 @@
-import React from 'react';
-import { assertUnreachable, PropTypes, useValueDebounce } from 'react-view';
+import React, { useState, useEffect } from 'react';
+import { assertUnreachable, PropTypes } from 'react-view';
import {
EuiSpacer,
EuiSwitch,
@@ -15,6 +15,8 @@ import {
EuiTableHeaderCell,
EuiTableRow,
EuiTableRowCell,
+ EuiTextColor,
+ EuiFormRow,
} from '../../../../src/components/';
import {
@@ -44,17 +46,26 @@ const Label = ({ children, tooltip }) => {
const Knob = ({
name,
- error,
+ error: errorMsg,
type,
defaultValue,
- val: globalVal,
- set: globalSet,
+ val,
+ set,
options = {},
description,
placeholder,
custom,
+ state,
}) => {
- const [val, set] = useValueDebounce(globalVal, globalSet);
+ const [error, setError] = useState(errorMsg);
+
+ useEffect(() => {
+ if (custom && custom.checkDep) {
+ setError(custom.checkDep(val, state));
+ }
+ }, [state, val, custom]);
+
+ let knobProps = {};
switch (type) {
case PropTypes.Ref:
return (
@@ -92,27 +103,45 @@ const Knob = ({
case PropTypes.String:
case PropTypes.Date:
+ if (custom && custom.validator) {
+ knobProps = {};
+ knobProps.onChange = e => {
+ const value = e.target.value;
+ if (custom.validator(value)) set(value);
+ else set(undefined);
+ };
+ } else if (custom && custom.sanitize) {
+ knobProps = {};
+ knobProps.value = val;
+ knobProps.onChange = e => {
+ const value = e.target.value;
+ set(custom.sanitize(value));
+ };
+ } else {
+ knobProps = {};
+ knobProps.value = val;
+ knobProps.onChange = e => {
+ const value = e.target.value;
+ set(value);
+ };
+ }
+
return (
- <>
+ 0}
+ error={error}
+ fullWidth>
{
- const value = e.target.value;
- if (custom && custom.validator) {
- if (custom.validator(value)) set(value);
- else set(undefined);
- } else {
- set(value);
- }
- }}
aria-label={description}
+ isInvalid={error && error.length > 0}
compressed
fullWidth
+ {...knobProps}
/>
-
- {error && error {error}
}
- >
+
);
+
case PropTypes.Boolean:
return (
<>
@@ -121,13 +150,14 @@ const Knob = ({
label=""
checked={val}
onChange={e => {
- globalSet(e.target.checked);
+ set(e.target.checked);
}}
compressed
/>
{error &&
error {error}
}
>
);
+
case PropTypes.Enum:
const optionsKeys = Object.keys(options);
const numberOfOptions = optionsKeys.length;
@@ -151,7 +181,7 @@ const Knob = ({
onChange={id => {
let val = id;
if (val.includes('__')) val = val.split('__')[0];
- globalSet(val);
+ set(val);
}}
name={`Select ${name}`}
/>
@@ -165,28 +195,52 @@ const Knob = ({
}));
return (
- <>
+ 0}
+ error={error}
+ fullWidth>
{
- globalSet(e.target.value);
+ set(e.target.value);
}}
+ isInvalid={error && error.length > 0}
aria-label={`Select ${name}`}
compressed
/>
- {error && error {error}
}
- >
+
);
}
+ case PropTypes.Custom:
+ if (custom && custom.use) {
+ switch (custom.use) {
+ case 'switch':
+ return (
+ <>
+ {
+ const value = e.target.checked;
+
+ set(value ? value : undefined);
+ }}
+ compressed
+ />
+ >
+ );
+ }
+ }
+
case PropTypes.ReactNode:
case PropTypes.Function:
case PropTypes.Array:
case PropTypes.Object:
- case PropTypes.Custom:
return null;
default:
return assertUnreachable();
@@ -210,13 +264,30 @@ const KnobColumn = ({ state, knobNames, error, set }) => {
{markup(humanizedType)}
);
+ let humanizedName = (
+ {name}
+ );
+
+ if (
+ state[name].custom &&
+ state[name].custom.origin &&
+ state[name].custom.origin.required
+ ) {
+ humanizedName = (
+
+ {humanizedName}{' '}
+ (required)
+
+ );
+ }
+
return (
- {name}
+ {humanizedName}
{state[name].description && (
<>
@@ -257,7 +328,9 @@ const KnobColumn = ({ state, knobNames, error, set }) => {
set={value => set(value, name)}
enumName={state[name].enumName}
defaultValue={state[name].defaultValue}
- custom={state[name].custom}
+ custom={state[name] && state[name].custom}
+ state={state}
+ orgSet={set}
/>
diff --git a/src-docs/src/services/playground/playground.js b/src-docs/src/services/playground/playground.js
index 6c23d46a956..7c23dd19114 100644
--- a/src-docs/src/services/playground/playground.js
+++ b/src-docs/src/services/playground/playground.js
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
import classNames from 'classnames';
import format from 'html-format';
-import { useView, Compiler, Error, Placeholder } from 'react-view';
+import { useView, Compiler, Placeholder } from 'react-view';
import { EuiSpacer, EuiTitle, EuiCodeBlock } from '../../../../src/components';
import Knobs from './knobs';
@@ -61,15 +61,9 @@ export default ({ config, setGhostBackground }) => {
placeholder={Placeholder}
/>
-
-
+
{getSnippet(params.editorProps.code)}
diff --git a/src-docs/src/services/playground/props.js b/src-docs/src/services/playground/props.js
index 97e82585bb8..3809e60d88f 100644
--- a/src-docs/src/services/playground/props.js
+++ b/src-docs/src/services/playground/props.js
@@ -1,7 +1,7 @@
/* eslint-disable guard-for-in */
import { PropTypes } from 'react-view';
-const getProp = (prop, propName) => {
+const getProp = prop => {
const newProp = {};
if (prop.description) newProp.description = prop.description;
newProp.custom = { origin: prop };
@@ -23,13 +23,8 @@ const getProp = (prop, propName) => {
newProp.required = prop.required;
if (prop.defaultValue) {
newProp.defaultValue = prop.defaultValue.value;
- newProp.value = prop.defaultValue.value.substring(
- 1,
- prop.defaultValue.value.length - 1
- );
- } else {
- newProp.value = undefined;
}
+ newProp.value = undefined;
newProp.options = {};
for (const i in prop.type.value) {
const val = prop.type.value[i].value;
@@ -40,30 +35,24 @@ const getProp = (prop, propName) => {
case 'number':
newProp.type = PropTypes.Number;
- newProp.placeholder = propName;
- if (prop.defaultValue) newProp.value = prop.defaultValue.value;
- else newProp.value = 0;
+ if (prop.defaultValue) newProp.defaultValue = prop.defaultValue.value;
break;
case 'string':
newProp.type = PropTypes.String;
- newProp.placeholder = propName;
- if (prop.defaultValue) newProp.value = prop.defaultValue.value;
- else newProp.value = '';
+ if (prop.defaultValue) newProp.defaultValue = prop.defaultValue.value;
break;
case 'func':
newProp.type = PropTypes.Function;
- newProp.placeholder = propName;
break;
case 'node':
case 'element':
newProp.type = PropTypes.ReactNode;
- newProp.placeholder = propName;
- if (prop.defaultValue) newProp.value = prop.defaultValue.value;
- else newProp.value = undefined;
+ if (prop.defaultValue) newProp.defaultValue = prop.defaultValue.value;
+ newProp.value = undefined;
break;
default:
@@ -78,7 +67,7 @@ const propUtilityForPlayground = props => {
const modifiedProps = {};
for (const key in props) {
- if (props[key].type) modifiedProps[key] = getProp(props[key], key);
+ if (props[key].type) modifiedProps[key] = getProp(props[key]);
}
return modifiedProps;
};
diff --git a/src-docs/src/views/badge/badge_example.js b/src-docs/src/views/badge/badge_example.js
index 703c6c4fbb3..60f815c12c1 100644
--- a/src-docs/src/views/badge/badge_example.js
+++ b/src-docs/src/views/badge/badge_example.js
@@ -14,6 +14,11 @@ import {
EuiBadgeGroup,
EuiCallOut,
} from '../../../../src/components';
+import {
+ badgeConfig,
+ betaBadgeConfig,
+ notificationBadgeConfig,
+} from './playground';
import Badge from './badge';
@@ -317,4 +322,5 @@ export const BadgeExample = {
demo: ,
},
],
+ playground: [badgeConfig, betaBadgeConfig, notificationBadgeConfig],
};
diff --git a/src-docs/src/views/badge/playground.js b/src-docs/src/views/badge/playground.js
new file mode 100644
index 00000000000..18163a71828
--- /dev/null
+++ b/src-docs/src/views/badge/playground.js
@@ -0,0 +1,187 @@
+import { PropTypes } from 'react-view';
+import {
+ EuiBadge,
+ EuiNotificationBadge,
+ EuiBetaBadge,
+} from '../../../../src/components/';
+import {
+ propUtilityForPlayground,
+ mapOptions,
+} from '../../services/playground';
+import { iconTypes } from '../icon/icons';
+import * as t from '@babel/types';
+
+const iconOptions = mapOptions(iconTypes);
+
+export const badgeConfig = () => {
+ const docgenInfo = Array.isArray(EuiBadge.__docgenInfo)
+ ? EuiBadge.__docgenInfo[0]
+ : EuiBadge.__docgenInfo;
+ const propsToUse = propUtilityForPlayground(docgenInfo.props);
+
+ propsToUse.onClick = {
+ ...propsToUse.onClick,
+ type: PropTypes.Custom,
+ value: undefined,
+ custom: {
+ ...propsToUse.onClick.custom,
+ use: 'switch',
+ label: 'Simulate',
+ modifyOtherProps: (val, state, set) => {
+ console.log(val, 'state', state);
+ if (val) {
+ if (!state.onClickAriaLabel.value) {
+ set('onClickAriaLabel', 'onClickAriaLabel');
+ }
+ } else {
+ set(state.onClickAriaLabel.value, 'onClickAriaLabel');
+ }
+ },
+ },
+ };
+
+ propsToUse.children = {
+ type: PropTypes.String,
+ value: 'Badge content',
+ hidden: true,
+ custom: {
+ sanitize: val => {
+ return val.replace(/<(?:"[^"]"['"]|'[^']'['"]|[^'">])+>/g, '');
+ },
+ },
+ };
+
+ propsToUse.onClickAriaLabel = {
+ ...propsToUse.onClickAriaLabel,
+ type: PropTypes.String,
+ custom: {
+ ...propsToUse.onClickAriaLabel.custom,
+ checkDep: (val, state) => {
+ if (state.onClick.value && !val) {
+ return 'When passing onClick to EuiBadge, you must also provide onClickAriaLabel';
+ }
+ return undefined;
+ },
+ },
+ };
+
+ propsToUse.iconOnClickAriaLabel = {
+ ...propsToUse.iconOnClickAriaLabel,
+ type: PropTypes.String,
+ };
+
+ propsToUse.iconType = {
+ ...propsToUse.iconType,
+ value: undefined,
+ type: PropTypes.String,
+ custom: {
+ ...propsToUse.iconType.custom,
+ validator: val => iconOptions[val],
+ },
+ };
+
+ propsToUse.color = {
+ ...propsToUse.color,
+ value: undefined,
+ type: PropTypes.String,
+ };
+
+ return {
+ config: {
+ componentName: 'EuiBadge',
+ props: propsToUse,
+ scope: {
+ EuiBadge,
+ },
+ imports: {
+ '@elastic/eui': {
+ named: ['EuiBadge'],
+ },
+ },
+ customProps: {
+ onClick: {
+ generate: val => {
+ if (!val) return null;
+ const obj = t.arrowFunctionExpression(
+ [],
+ t.blockStatement([]),
+ false
+ );
+ return obj;
+ },
+ },
+ },
+ },
+ };
+};
+
+export const betaBadgeConfig = () => {
+ const docgenInfo = Array.isArray(EuiBetaBadge.__docgenInfo)
+ ? EuiBetaBadge.__docgenInfo[0]
+ : EuiBetaBadge.__docgenInfo;
+ const propsToUse = propUtilityForPlayground(docgenInfo.props);
+
+ propsToUse.label = {
+ ...propsToUse.label,
+ type: PropTypes.String,
+ value: 'content',
+ };
+
+ propsToUse.tooltipContent = {
+ ...propsToUse.tooltipContent,
+ type: PropTypes.String,
+ };
+
+ propsToUse.iconType = {
+ ...propsToUse.iconType,
+ value: undefined,
+ type: PropTypes.String,
+ custom: {
+ ...propsToUse.iconType.custom,
+ validator: val => iconOptions[val],
+ },
+ };
+
+ return {
+ config: {
+ componentName: 'EuiBetaBadge',
+ props: propsToUse,
+ scope: {
+ EuiBetaBadge,
+ },
+ imports: {
+ '@elastic/eui': {
+ named: ['EuiBetaBadge'],
+ },
+ },
+ },
+ };
+};
+
+export const notificationBadgeConfig = () => {
+ const docgenInfo = Array.isArray(EuiNotificationBadge.__docgenInfo)
+ ? EuiNotificationBadge.__docgenInfo[0]
+ : EuiNotificationBadge.__docgenInfo;
+ const propsToUse = propUtilityForPlayground(docgenInfo.props);
+
+ propsToUse.children = {
+ type: PropTypes.String,
+ value: '10',
+ hidden: true,
+ };
+
+ return {
+ config: {
+ componentName: 'EuiNotificationBadge',
+ props: propsToUse,
+ scope: {
+ EuiNotificationBadge,
+ },
+ imports: {
+ '@elastic/eui': {
+ named: ['EuiNotificationBadge'],
+ },
+ },
+ },
+ };
+};