Skip to content

Commit d5e0b41

Browse files
Fix playground examples tab
Fixes #4605 by removing the `validator` from the `Example` samples - Updated the `examples.ts` to remove the `validator` that was causing the issue - Updated `Samples.ts` to remove the `validator` redefinition from the `Samples` types - Updated the `Playground` to add the `validator` back onto the `load` function, renaming `validator` to `theValidator` to avoid possible confusion with the state variable - Updated `Header` to remove `React.` with inputs and replaced `React.FC` with a real functional component using `PropsWithChildren` - Also fixed up type warning for `onSubthemeSelected` by using proper `SubthemeType`. - Made the `HeaderButtons` click handlers be `useCallback`s - Updated `SpecialInput` to remove `React.FC` in favor of a functional component using `PropsWithChildren`, extracting the `onChange` handler to a `useCallback` - Updated `SubthemeSelector.ts` to export the `SubthemeType` - Updated `ThemeSelector` and `ValidatorSelector` to extract the `onChange` handlers to a `useCallback`
1 parent 4e44e4c commit d5e0b41

File tree

8 files changed

+80
-53
lines changed

8 files changed

+80
-53
lines changed

packages/playground/src/components/Header.tsx

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { useCallback } from 'react';
1+
import {
2+
useCallback,
3+
ButtonHTMLAttributes,
4+
Dispatch,
5+
MutableRefObject,
6+
PropsWithChildren,
7+
SetStateAction,
8+
} from 'react';
29
import Form, { IChangeEvent } from '@rjsf/core';
310
import { RJSFSchema, UiSchema, ValidatorType } from '@rjsf/utils';
411
import localValidator from '@rjsf/validator-ajv8';
@@ -8,43 +15,43 @@ import CopyLink from './CopyLink';
815
import ThemeSelector, { ThemesType } from './ThemeSelector';
916
import SampleSelector, { SampleSelectorProps } from './SampleSelector';
1017
import ValidatorSelector from './ValidatorSelector';
11-
import SubthemeSelector from './SubthemeSelector';
18+
import SubthemeSelector, { SubthemeType } from './SubthemeSelector';
1219
import RawValidatorTest from './RawValidatorTest';
1320

14-
const HeaderButton: React.FC<
15-
{
16-
title: string;
17-
onClick: () => void;
18-
} & React.ButtonHTMLAttributes<HTMLButtonElement>
19-
> = ({ title, onClick, children, ...buttonProps }) => {
21+
type HeaderButtonProps = {
22+
title: string;
23+
onClick: () => void;
24+
} & ButtonHTMLAttributes<HTMLButtonElement>;
25+
26+
function HeaderButton({ title, onClick, children, ...buttonProps }: PropsWithChildren<HeaderButtonProps>) {
2027
return (
2128
<button type='button' className='btn btn-default' title={title} onClick={onClick} {...buttonProps}>
2229
{children}
2330
</button>
2431
);
25-
};
32+
}
2633

