@petrarca/sonnet-playground 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +63 -101
  2. package/dist/PlayAuth-SOEYPOOL.js +8 -0
  3. package/dist/{PlayCoreComponents-AG5D4SBS.js → PlayCoreComponents-YTEAS3GL.js} +2 -2
  4. package/dist/{PlayFormWidgets-IWJJQ5XL.js → PlayFormWidgets-6JYFRTAL.js} +2 -2
  5. package/dist/PlayForms-L532W3JL.js +7 -0
  6. package/dist/PlayGraph-M4KQSFI7.js +7 -0
  7. package/dist/PlaySchemaDesigner-S4DBB53G.js +7 -0
  8. package/dist/PlaySchemaDesigner-S4DBB53G.js.map +1 -0
  9. package/dist/{chunk-PBT6HTKY.js → chunk-2XMWOZ5O.js} +130 -6
  10. package/dist/chunk-2XMWOZ5O.js.map +1 -0
  11. package/dist/{chunk-Q6NLY2BZ.js → chunk-6WI3N7JI.js} +309 -1
  12. package/dist/chunk-6WI3N7JI.js.map +1 -0
  13. package/dist/{chunk-C2P3UQMZ.js → chunk-E5X7GVLU.js} +2 -2
  14. package/dist/chunk-E5X7GVLU.js.map +1 -0
  15. package/dist/{chunk-6DZ3TSV4.js → chunk-I2FLG6ZD.js} +102 -4
  16. package/dist/chunk-I2FLG6ZD.js.map +1 -0
  17. package/dist/chunk-RYCRENYO.js +401 -0
  18. package/dist/chunk-RYCRENYO.js.map +1 -0
  19. package/dist/{chunk-DZB6WFHA.js → chunk-UB7462QG.js} +106 -1
  20. package/dist/chunk-UB7462QG.js.map +1 -0
  21. package/dist/index.d.ts +59 -17
  22. package/dist/index.js +251 -53
  23. package/dist/index.js.map +1 -1
  24. package/dist/pages/index.d.ts +3 -1
  25. package/dist/pages/index.js +9 -5
  26. package/package.json +7 -7
  27. package/dist/PlayForms-FOF3XE6G.js +0 -7
  28. package/dist/PlayGraph-M7UE5MZC.js +0 -7
  29. package/dist/PlaySchemaDesigner-B2RVRRCH.js +0 -7
  30. package/dist/chunk-6DZ3TSV4.js.map +0 -1
  31. package/dist/chunk-C2P3UQMZ.js.map +0 -1
  32. package/dist/chunk-DZB6WFHA.js.map +0 -1
  33. package/dist/chunk-PBT6HTKY.js.map +0 -1
  34. package/dist/chunk-Q6NLY2BZ.js.map +0 -1
  35. /package/dist/{PlayCoreComponents-AG5D4SBS.js.map → PlayAuth-SOEYPOOL.js.map} +0 -0
  36. /package/dist/{PlayFormWidgets-IWJJQ5XL.js.map → PlayCoreComponents-YTEAS3GL.js.map} +0 -0
  37. /package/dist/{PlayForms-FOF3XE6G.js.map → PlayFormWidgets-6JYFRTAL.js.map} +0 -0
  38. /package/dist/{PlayGraph-M7UE5MZC.js.map → PlayForms-L532W3JL.js.map} +0 -0
  39. /package/dist/{PlaySchemaDesigner-B2RVRRCH.js.map → PlayGraph-M4KQSFI7.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pages/PlayFormWidgets.tsx"],"sourcesContent":["/**\n * Playground page for testing form widgets\n * Accessible at /playground/form-widgets\n */\n\nimport {\n type Dispatch,\n type SetStateAction,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { SimpleStack, Card } from \"@petrarca/sonnet-ui\";\nimport { ExampleBlock } from \"../PlaygroundSection\";\nimport {\n TextInputWidget,\n TextareaWidget,\n NumberWidget,\n CheckboxWidget,\n SelectWidget,\n QuantityWidget,\n DateWidget,\n TimeWidget,\n DateTimeWidget,\n DisplayWidget,\n DEFAULT_WIDGETS,\n type QuantityValue,\n} from \"@petrarca/sonnet-forms\";\nimport type { JsonSchema } from \"@petrarca/sonnet-core/schema\";\n\nconst dummySchema: JsonSchema = {\n title: \"Form Widgets Demo\",\n type: \"object\",\n properties: {},\n \"x-entity\": {\n type: \"entity\",\n label: \"Demo\",\n relations: [],\n },\n};\n\nfunction makeQuantityHandler(\n set: Dispatch<SetStateAction<QuantityValue>>,\n): (v: unknown) => void {\n return (v: unknown) => {\n if (v != null && typeof v === \"object\" && !Array.isArray(v)) {\n set(v as QuantityValue);\n }\n };\n}\n\nexport default function PlayFormWidgets() {\n // State for each widget\n const [textValue, setTextValue] = useState<string>(\"\");\n const [textareaValue, setTextareaValue] = useState<string>(\"\");\n const [numberValue, setNumberValue] = useState<number | undefined>(undefined);\n const [checkboxValue, setCheckboxValue] = useState<boolean>(false);\n const [selectValue, setSelectValue] = useState<string>(\"\");\n const [multiSelectValue, setMultiSelectValue] = useState<string[]>([]);\n const [multiSelectColorValue, setMultiSelectColorValue] = useState<string[]>(\n [],\n );\n const [tempValue, setTempValue] = useState<QuantityValue>({\n value: 37.0,\n unit: \"degC\",\n });\n const [weightValue, setWeightValue] = useState<QuantityValue>({\n value: undefined,\n unit: \"kg\",\n });\n const [bpValue, setBpValue] = useState<QuantityValue>({\n value: 72,\n unit: \"bpm\",\n });\n const [priceValue, setPriceValue] = useState<QuantityValue>({\n value: 49.99,\n unit: \"EUR\",\n });\n const [dateValue, setDateValue] = useState<string>(\"2026-06-15\");\n const [birthYear, setBirthYear] = useState<string>(\"1980\");\n const [timeValue, setTimeValue] = useState<string>(\"09:30\");\n const [dateTimeValue, setDateTimeValue] =\n useState<string>(\"2026-06-15T09:30\");\n\n // Narrowing adapters: WidgetProps.onChange is (value: unknown) => void.\n // All quantity adapters have stable identity (empty deps) -- the fallback\n // branch is dropped so the state setter is not captured in the closure.\n const onTextChange = useCallback(\n (v: unknown) => setTextValue(typeof v === \"string\" ? v : \"\"),\n [],\n );\n const onTextareaChange = useCallback(\n (v: unknown) => setTextareaValue(typeof v === \"string\" ? v : \"\"),\n [],\n );\n const onNumberChange = useCallback(\n (v: unknown) => setNumberValue(typeof v === \"number\" ? v : undefined),\n [],\n );\n const onCheckboxChange = useCallback(\n (v: unknown) => setCheckboxValue(typeof v === \"boolean\" ? v : false),\n [],\n );\n const onSelectChange = useCallback(\n (v: unknown) => setSelectValue(typeof v === \"string\" ? v : \"\"),\n [],\n );\n const onMultiSelectChange = useCallback(\n (v: unknown) =>\n setMultiSelectValue(Array.isArray(v) ? (v as string[]) : []),\n [],\n );\n const onMultiSelectColorChange = useCallback(\n (v: unknown) =>\n setMultiSelectColorValue(Array.isArray(v) ? (v as string[]) : []),\n [],\n );\n // Quantity adapters: QuantityWidget passes unknown, guard narrows to QuantityValue.\n const onTempChange = useMemo(() => makeQuantityHandler(setTempValue), []);\n const onWeightChange = useMemo(() => makeQuantityHandler(setWeightValue), []);\n const onBpChange = useMemo(() => makeQuantityHandler(setBpValue), []);\n const onPriceChange = useMemo(() => makeQuantityHandler(setPriceValue), []);\n const onStringChange = useCallback(\n (set: Dispatch<SetStateAction<string>>) => (v: unknown) =>\n set(typeof v === \"string\" ? v : \"\"),\n [],\n );\n\n return (\n <div className=\"w-full max-w-4xl space-y-6\">\n <div>\n <h1>Basic Form Widgets Playground</h1>\n <p className=\"text-sm text-muted-foreground mb-3\">\n Interactive demonstration of all basic form widgets\n </p>\n </div>\n\n <div>\n <SimpleStack gap=\"md\" style={{ maxWidth: \"900px\" }}>\n {/* TextInputWidget */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>TextInputWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Single-line text input with support for various HTML input types\n (text, email, password, url, etc.)\n </p>\n\n <TextInputWidget\n id=\"text-input-demo\"\n name=\"textInput\"\n value={textValue}\n onChange={onTextChange}\n label=\"Text Input\"\n description=\"Enter some text\"\n placeholder=\"Type here...\"\n propertySchema={{ type: \"string\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n />\n\n <TextInputWidget\n id=\"text-input-email\"\n name=\"emailInput\"\n value={textValue}\n onChange={onTextChange}\n label=\"Email Input\"\n description=\"Input type: email\"\n placeholder=\"user@example.com\"\n propertySchema={{ type: \"string\", format: \"email\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{ inputType: \"email\" }}\n />\n\n <pre className=\"text-[11px] bg-muted p-2 rounded overflow-x-auto\">\n <code>{JSON.stringify({ value: textValue }, null, 2)}</code>\n </pre>\n </SimpleStack>\n </Card>\n\n {/* TextareaWidget */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>TextareaWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Multi-line text input with configurable rows and autosize\n support\n </p>\n\n <TextareaWidget\n id=\"textarea-demo\"\n name=\"textarea\"\n value={textareaValue}\n onChange={onTextareaChange}\n label=\"Textarea\"\n description=\"Enter multiple lines\"\n placeholder=\"Type here...\"\n propertySchema={{ type: \"string\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{ rows: 4 }}\n />\n\n <pre className=\"text-[11px] bg-muted p-2 rounded overflow-x-auto\">\n <code>{JSON.stringify({ value: textareaValue }, null, 2)}</code>\n </pre>\n </SimpleStack>\n </Card>\n\n {/* NumberWidget */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>NumberWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Number input with support for min, max, and step constraints\n </p>\n\n <NumberWidget\n id=\"number-demo\"\n name=\"number\"\n value={numberValue}\n onChange={onNumberChange}\n label=\"Number Input\"\n description=\"Enter a number (0-100, step: 5)\"\n placeholder=\"0\"\n propertySchema={{ type: \"number\", minimum: 0, maximum: 100 }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{ step: 5 }}\n />\n\n <pre className=\"text-[11px] bg-muted p-2 rounded overflow-x-auto\">\n <code>{JSON.stringify({ value: numberValue }, null, 2)}</code>\n </pre>\n </SimpleStack>\n </Card>\n\n {/* CheckboxWidget */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>CheckboxWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Boolean checkbox for true/false values\n </p>\n\n <CheckboxWidget\n id=\"checkbox-demo\"\n name=\"checkbox\"\n value={checkboxValue}\n onChange={onCheckboxChange}\n label=\"Enable Feature\"\n description=\"Check to enable\"\n propertySchema={{ type: \"boolean\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n />\n\n <pre className=\"text-[11px] bg-muted p-2 rounded overflow-x-auto\">\n <code>{JSON.stringify({ value: checkboxValue }, null, 2)}</code>\n </pre>\n </SimpleStack>\n </Card>\n\n {/* SelectWidget - All Variations */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>SelectWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Dropdown select for enum values with single-select,\n multi-select, and custom badge colors\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Single select\">\n <SelectWidget\n id=\"select-demo\"\n name=\"select\"\n value={selectValue}\n onChange={onSelectChange}\n label=\"Select Status\"\n description=\"Choose a status\"\n placeholder=\"Select one...\"\n propertySchema={{\n type: \"string\",\n enum: [\"active\", \"inactive\", \"pending\", \"archived\"],\n }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{\n enumNames: {\n active: \"Active\",\n inactive: \"Inactive\",\n pending: \"Pending\",\n archived: \"Archived\",\n },\n searchable: true,\n clearable: true,\n }}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Multi select\">\n <SelectWidget\n id=\"multiselect-demo\"\n name=\"multiselect\"\n value={multiSelectValue}\n onChange={onMultiSelectChange}\n label=\"Select Tags\"\n description=\"Choose multiple tags\"\n placeholder=\"Select tags...\"\n propertySchema={{\n type: \"array\",\n items: { type: \"string\" },\n enum: [\n \"frontend\",\n \"backend\",\n \"database\",\n \"devops\",\n \"testing\",\n \"security\",\n ],\n }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{ searchable: true, clearable: true }}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Custom badge color\">\n <SelectWidget\n id=\"multiselect-color-demo\"\n name=\"multiselectColor\"\n value={multiSelectColorValue}\n onChange={onMultiSelectColorChange}\n label=\"Select Categories\"\n description=\"Custom grape-colored badges\"\n placeholder=\"Select categories...\"\n propertySchema={{\n type: \"array\",\n items: { type: \"string\" },\n enum: [\n \"feature\",\n \"bugfix\",\n \"enhancement\",\n \"documentation\",\n \"refactor\",\n ],\n }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{\n searchable: true,\n clearable: true,\n badgeColor: \"grape\",\n enumNames: {\n feature: \"Feature\",\n bugfix: \"Bug Fix\",\n enhancement: \"Enhancement\",\n documentation: \"Documentation\",\n refactor: \"Refactor\",\n },\n }}\n />\n </ExampleBlock>\n </div>\n </SimpleStack>\n </Card>\n\n {/* DisplayWidget */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>DisplayWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Read-only text block (type: null / x-ui-widget: display).\n Renders title + description as static text, collects no value.\n For instructions and notes placed between fields.\n </p>\n\n <div className=\"rounded-md border border-dashed p-3\">\n <DisplayWidget\n id=\"display-demo\"\n name=\"displayNote\"\n value={null}\n onChange={() => {}}\n label=\"Section 3: Medical history\"\n description=\"Answer the following to the best of your knowledge. Leave blank if unsure.\"\n propertySchema={{ type: \"null\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n />\n </div>\n </SimpleStack>\n </Card>\n\n {/* Date / Time / DateTime widgets */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>DateWidget / TimeWidget / DateTimeWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Date, time, and datetime fields. Auto-resolve from schema format\n (date / time / date-time). Values are ISO strings; display and\n parsing follow the playground locale (gear icon).\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Date (format: date)\">\n <DateWidget\n id=\"date-widget-demo\"\n name=\"date\"\n value={dateValue}\n onChange={onStringChange(setDateValue)}\n label=\"Appointment date\"\n description=\"Resolved from format: date\"\n propertySchema={{ type: \"string\", format: \"date\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Date, year precision\">\n <DateWidget\n id=\"date-widget-year\"\n name=\"birthYear\"\n value={birthYear}\n onChange={onStringChange(setBirthYear)}\n label=\"Birth year\"\n description=\"x-ui-options.precision: year\"\n propertySchema={{ type: \"string\", format: \"date\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{ precision: \"year\" }}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Time (format: time)\">\n <TimeWidget\n id=\"time-widget-demo\"\n name=\"time\"\n value={timeValue}\n onChange={onStringChange(setTimeValue)}\n label=\"Start time\"\n description=\"Zone-free time of day\"\n propertySchema={{ type: \"string\", format: \"time\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Date & time (format: date-time)\">\n <DateTimeWidget\n id=\"datetime-widget-demo\"\n name=\"dateTime\"\n value={dateTimeValue}\n onChange={onStringChange(setDateTimeValue)}\n label=\"Scheduled at\"\n description=\"Plain wall-clock, timezone hint\"\n propertySchema={{ type: \"string\", format: \"date-time\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{ timeZone: \"Europe/Berlin\" }}\n />\n </ExampleBlock>\n </div>\n\n <pre className=\"text-[11px] bg-muted p-2 rounded overflow-x-auto\">\n <code>\n {JSON.stringify(\n {\n date: dateValue,\n birthYear,\n time: timeValue,\n dateTime: dateTimeValue,\n },\n null,\n 2,\n )}\n </code>\n </pre>\n </SimpleStack>\n </Card>\n\n {/* QuantityWidget */}\n <Card className=\"border shadow-sm p-4\">\n <SimpleStack gap=\"sm\">\n <h2>QuantityWidget</h2>\n <p className=\"text-sm text-muted-foreground\">\n Compound numeric value + unit selector. Multi-unit shows a\n dropdown, single-unit shows static text, prefix mode places the\n unit before the value.\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n <ExampleBlock label=\"Multi-unit suffix (Temperature)\">\n <QuantityWidget\n id=\"quantity-temp\"\n name=\"temperature\"\n value={tempValue}\n onChange={onTempChange}\n label=\"Temperature\"\n description=\"Body temperature with per-unit validation\"\n placeholder=\"0.0\"\n propertySchema={{ type: \"object\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{\n precision: 1,\n units: [\n { value: \"degC\", label: \"C\", min: 35, max: 42 },\n { value: \"degF\", label: \"F\", min: 95, max: 108 },\n ],\n }}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Single-unit suffix (Weight)\">\n <QuantityWidget\n id=\"quantity-weight\"\n name=\"weight\"\n value={weightValue}\n onChange={onWeightChange}\n label=\"Weight\"\n description=\"Single unit, global min/max from schema\"\n placeholder=\"0\"\n propertySchema={{\n type: \"object\",\n minimum: 0,\n maximum: 500,\n }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{\n precision: 1,\n units: [{ value: \"kg\", label: \"kg\" }],\n }}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Integer mode (Heart Rate)\">\n <QuantityWidget\n id=\"quantity-hr\"\n name=\"heartRate\"\n value={bpValue}\n onChange={onBpChange}\n label=\"Heart Rate\"\n description=\"Integer with per-unit validation (30-250 bpm)\"\n placeholder=\"0\"\n propertySchema={{ type: \"object\" }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{\n precision: 0,\n units: [\n { value: \"bpm\", label: \"bpm\", min: 30, max: 250 },\n ],\n }}\n />\n </ExampleBlock>\n <ExampleBlock label=\"Multi-unit prefix (Currency)\">\n <QuantityWidget\n id=\"quantity-price\"\n name=\"price\"\n value={priceValue}\n onChange={onPriceChange}\n label=\"Price\"\n description=\"Currency symbol as prefix, multi-unit selector\"\n placeholder=\"0.00\"\n propertySchema={{ type: \"object\", minimum: 0 }}\n schema={dummySchema}\n registry={DEFAULT_WIDGETS}\n options={{\n precision: 2,\n unitPosition: \"prefix\",\n units: [\n { value: \"EUR\", label: \"EUR\" },\n { value: \"USD\", label: \"$\" },\n { value: \"GBP\", label: \"GBP\" },\n ],\n }}\n />\n </ExampleBlock>\n </div>\n </SimpleStack>\n </Card>\n </SimpleStack>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -55,17 +55,21 @@ interface PlaygroundModuleOptions {
55
55
  grouped?: boolean;
56
56
  }
57
57
 
58
- /**
59
- * PlaygroundRegistry -- mutable collection of playground entries.
60
- *
61
- * The library ships a default instance pre-populated with the built-in
62
- * sonnet component demos. Consumers register additional entries for
63
- * domain-specific playgrounds before passing the registry to
64
- * createPlaygroundModule().
65
- */
66
-
67
58
  declare class PlaygroundRegistry {
68
59
  private entries;
60
+ /**
61
+ * Report registrations that cannot work, rather than silently misbehaving.
62
+ *
63
+ * Entries are keyed by `id`, so two entries may legally share a `path` --
64
+ * and then both produce a route on the same URL and one is unreachable.
65
+ * Groups are bucketed by their exact label, so two labels differing only by
66
+ * case become two separate groups.
67
+ *
68
+ * Neither is corrected here: dropping an entry, or merging groups the caller
69
+ * spelled differently, would be its own surprise. The registration stands and
70
+ * the problem is made diagnosable.
71
+ */
72
+ private warnOnConflicts;
69
73
  /** Register a playground entry. Overwrites any existing entry with the same id. */
70
74
  register(entry: PlaygroundEntry): void;
71
75
  /** Register multiple entries at once. */
@@ -93,13 +97,6 @@ declare class PlaygroundRegistry {
93
97
  get size(): number;
94
98
  }
95
99
 
96
- /**
97
- * Create a ShellModule for the playground.
98
- *
99
- * Returns a complete module definition ready to pass to
100
- * createModuleRegistry(). Routes, navigation, and the overview page
101
- * are all generated from the registry.
102
- */
103
100
  declare function createPlaygroundModule(registry: PlaygroundRegistry, options?: PlaygroundModuleOptions): ShellModule;
104
101
 
105
102
  /**
@@ -137,9 +134,54 @@ interface PlaygroundSectionProps {
137
134
  children: React$1.ReactNode;
138
135
  variant?: "default" | "card";
139
136
  }
137
+ interface ExampleBlockProps {
138
+ label: string;
139
+ children: React$1.ReactNode;
140
+ }
141
+ /** Labeled divider wrapper for individual component examples within a section. */
142
+ declare function ExampleBlock({ label, children, }: ExampleBlockProps): React$1.ReactElement;
140
143
  /** Titled section wrapper used across playground pages. */
141
144
  declare function PlaygroundSection({ title, description, children, variant, }: PlaygroundSectionProps): React$1.ReactElement;
142
145
 
146
+ /**
147
+ * Playground-scoped settings (locale, ...).
148
+ *
149
+ * A self-contained provider that wraps all playground routes. It owns a small
150
+ * settings object, persists it to a namespaced localStorage key, and renders a
151
+ * SonnetConfigProvider so the settings flow to every playground page.
152
+ *
153
+ * Scope and containment: the provider is nested under any host-app provider and
154
+ * merges onto it, so a playground override shadows the app/browser value only
155
+ * within the playground subtree -- it never mutates the host app's global
156
+ * config. The default is "inherit" (empty locale), so out of the box the
157
+ * playground changes nothing.
158
+ */
159
+
160
+ interface PlaygroundSettings {
161
+ /** BCP-47 locale override, or "" to inherit the app/browser locale. */
162
+ locale: string;
163
+ }
164
+ interface PlaygroundSettingsContextValue {
165
+ settings: PlaygroundSettings;
166
+ setSettings: (next: Partial<PlaygroundSettings>) => void;
167
+ }
168
+ interface PlaygroundSettingsProviderProps {
169
+ children: React$1.ReactNode;
170
+ }
171
+ declare function PlaygroundSettingsProvider({ children, }: PlaygroundSettingsProviderProps): React$1.ReactElement;
172
+ /** Access playground settings. Returns defaults when no provider is present. */
173
+ declare function usePlaygroundSettings(): PlaygroundSettingsContextValue;
174
+
175
+ /**
176
+ * PlaygroundSettingsPanel -- gear button that opens a right-side settings sheet.
177
+ *
178
+ * Hosts playground-wide settings (currently locale). Edits flow through
179
+ * usePlaygroundSettings, which drives the SonnetConfigProvider wrapping all
180
+ * playground routes.
181
+ */
182
+
183
+ declare function PlaygroundSettingsPanel(): React$1.ReactElement;
184
+
143
185
  declare const builtinEntries: PlaygroundEntry[];
144
186
 
145
187
  /**
@@ -168,4 +210,4 @@ declare const builtinEntries: PlaygroundEntry[];
168
210
  */
169
211
  declare function createPlaygroundRegistry(): PlaygroundRegistry;
170
212
 
171
- export { type PlaygroundColor, type PlaygroundEntry, type PlaygroundModuleOptions, PlaygroundOverview, PlaygroundRegistry, PlaygroundSection, builtinEntries, createPlaygroundModule, createPlaygroundRegistry };
213
+ export { ExampleBlock, type PlaygroundColor, type PlaygroundEntry, type PlaygroundModuleOptions, PlaygroundOverview, PlaygroundRegistry, PlaygroundSection, type PlaygroundSettings, PlaygroundSettingsPanel, PlaygroundSettingsProvider, builtinEntries, createPlaygroundModule, createPlaygroundRegistry, usePlaygroundSettings };
package/dist/index.js CHANGED
@@ -1,18 +1,50 @@
1
1
  import {
2
+ ExampleBlock,
2
3
  PlaygroundSection
3
4
  } from "./chunk-C2EZ2ECG.js";
4
5
 
5
6
  // src/PlaygroundRegistry.ts
7
+ import { warnLog } from "@petrarca/sonnet-core";
6
8
  var PlaygroundRegistry = class _PlaygroundRegistry {
7
9
  entries = /* @__PURE__ */ new Map();
10
+ /**
11
+ * Report registrations that cannot work, rather than silently misbehaving.
12
+ *
13
+ * Entries are keyed by `id`, so two entries may legally share a `path` --
14
+ * and then both produce a route on the same URL and one is unreachable.
15
+ * Groups are bucketed by their exact label, so two labels differing only by
16
+ * case become two separate groups.
17
+ *
18
+ * Neither is corrected here: dropping an entry, or merging groups the caller
19
+ * spelled differently, would be its own surprise. The registration stands and
20
+ * the problem is made diagnosable.
21
+ */
22
+ warnOnConflicts(entry) {
23
+ for (const existing of this.entries.values()) {
24
+ if (existing.id === entry.id) continue;
25
+ if (existing.path === entry.path) {
26
+ warnLog(
27
+ `[PlaygroundRegistry] entries "${existing.id}" and "${entry.id}" share the path "${entry.path}". Both will route to the same URL and one will be unreachable.`
28
+ );
29
+ }
30
+ const group = entry.group ?? _PlaygroundRegistry.DEFAULT_GROUP;
31
+ const existingGroup = existing.group ?? _PlaygroundRegistry.DEFAULT_GROUP;
32
+ if (group !== existingGroup && group.toLowerCase() === existingGroup.toLowerCase()) {
33
+ warnLog(
34
+ `[PlaygroundRegistry] group "${group}" differs from "${existingGroup}" only by case; they will render as two separate groups.`
35
+ );
36
+ }
37
+ }
38
+ }
8
39
  /** Register a playground entry. Overwrites any existing entry with the same id. */
9
40
  register(entry) {
41
+ this.warnOnConflicts(entry);
10
42
  this.entries.set(entry.id, entry);
11
43
  }
12
44
  /** Register multiple entries at once. */
13
45
  registerAll(entries) {
14
46
  for (const entry of entries) {
15
- this.entries.set(entry.id, entry);
47
+ this.register(entry);
16
48
  }
17
49
  }
18
50
  /** Remove an entry by id. Returns true if it existed. */
@@ -87,7 +119,8 @@ import {
87
119
  Table2,
88
120
  Network,
89
121
  SquareTerminal,
90
- PencilRuler
122
+ PencilRuler,
123
+ ShieldCheck
91
124
  } from "lucide-react";
92
125
  var builtinEntries = [
93
126
  {
@@ -119,7 +152,7 @@ var builtinEntries = [
119
152
  icon: Grid,
120
153
  color: "indigo",
121
154
  path: "core-components",
122
- component: lazy(() => import("./PlayCoreComponents-AG5D4SBS.js")),
155
+ component: lazy(() => import("./PlayCoreComponents-YTEAS3GL.js")),
123
156
  group: "Components",
124
157
  order: 0
125
158
  },
@@ -163,7 +196,7 @@ var builtinEntries = [
163
196
  icon: Edit,
164
197
  color: "purple",
165
198
  path: "forms",
166
- component: lazy(() => import("./PlayForms-FOF3XE6G.js")),
199
+ component: lazy(() => import("./PlayForms-L532W3JL.js")),
167
200
  group: "Forms",
168
201
  order: 1
169
202
  },
@@ -174,7 +207,7 @@ var builtinEntries = [
174
207
  icon: Package,
175
208
  color: "indigo",
176
209
  path: "form-widgets",
177
- component: lazy(() => import("./PlayFormWidgets-IWJJQ5XL.js")),
210
+ component: lazy(() => import("./PlayFormWidgets-6JYFRTAL.js")),
178
211
  group: "Forms",
179
212
  order: 2
180
213
  },
@@ -185,7 +218,7 @@ var builtinEntries = [
185
218
  icon: PencilRuler,
186
219
  color: "teal",
187
220
  path: "schema-designer",
188
- component: lazy(() => import("./PlaySchemaDesigner-B2RVRRCH.js")),
221
+ component: lazy(() => import("./PlaySchemaDesigner-S4DBB53G.js")),
189
222
  group: "Schemas",
190
223
  order: 0
191
224
  },
@@ -207,7 +240,7 @@ var builtinEntries = [
207
240
  icon: Network,
208
241
  color: "cyan",
209
242
  path: "graph",
210
- component: lazy(() => import("./PlayGraph-M7UE5MZC.js")),
243
+ component: lazy(() => import("./PlayGraph-M4KQSFI7.js")),
211
244
  group: "Graph",
212
245
  order: 0
213
246
  },
@@ -221,19 +254,163 @@ var builtinEntries = [
221
254
  component: lazy(() => import("./PlayShellApi-5O6VYR2X.js")),
222
255
  group: "Shell",
223
256
  order: 0
257
+ },
258
+ {
259
+ id: "sonnet.auth",
260
+ title: "Auth Screens",
261
+ description: "The pre-application login and organization selection screens: identifier-first and legacy flows, provider combinations, error and loading states, and every org-selection outcome.",
262
+ icon: ShieldCheck,
263
+ color: "teal",
264
+ path: "auth",
265
+ component: lazy(() => import("./PlayAuth-SOEYPOOL.js")),
266
+ group: "Shell",
267
+ order: 1
224
268
  }
225
269
  ];
226
270
 
227
271
  // src/createPlaygroundModule.tsx
228
272
  import { Suspense } from "react";
273
+ import { Outlet } from "react-router-dom";
229
274
  import { FlaskConical } from "lucide-react";
230
275
 
231
276
  // src/PlaygroundOverview.tsx
232
- import { useState } from "react";
277
+ import { useState as useState3 } from "react";
233
278
  import { useNavigate } from "react-router-dom";
234
279
  import { LayoutGrid, List } from "lucide-react";
235
280
  import { Card, Button, SimpleTooltip } from "@petrarca/sonnet-ui";
236
- import { jsx, jsxs } from "react/jsx-runtime";
281
+
282
+ // src/PlaygroundSettingsPanel.tsx
283
+ import { useState as useState2 } from "react";
284
+ import { Settings } from "lucide-react";
285
+ import {
286
+ IconButton,
287
+ Label,
288
+ Sheet,
289
+ SheetContent,
290
+ SheetHeader,
291
+ SheetTitle,
292
+ SheetDescription,
293
+ SheetBody,
294
+ Select,
295
+ SelectTrigger,
296
+ SelectValue,
297
+ SelectContent,
298
+ SelectItem
299
+ } from "@petrarca/sonnet-ui";
300
+
301
+ // src/PlaygroundSettings.tsx
302
+ import {
303
+ createContext,
304
+ useCallback,
305
+ useContext,
306
+ useMemo,
307
+ useState
308
+ } from "react";
309
+ import { SonnetConfigProvider } from "@petrarca/sonnet-core/config";
310
+ import { jsx } from "react/jsx-runtime";
311
+ var STORAGE_KEY = "sonnet.playground.settings";
312
+ var DEFAULT_SETTINGS = { locale: "" };
313
+ var PlaygroundSettingsContext = createContext(null);
314
+ var storage = {
315
+ get(key) {
316
+ try {
317
+ return typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
318
+ } catch {
319
+ return null;
320
+ }
321
+ },
322
+ set(key, value) {
323
+ try {
324
+ if (typeof localStorage !== "undefined") localStorage.setItem(key, value);
325
+ } catch {
326
+ }
327
+ }
328
+ };
329
+ function loadSettings() {
330
+ const raw = storage.get(STORAGE_KEY);
331
+ if (!raw) return DEFAULT_SETTINGS;
332
+ try {
333
+ return { ...DEFAULT_SETTINGS, ...JSON.parse(raw) };
334
+ } catch {
335
+ return DEFAULT_SETTINGS;
336
+ }
337
+ }
338
+ function persistSettings(settings) {
339
+ storage.set(STORAGE_KEY, JSON.stringify(settings));
340
+ }
341
+ function PlaygroundSettingsProvider({
342
+ children
343
+ }) {
344
+ const [settings, setSettingsState] = useState(loadSettings);
345
+ const setSettings = useCallback(
346
+ (next) => setSettingsState((prev) => {
347
+ const merged = { ...prev, ...next };
348
+ persistSettings(merged);
349
+ return merged;
350
+ }),
351
+ []
352
+ );
353
+ const contextValue = useMemo(
354
+ () => ({ settings, setSettings }),
355
+ [settings, setSettings]
356
+ );
357
+ const config = useMemo(
358
+ () => ({ globals: { locale: settings.locale || void 0 } }),
359
+ [settings.locale]
360
+ );
361
+ return /* @__PURE__ */ jsx(PlaygroundSettingsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(SonnetConfigProvider, { value: config, children }) });
362
+ }
363
+ function usePlaygroundSettings() {
364
+ return useContext(PlaygroundSettingsContext) ?? {
365
+ settings: DEFAULT_SETTINGS,
366
+ setSettings: () => {
367
+ }
368
+ };
369
+ }
370
+
371
+ // src/PlaygroundSettingsPanel.tsx
372
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
373
+ var INHERIT = "__inherit__";
374
+ var LOCALE_OPTIONS = [
375
+ { code: INHERIT, label: "Inherit (app / browser)" },
376
+ { code: "en-US", label: "English (US) - MM/DD, Sun" },
377
+ { code: "en-GB", label: "English (UK) - DD/MM, Mon" },
378
+ { code: "de-DE", label: "German - DD.MM, Mon" },
379
+ { code: "fr-FR", label: "French - DD/MM, Mon" },
380
+ { code: "sv-SE", label: "Swedish - YYYY-MM-DD, Mon" },
381
+ { code: "ja-JP", label: "Japanese - YYYY/MM/DD, Sun" }
382
+ ];
383
+ function PlaygroundSettingsPanel() {
384
+ const [open, setOpen] = useState2(false);
385
+ const { settings, setSettings } = usePlaygroundSettings();
386
+ return /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
387
+ /* @__PURE__ */ jsx2(IconButton, { label: "Playground settings", onClick: () => setOpen(true), children: /* @__PURE__ */ jsx2(Settings, {}) }),
388
+ /* @__PURE__ */ jsxs(SheetContent, { side: "right", children: [
389
+ /* @__PURE__ */ jsxs(SheetHeader, { children: [
390
+ /* @__PURE__ */ jsx2(SheetTitle, { children: "Playground settings" }),
391
+ /* @__PURE__ */ jsx2(SheetDescription, { children: "Scoped to the playground. Values exchanged with components stay locale-independent (ISO); only display and input parsing change." })
392
+ ] }),
393
+ /* @__PURE__ */ jsx2(SheetBody, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
394
+ /* @__PURE__ */ jsx2(Label, { htmlFor: "playground-locale", children: "Locale" }),
395
+ /* @__PURE__ */ jsxs(
396
+ Select,
397
+ {
398
+ value: settings.locale || INHERIT,
399
+ onValueChange: (value) => setSettings({ locale: value === INHERIT ? "" : value }),
400
+ children: [
401
+ /* @__PURE__ */ jsx2(SelectTrigger, { id: "playground-locale", children: /* @__PURE__ */ jsx2(SelectValue, {}) }),
402
+ /* @__PURE__ */ jsx2(SelectContent, { children: LOCALE_OPTIONS.map((opt) => /* @__PURE__ */ jsx2(SelectItem, { value: opt.code, children: opt.label }, opt.code)) })
403
+ ]
404
+ }
405
+ ),
406
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-tertiary-foreground", children: "Drives locale-sensitive components (e.g. Date Input) across every playground page." })
407
+ ] }) })
408
+ ] })
409
+ ] });
410
+ }
411
+
412
+ // src/PlaygroundOverview.tsx
413
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
237
414
  var COLOR_CLASSES = {
238
415
  blue: "bg-blue-100 text-blue-600",
239
416
  violet: "bg-violet-100 text-violet-600",
@@ -248,21 +425,21 @@ var COLOR_CLASSES = {
248
425
  };
249
426
  var TILE_GRID = "grid grid-cols-1 sm:grid-cols-2 2xl:grid-cols-3 gap-6";
250
427
  function PlaygroundTile({ item, onNavigate }) {
251
- return /* @__PURE__ */ jsxs(
428
+ return /* @__PURE__ */ jsxs2(
252
429
  Card,
253
430
  {
254
431
  className: "cursor-pointer shadow-sm border rounded-md p-6 transition-transform duration-200 motion-safe:hover:-translate-y-1",
255
432
  onClick: () => onNavigate(item.path),
256
433
  children: [
257
- /* @__PURE__ */ jsx("div", { className: "flex items-center mb-4", children: /* @__PURE__ */ jsx(
434
+ /* @__PURE__ */ jsx3("div", { className: "flex items-center mb-4", children: /* @__PURE__ */ jsx3(
258
435
  "div",
259
436
  {
260
437
  className: `flex items-center justify-center w-9 h-9 rounded-md ${COLOR_CLASSES[item.color] ?? COLOR_CLASSES.blue}`,
261
- children: /* @__PURE__ */ jsx(item.icon, { size: 18 })
438
+ children: /* @__PURE__ */ jsx3(item.icon, { size: 18 })
262
439
  }
263
440
  ) }),
264
- /* @__PURE__ */ jsx("h3", { className: "heading-section mb-1", children: item.title }),
265
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: item.description })
441
+ /* @__PURE__ */ jsx3("h3", { className: "heading-section mb-1", children: item.title }),
442
+ /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: item.description })
266
443
  ]
267
444
  }
268
445
  );
@@ -275,27 +452,36 @@ function PlaygroundOverview({
275
452
  grouped: initialGrouped = true
276
453
  }) {
277
454
  const navigate = useNavigate();
278
- const [grouped, setGrouped] = useState(initialGrouped);
455
+ const [grouped, setGrouped] = useState3(initialGrouped);
279
456
  const handleNavigate = (path) => navigate(`${basePath}/${path}`);
280
- return /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
281
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between mb-6", children: [
282
- /* @__PURE__ */ jsxs("div", { children: [
283
- /* @__PURE__ */ jsx("h1", { className: "mb-1", children: title }),
284
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle })
457
+ return /* @__PURE__ */ jsxs2("div", { className: "w-full", children: [
458
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between mb-6", children: [
459
+ /* @__PURE__ */ jsxs2("div", { children: [
460
+ /* @__PURE__ */ jsx3("h1", { className: "mb-1", children: title }),
461
+ /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: subtitle })
285
462
  ] }),
286
- /* @__PURE__ */ jsx(SimpleTooltip, { label: grouped ? "Show flat list" : "Group by category", children: /* @__PURE__ */ jsx(
287
- Button,
288
- {
289
- variant: "ghost",
290
- size: "icon",
291
- onClick: () => setGrouped((v) => !v),
292
- children: grouped ? /* @__PURE__ */ jsx(LayoutGrid, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(List, { className: "h-4 w-4" })
293
- }
294
- ) })
463
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1", children: [
464
+ /* @__PURE__ */ jsx3(
465
+ SimpleTooltip,
466
+ {
467
+ label: grouped ? "Show flat list" : "Group by category",
468
+ children: /* @__PURE__ */ jsx3(
469
+ Button,
470
+ {
471
+ variant: "ghost",
472
+ size: "icon",
473
+ onClick: () => setGrouped((v) => !v),
474
+ children: grouped ? /* @__PURE__ */ jsx3(LayoutGrid, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(List, { className: "h-4 w-4" })
475
+ }
476
+ )
477
+ }
478
+ ),
479
+ /* @__PURE__ */ jsx3(PlaygroundSettingsPanel, {})
480
+ ] })
295
481
  ] }),
296
- grouped ? registry.getGrouped().map(([groupLabel, entries]) => /* @__PURE__ */ jsxs("div", { className: "mb-8", children: [
297
- /* @__PURE__ */ jsx("h2", { className: "text-sm font-medium text-muted-foreground uppercase tracking-wider mb-4", children: groupLabel }),
298
- /* @__PURE__ */ jsx("div", { className: TILE_GRID, children: entries.map((item) => /* @__PURE__ */ jsx(
482
+ grouped ? registry.getGrouped().map(([groupLabel, entries]) => /* @__PURE__ */ jsxs2("div", { className: "mb-8", children: [
483
+ /* @__PURE__ */ jsx3("h2", { className: "text-sm font-medium text-muted-foreground uppercase tracking-wider mb-4", children: groupLabel }),
484
+ /* @__PURE__ */ jsx3("div", { className: TILE_GRID, children: entries.map((item) => /* @__PURE__ */ jsx3(
299
485
  PlaygroundTile,
300
486
  {
301
487
  item,
@@ -303,7 +489,7 @@ function PlaygroundOverview({
303
489
  },
304
490
  item.id
305
491
  )) })
306
- ] }, groupLabel)) : /* @__PURE__ */ jsx("div", { className: TILE_GRID, children: registry.getAll().map((item) => /* @__PURE__ */ jsx(
492
+ ] }, groupLabel)) : /* @__PURE__ */ jsx3("div", { className: TILE_GRID, children: registry.getAll().map((item) => /* @__PURE__ */ jsx3(
307
493
  PlaygroundTile,
308
494
  {
309
495
  item,
@@ -315,15 +501,14 @@ function PlaygroundOverview({
315
501
  }
316
502
 
317
503
  // src/createPlaygroundModule.tsx
318
- import { jsx as jsx2 } from "react/jsx-runtime";
504
+ import { jsx as jsx4 } from "react/jsx-runtime";
319
505
  function buildNavigation(registry, basePath) {
320
506
  const groups = registry.getGrouped();
321
507
  const navGroups = [];
322
- const overviewGroup = {
508
+ navGroups.push({
323
509
  id: "playground-overview",
324
510
  links: [{ label: "Overview", path: basePath }]
325
- };
326
- navGroups.push(overviewGroup);
511
+ });
327
512
  for (const [groupLabel, entries] of groups) {
328
513
  navGroups.push({
329
514
  id: `playground-${groupLabel.toLowerCase().replace(/\s+/g, "-")}`,
@@ -337,7 +522,10 @@ function buildNavigation(registry, basePath) {
337
522
  return navGroups;
338
523
  }
339
524
  function suspended(Component) {
340
- return /* @__PURE__ */ jsx2(Suspense, { children: /* @__PURE__ */ jsx2(Component, {}) });
525
+ return /* @__PURE__ */ jsx4(Suspense, { children: /* @__PURE__ */ jsx4(Component, {}) });
526
+ }
527
+ function PlaygroundLayout() {
528
+ return /* @__PURE__ */ jsx4(PlaygroundSettingsProvider, { children: /* @__PURE__ */ jsx4(Outlet, {}) });
341
529
  }
342
530
  function createPlaygroundModule(registry, options = {}) {
343
531
  const {
@@ -352,21 +540,27 @@ function createPlaygroundModule(registry, options = {}) {
352
540
  const routes = [
353
541
  {
354
542
  path: routeBase,
355
- element: suspended(() => /* @__PURE__ */ jsx2(
356
- PlaygroundOverview,
543
+ element: /* @__PURE__ */ jsx4(PlaygroundLayout, {}),
544
+ children: [
357
545
  {
358
- registry,
359
- basePath,
360
- title: overviewTitle,
361
- subtitle: overviewSubtitle,
362
- grouped
363
- }
364
- ))
365
- },
366
- ...registry.getAll().map((entry) => ({
367
- path: `${routeBase}/${entry.path}`,
368
- element: suspended(entry.component)
369
- }))
546
+ index: true,
547
+ element: suspended(() => /* @__PURE__ */ jsx4(
548
+ PlaygroundOverview,
549
+ {
550
+ registry,
551
+ basePath,
552
+ title: overviewTitle,
553
+ subtitle: overviewSubtitle,
554
+ grouped
555
+ }
556
+ ))
557
+ },
558
+ ...registry.getAll().map((entry) => ({
559
+ path: entry.path,
560
+ element: suspended(entry.component)
561
+ }))
562
+ ]
563
+ }
370
564
  ];
371
565
  return {
372
566
  id: "playground",
@@ -386,11 +580,15 @@ function createPlaygroundRegistry() {
386
580
  return registry;
387
581
  }
388
582
  export {
583
+ ExampleBlock,
389
584
  PlaygroundOverview,
390
585
  PlaygroundRegistry,
391
586
  PlaygroundSection,
587
+ PlaygroundSettingsPanel,
588
+ PlaygroundSettingsProvider,
392
589
  builtinEntries,
393
590
  createPlaygroundModule,
394
- createPlaygroundRegistry
591
+ createPlaygroundRegistry,
592
+ usePlaygroundSettings
395
593
  };
396
594
  //# sourceMappingURL=index.js.map