Skip to content

Commit

Permalink
[charts] Allow controlling the demo form from the example (#13796)
Browse files Browse the repository at this point in the history
  • Loading branch information
JCQuintas committed Jul 12, 2024
1 parent 4765a52 commit c3b2f37
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 54 deletions.
52 changes: 29 additions & 23 deletions docs/src/modules/components/ChartsUsageDemo.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,22 @@ export default function ChartsUsageDemo({
renderDemo,
getCode,
}) {
const initialProps = {};
let demoProps = {};
let codeBlockProps = {};
data.forEach((p) => {
demoProps[p.propName] = p.defaultValue;
if (p.codeBlockDisplay) {
initialProps[p.propName] = p.defaultValue;
}
if (!p.knob) {
codeBlockProps[p.propName] = p.defaultValue;
}
});
const [props, setProps] = React.useState(initialProps);
demoProps = { ...demoProps, ...props };
codeBlockProps = { ...props, ...codeBlockProps };
data.forEach((p) => {
if (p.codeBlockDisplay === false) {
delete codeBlockProps[p.propName];
}
});
const [props, setProps] = React.useState(
data.reduce((acc, { propName, defaultValue }) => {
acc[propName] = defaultValue;
return acc;
}, {}),
);

React.useEffect(() => {
setProps(
data.reduce((acc, { propName, defaultValue }) => {
acc[propName] = defaultValue;
return acc;
}, {}),
);
}, [data]);

return (
<Box
sx={{
Expand All @@ -55,21 +51,31 @@ export default function ChartsUsageDemo({
width: '100%',
}}
>
{renderDemo(demoProps)}
{renderDemo(props, setProps)}
</Box>
<BrandingProvider mode="dark">
<HighlightedCode
code={getCode({
name: componentName,
props: codeBlockProps,
props: Object.entries(props).reduce((acc, [key, value]) => {
if (data.find((d) => d.propName === key)?.codeBlockDisplay !== false) {
acc[key] = value;
}
return acc;
}, {}),
childrenAccepted,
})}
language="jsx"
sx={{ display: { xs: 'none', md: 'block' } }}
/>
</BrandingProvider>
</Box>
<DemoPropsForm data={data} componentName={componentName} onPropsChange={setProps} />
<DemoPropsForm
data={data}
props={props}
componentName={componentName}
onPropsChange={setProps}
/>
</Box>
);
}
Expand Down
93 changes: 62 additions & 31 deletions docs/src/modules/components/DemoPropsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import FormLabel, { formLabelClasses } from '@mui/material/FormLabel';
import IconButton from '@mui/material/IconButton';
import Input, { inputClasses } from '@mui/material/Input';
import MenuItem from '@mui/material/MenuItem';
import Slider from '@mui/material/Slider';

import FormControlLabel, { formControlLabelClasses } from '@mui/material/FormControlLabel';
import Radio from '@mui/material/Radio';
Expand All @@ -30,20 +31,30 @@ const shallowEqual = (item1: { [k: string]: any }, item2: { [k: string]: any })
return equal;
};

type DataType<ComponentProps> = {
type DataType<PropName> = {
/**
* Name of the prop, for example 'children'
*/
propName: Extract<keyof ComponentProps, string>;
propName: PropName;
/**
* The controller to be used:
* - `switch`: render the switch component for boolean
* - `color`: render the built-in color selector
* - `select`: render <select> with the specified options
* - `input`: render <input />
* - `radio`: render group of radios
* - `slider`: render the slider component
*/
knob?: 'switch' | 'color' | 'select' | 'input' | 'radio' | 'controlled' | 'number' | 'placement';
knob:
| 'switch'
| 'color'
| 'select'
| 'input'
| 'radio'
| 'controlled'
| 'number'
| 'placement'
| 'slider';
/**
* The options for these knobs: `select` and `radio`
*/
Expand Down Expand Up @@ -78,18 +89,22 @@ type DataType<ComponentProps> = {
* Option for knobs: `number`
*/
max?: number;
}[];
};

interface ChartDemoPropsFormProps<ComponentProps> {
interface ChartDemoPropsFormProps<PropName extends string> {
/**
* Name of the component to show in the code block.
*/
componentName: string;
/**
* Configuration
*/
data: DataType<ComponentProps>;
onPropsChange: (data: any) => void;
data: DataType<PropName>[];
/**
* Props to be displayed in the form
*/
props: Record<PropName, any>;
onPropsChange: (data: Record<PropName, any> | ((data: Record<PropName, any>) => void)) => void;
}

function ControlledColorRadio(props: any) {
Expand Down Expand Up @@ -131,26 +146,23 @@ function ControlledColorRadio(props: any) {
);
}

export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>({
export default function ChartDemoPropsForm<T extends string>({
componentName,
data,
props,
onPropsChange,
}: ChartDemoPropsFormProps<T>) {
const initialProps = {} as { [k in keyof T]: any };
let demoProps = {} as { [k in keyof T]: any };

data.forEach((p) => {
demoProps[p.propName] = p.defaultValue;

initialProps[p.propName] = p.defaultValue;
});
const [props, setProps] = React.useState<T>(initialProps as T);

React.useEffect(() => {
onPropsChange(props);
}, [props, onPropsChange]);

demoProps = { ...demoProps, ...props };
const initialProps = React.useMemo<Record<T, any>>(
() =>
data.reduce(
(acc, { propName, defaultValue }) => {
acc[propName] = defaultValue;
return acc;
},
{} as Record<T, any>,
),
[data],
);

return (
<Box
Expand Down Expand Up @@ -187,7 +199,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
<IconButton
aria-label="Reset all"
size="small"
onClick={() => setProps(initialProps as T)}
onClick={() => onPropsChange(initialProps)}
sx={{
visibility: !shallowEqual(props, initialProps) ? 'visible' : 'hidden',
'--IconButton-size': '30px',
Expand Down Expand Up @@ -224,7 +236,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
<Switch
checked={Boolean(resolvedValue)}
onChange={(event) =>
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: event.target.checked,
}))
Expand All @@ -233,6 +245,25 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
</FormControl>
);
}
if (knob === 'slider') {
return (
<FormControl key={propName}>
<FormLabel>{propName}</FormLabel>
<Slider
value={Number.parseFloat(`${resolvedValue}`)}
onChange={(_, value) =>
onPropsChange((latestProps) => ({
...latestProps,
[propName]: Number.parseFloat(`${value}`),
}))
}
step={step}
min={min}
max={max}
/>
</FormControl>
);
}
if (knob === 'radio') {
const labelId = `${componentName}-${propName}`;
return (
Expand All @@ -251,7 +282,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
} else if (value === 'undefined') {
value = undefined;
}
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: value,
}));
Expand Down Expand Up @@ -282,7 +313,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
name={`${componentName}-color`}
value={resolvedValue || ''}
onChange={(event) =>
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: event.target.value,
}))
Expand Down Expand Up @@ -317,7 +348,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
placeholder="Select a variant..."
value={(resolvedValue || 'none') as string}
onChange={(event) =>
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: event.target.value,
}))
Expand All @@ -340,7 +371,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
size="small"
value={props[propName] ?? ''}
onChange={(event) =>
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: event.target.value,
}))
Expand Down Expand Up @@ -371,7 +402,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
if (Number.isNaN(Number.parseFloat(event.target.value))) {
return;
}
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: Number.parseFloat(event.target.value),
}));
Expand Down Expand Up @@ -401,7 +432,7 @@ export default function ChartDemoPropsForm<T extends { [k: string]: any } = {}>(
name="placement"
value={resolvedValue}
onChange={(event) =>
setProps((latestProps) => ({
onPropsChange((latestProps) => ({
...latestProps,
[propName]: event.target.value,
}))
Expand Down

0 comments on commit c3b2f37

Please sign in to comment.