27-
function HeaderButtons({ playGroundFormRef }: { playGroundFormRef: React.MutableRefObject<any> }) {
34+
function HeaderButtons({ playGroundFormRef }: { playGroundFormRef: MutableRefObject<any> }) {
35+
const submitClick = useCallback(() => {
36+
playGroundFormRef.current.submit();
37+
}, [playGroundFormRef]);
38+
const validateClick = useCallback(() => {
39+
playGroundFormRef.current.validateForm();
40+
}, [playGroundFormRef]);
41+
const resetClick = useCallback(() => {
42+
playGroundFormRef.current.reset();
43+
}, [playGroundFormRef]);
2844
return (
2945
<>
3046
<label className='control-label'>Programmatic</label>
3147
<div className='btn-group'>
32-
<HeaderButton
33-
title='Click me to submit the form programmatically.'
34-
onClick={() => playGroundFormRef.current.submit()}
35-
>
48+
<HeaderButton title='Click me to submit the form programmatically.' onClick={submitClick}>
3649
Submit
3750
</HeaderButton>
38-
<HeaderButton
39-
title='Click me to validate the form programmatically.'
40-
onClick={() => playGroundFormRef.current.validateForm()}
41-
>
51+
<HeaderButton title='Click me to validate the form programmatically.' onClick={validateClick}>
4252
Validate
4353
</HeaderButton>
44-
<HeaderButton
45-
title='Click me to reset the form programmatically.'
46-
onClick={() => playGroundFormRef.current.reset()}
47-
>
54+
<HeaderButton title='Click me to reset the form programmatically.' onClick={resetClick}>
4855
Reset
4956
</HeaderButton>
5057
</div>
@@ -242,14 +249,14 @@ type HeaderProps = {
242249
};
243250
validator: string;
244251
liveSettings: LiveSettings;
245-
playGroundFormRef: React.MutableRefObject<any>;
252+
playGroundFormRef: MutableRefObject<any>;
246253
onSampleSelected: SampleSelectorProps['onSelected'];
247254
onThemeSelected: (theme: string, themeObj: ThemesType) => void;
248-
setSubtheme: React.Dispatch<React.SetStateAction<string | null>>;
249-
setStylesheet: React.Dispatch<React.SetStateAction<string | null>>;
250-
setValidator: React.Dispatch<React.SetStateAction<string>>;
251-
setLiveSettings: React.Dispatch<React.SetStateAction<LiveSettings>>;
252-
setShareURL: React.Dispatch<React.SetStateAction<string | null>>;
255+
setSubtheme: Dispatch<SetStateAction<string | null>>;
256+
setStylesheet: Dispatch<SetStateAction<string | null>>;
257+
setValidator: Dispatch<SetStateAction<string>>;
258+
setLiveSettings: Dispatch<SetStateAction<LiveSettings>>;
259+
setShareURL: Dispatch<SetStateAction<string | null>>;
253260
};
254261

255262
export default function Header({
@@ -274,9 +281,9 @@ export default function Header({
274281
onSampleSelected,
275282
}: HeaderProps) {
276283
const onSubthemeSelected = useCallback(
277-
(subtheme: any, { stylesheet }: { stylesheet: any }) => {
284+
(subtheme: any, { stylesheet }: SubthemeType) => {
278285
setSubtheme(subtheme);
279-
setStylesheet(stylesheet);
286+
setStylesheet(stylesheet || null);
280287
},
281288
[setSubtheme, setStylesheet],
282289
);

packages/playground/src/components/Playground.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export default function Playground({ themes, validators }: PlaygroundProps) {
6363
);
6464

6565
const load = useCallback(
66-
(data: Sample & { theme: string; liveSettings: LiveSettings; sampleName?: string }) => {
66+
(data: Sample & { theme: string; liveSettings: LiveSettings; sampleName?: string; validator?: string }) => {
6767
const {
6868
schema,
6969
// uiSchema is missing on some examples. Provide a default to
@@ -76,7 +76,7 @@ export default function Playground({ themes, validators }: PlaygroundProps) {
7676
theme: dataTheme = theme,
7777
extraErrors,
7878
liveSettings,
79-
validator,
79+
validator: theValidator,
8080
sampleName,
8181
...rest
8282
} = data;
@@ -110,8 +110,8 @@ export default function Playground({ themes, validators }: PlaygroundProps) {
110110
setExtraErrors(extraErrors);
111111
setShowForm(true);
112112
setLiveSettings(liveSettings);
113-
if ('validator' in data && validator !== undefined) {
114-
setValidator(validator);
113+
if ('validator' in data && theValidator !== undefined) {
114+
setValidator(theValidator);
115115
}
116116
setOtherFormProps({ fields, templates, ...rest });
117117
},
Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
import { ChangeEvent, PropsWithChildren, useCallback, useState } from 'react';
12
import { FieldProps } from '@rjsf/utils';
2-
import { FC, useState } from 'react';
33

44
const COLORS = ['red', 'green', 'blue'];
55

6-
const SpecialInput: FC<FieldProps<string>> = ({ onChange, formData }) => {
6+
export default function SpecialInput({ onChange, formData }: PropsWithChildren<FieldProps>) {
77
const [text, setText] = useState<string>(formData || '');
88

99
const inputBgColor = COLORS[text.length % COLORS.length];
1010

11+
const handleOnChange = useCallback(
12+
({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
13+
onChange(value);
14+
setText(value);
15+
},
16+
[onChange, setText],
17+
);
18+
1119
return (
1220
<div className='SpecialInput'>
1321
<h3>Hey, I&apos;m a custom component</h3>
@@ -23,15 +31,10 @@ const SpecialInput: FC<FieldProps<string>> = ({ onChange, formData }) => {
2331
className='form-control'
2432
style={{ background: inputBgColor, color: 'white', fontSize: 14 }}
2533
value={text}
26-
onChange={({ target: { value } }) => {
27-
onChange(value);
28-
setText(value);
29-
}}
34+
onChange={handleOnChange}
3035
/>
3136
</div>
3237
</div>
3338
</div>
3439
);
35-
};
36-
37-
export default SpecialInput;
40+
}

packages/playground/src/components/SubthemeSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const uiSchema: UiSchema = {
77
'ui:placeholder': 'Select subtheme',
88
};
99

10-
interface SubthemeType {
10+
export interface SubthemeType {
1111
stylesheet?: string;
1212
dataTheme?: string;
1313
}

packages/playground/src/components/ThemeSelector.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { useCallback } from 'react';
12
import Form, { IChangeEvent } from '@rjsf/core';
23
import { RJSFSchema, UiSchema } from '@rjsf/utils';
34
import localValidator from '@rjsf/validator-ajv8';
5+
46
import { SubthemesType } from './SubthemeSelector';
57

68
export interface ThemesType {
@@ -26,6 +28,15 @@ export default function ThemeSelector({ theme, themes, select }: ThemeSelectorPr
2628
'ui:placeholder': 'Select theme',
2729
};
2830

31+
const onChange = useCallback(
32+
({ formData }: IChangeEvent) => {
33+
if (formData) {
34+
select(formData, themes[formData]);
35+
}
36+
},
37+
[select, themes],
38+
);
39+
2940
return (
3041
<Form
3142
className='form_rjsf_themeSelector'
@@ -34,7 +45,7 @@ export default function ThemeSelector({ theme, themes, select }: ThemeSelectorPr
3445
uiSchema={uiSchema}
3546
formData={theme}
3647
validator={localValidator}
37-
onChange={({ formData }: IChangeEvent) => formData && select(formData, themes[formData])}
48+
onChange={onChange}
3849
>
3950
<div />
4051
</Form>

packages/playground/src/components/ValidatorSelector.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { useCallback } from 'react';
12
import Form, { IChangeEvent } from '@rjsf/core';
2-
import { GenericObjectType, RJSFSchema, UiSchema } from '@rjsf/utils';
3+
import { RJSFSchema, UiSchema, ValidatorType } from '@rjsf/utils';
34
import localValidator from '@rjsf/validator-ajv8';
45

56
interface ValidatorSelectorProps {
67
validator: string;
7-
validators: GenericObjectType;
8+
validators: { [validatorName: string]: ValidatorType };
89
select: (validator: string) => void;
910
}
1011

@@ -19,6 +20,15 @@ export default function ValidatorSelector({ validator, validators, select }: Val
1920
'ui:placeholder': 'Select validator',
2021
};
2122

23+
const onChange = useCallback(
24+
({ formData }: IChangeEvent) => {
25+
if (formData) {
26+
select(formData);
27+
}
28+
},
29+
[select],
30+
);
31+
2232
return (
2333
<Form
2434
className='form_rjsf_validatorSelector'
@@ -27,7 +37,7 @@ export default function ValidatorSelector({ validator, validators, select }: Val
2737
uiSchema={uiSchema}
2838
formData={validator}
2939
validator={localValidator}
30-
onChange={({ formData }: IChangeEvent) => formData && select(formData)}
40+
onChange={onChange}
3141
>
3242
<div />
3343
</Form>

packages/playground/src/samples/Sample.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ import { FormProps } from '@rjsf/core';
44
export type UiSchemaForTheme = (theme: string) => UiSchema;
55

66
export interface Sample extends Omit<FormProps, 'validator' | 'uiSchema'> {
7-
validator?: string;
8-
uiSchema: FormProps['uiSchema'] | UiSchemaForTheme;
7+
uiSchema?: FormProps['uiSchema'] | UiSchemaForTheme;
98
}

packages/playground/src/samples/examples.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import validator from '@rjsf/validator-ajv8';
2-
31
import { Sample } from './Sample';
42

53
const examples: Sample = {
6-
validator: validator,
74
schema: {
85
title: 'Examples',
96
description: 'A text field with example values.',

0 commit comments

Comments
 (0)