Skip to content

Commit eef5138

Browse files
committed
chore: Improve playground
1 parent 9e440ad commit eef5138

2 files changed

Lines changed: 323 additions & 35 deletions

File tree

packages/website/src/components/playground/OptionPanel.tsx

Lines changed: 188 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ import { Select } from 'nextra/components';
33
import { CheckIcon } from 'nextra/icons';
44

55
interface OptionPanelProps {
6+
handlerPreset: HandlerPreset;
67
language: Language;
8+
resolverPreset: ResolverPreset;
9+
selectedHandlerIds: HandlerId[];
10+
onHandlerPresetChange: (preset: HandlerPreset) => void;
11+
onHandlerToggle: (handlerId: HandlerId) => void;
712
onLanguageChange: (language: Language) => void;
13+
onResolverPresetChange: (preset: ResolverPreset) => void;
814
}
915

1016
export enum Language {
@@ -13,38 +19,199 @@ export enum Language {
1319
TYPESCRIPT = 'ts',
1420
}
1521

16-
const options = [
22+
export enum ResolverPreset {
23+
ALL_DEFINITIONS = 'all-definitions',
24+
ANNOTATED = 'annotated',
25+
EXPORTED = 'exported',
26+
}
27+
28+
export enum HandlerPreset {
29+
ALL = 'all',
30+
CUSTOM = 'custom',
31+
NONE = 'none',
32+
}
33+
34+
export enum HandlerId {
35+
CHILD_CONTEXT_TYPE = 'childContextTypeHandler',
36+
CODE_TYPE = 'codeTypeHandler',
37+
COMPONENT_DOCBLOCK = 'componentDocblockHandler',
38+
COMPONENT_METHODS = 'componentMethodsHandler',
39+
COMPONENT_METHODS_JS_DOC = 'componentMethodsJsDocHandler',
40+
CONTEXT_TYPE = 'contextTypeHandler',
41+
DEFAULT_PROPS = 'defaultPropsHandler',
42+
DISPLAY_NAME = 'displayNameHandler',
43+
PROP_DOCBLOCK = 'propDocblockHandler',
44+
PROP_TYPE = 'propTypeHandler',
45+
PROP_TYPE_COMPOSITION = 'propTypeCompositionHandler',
46+
}
47+
48+
export const allHandlerIds = [
49+
HandlerId.PROP_TYPE,
50+
HandlerId.CONTEXT_TYPE,
51+
HandlerId.CHILD_CONTEXT_TYPE,
52+
HandlerId.PROP_TYPE_COMPOSITION,
53+
HandlerId.PROP_DOCBLOCK,
54+
HandlerId.CODE_TYPE,
55+
HandlerId.DEFAULT_PROPS,
56+
HandlerId.COMPONENT_DOCBLOCK,
57+
HandlerId.DISPLAY_NAME,
58+
HandlerId.COMPONENT_METHODS,
59+
HandlerId.COMPONENT_METHODS_JS_DOC,
60+
];
61+
62+
const languageOptions = [
1763
{ id: Language.TYPESCRIPT, name: 'TypeScript' },
1864
{ id: Language.JAVASCRIPT, name: 'JavaScript' },
1965
{ id: Language.FLOW, name: 'Flow' },
2066
];
2167

22-
export default function OptionPanel({
23-
language,
24-
onLanguageChange,
25-
}: OptionPanelProps) {
26-
const selectedOption = options.find((option) => option.id === language);
68+
const resolverOptions = [
69+
{ id: ResolverPreset.ALL_DEFINITIONS, name: 'All definitions' },
70+
{ id: ResolverPreset.EXPORTED, name: 'Exported' },
71+
{ id: ResolverPreset.ANNOTATED, name: 'Annotated' },
72+
];
73+
74+
const handlerPresetOptions = [
75+
{ id: HandlerPreset.ALL, name: 'All built-in handlers' },
76+
{ id: HandlerPreset.NONE, name: 'No handlers' },
77+
{ id: HandlerPreset.CUSTOM, name: 'Custom' },
78+
];
79+
80+
const handlerOptions = [
81+
{ id: HandlerId.PROP_TYPE, name: 'propType' },
82+
{ id: HandlerId.CONTEXT_TYPE, name: 'contextType' },
83+
{ id: HandlerId.CHILD_CONTEXT_TYPE, name: 'childContextType' },
84+
{ id: HandlerId.PROP_TYPE_COMPOSITION, name: 'propTypeComposition' },
85+
{ id: HandlerId.PROP_DOCBLOCK, name: 'propDocblock' },
86+
{ id: HandlerId.CODE_TYPE, name: 'codeType' },
87+
{ id: HandlerId.DEFAULT_PROPS, name: 'defaultProps' },
88+
{ id: HandlerId.COMPONENT_DOCBLOCK, name: 'componentDocblock' },
89+
{ id: HandlerId.DISPLAY_NAME, name: 'displayName' },
90+
{ id: HandlerId.COMPONENT_METHODS, name: 'componentMethods' },
91+
{ id: HandlerId.COMPONENT_METHODS_JS_DOC, name: 'componentMethodsJsDoc' },
92+
];
93+
94+
function getSelectedOption<T extends string>(
95+
options: { id: T; name: string }[],
96+
selectedId: T,
97+
optionType: string,
98+
) {
99+
const selectedOption = options.find((option) => option.id === selectedId);
27100

28101
if (!selectedOption) {
29-
throw new Error(`Could not find language '${language}'`);
102+
throw new Error(`Could not find ${optionType} '${selectedId}'`);
30103
}
31-
//className={cn('x:flex x:items-center x:gap-2', className)}
32104

105+
return selectedOption;
106+
}
107+
108+
function SelectOption({ name }: { name: string }) {
33109
return (
34110
<>
35-
<Select
36-
className="x:flex x:items-center x:gap-2"
37-
value={selectedOption.id}
38-
title="Change language"
39-
selectedOption={
40-
<>
41-
<CheckIcon height="1em" />
42-
{selectedOption.name}
43-
</>
44-
}
45-
options={options}
46-
onChange={(lang) => onLanguageChange(lang as Language)}
47-
/>
111+
<CheckIcon height="1em" />
112+
{name}
48113
</>
49114
);
50115
}
116+
117+
export default function OptionPanel({
118+
handlerPreset,
119+
language,
120+
resolverPreset,
121+
selectedHandlerIds,
122+
onHandlerPresetChange,
123+
onHandlerToggle,
124+
onLanguageChange,
125+
onResolverPresetChange,
126+
}: OptionPanelProps) {
127+
const selectedLanguage = getSelectedOption(
128+
languageOptions,
129+
language,
130+
'language',
131+
);
132+
const selectedResolver = getSelectedOption(
133+
resolverOptions,
134+
resolverPreset,
135+
'resolver preset',
136+
);
137+
const selectedHandlerPreset = getSelectedOption(
138+
handlerPresetOptions,
139+
handlerPreset,
140+
'handler preset',
141+
);
142+
143+
return (
144+
<div className="flex flex-col gap-5 text-sm">
145+
<div className="flex flex-col gap-2">
146+
<span className="text-xs font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">
147+
Language
148+
</span>
149+
<Select
150+
className="x:flex x:items-center x:gap-2"
151+
value={selectedLanguage.id}
152+
title="Change language"
153+
selectedOption={<SelectOption name={selectedLanguage.name} />}
154+
options={languageOptions}
155+
onChange={(lang) => onLanguageChange(lang as Language)}
156+
/>
157+
</div>
158+
159+
<div className="flex flex-col gap-2">
160+
<span className="text-xs font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">
161+
Resolver
162+
</span>
163+
<Select
164+
className="x:flex x:items-center x:gap-2"
165+
value={selectedResolver.id}
166+
title="Change resolver"
167+
selectedOption={<SelectOption name={selectedResolver.name} />}
168+
options={resolverOptions}
169+
onChange={(preset) =>
170+
onResolverPresetChange(preset as ResolverPreset)
171+
}
172+
/>
173+
</div>
174+
175+
<div className="flex flex-col gap-2">
176+
<span className="text-xs font-semibold tracking-wide text-gray-500 uppercase dark:text-gray-400">
177+
Handlers
178+
</span>
179+
<Select
180+
className="x:flex x:items-center x:gap-2"
181+
value={selectedHandlerPreset.id}
182+
title="Change handlers"
183+
selectedOption={<SelectOption name={selectedHandlerPreset.name} />}
184+
options={handlerPresetOptions}
185+
onChange={(preset) => onHandlerPresetChange(preset as HandlerPreset)}
186+
/>
187+
188+
<div className="mt-1 ml-4 flex flex-col gap-2">
189+
{handlerOptions.map((handler) => (
190+
<label
191+
className="flex min-h-6 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs leading-5 transition-colors hover:bg-gray-100 dark:hover:bg-neutral-800"
192+
key={handler.id}
193+
>
194+
<input
195+
checked={selectedHandlerIds.includes(handler.id)}
196+
className="sr-only"
197+
type="checkbox"
198+
onChange={() => onHandlerToggle(handler.id)}
199+
/>
200+
<span className="flex h-4 w-4 flex-none items-center justify-center">
201+
<CheckIcon
202+
className={
203+
selectedHandlerIds.includes(handler.id)
204+
? 'text-gray-600 dark:text-gray-300'
205+
: 'text-transparent'
206+
}
207+
height="1em"
208+
/>
209+
</span>
210+
<span>{handler.name}</span>
211+
</label>
212+
))}
213+
</div>
214+
</div>
215+
</div>
216+
);
217+
}

0 commit comments

Comments
 (0)