@petrarca/sonnet-playground 0.5.0 → 0.6.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pages/PlayForms.tsx"],"sourcesContent":["/**\n * Playground page for testing JsonSchemaFormRenderer\n * Accessible at /playground/forms\n */\n\nimport { useState, useCallback } from \"react\";\nimport type { FormDiff } from \"@petrarca/sonnet-core/schema\";\nimport {\n SimpleStack,\n SimpleGroup,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Card,\n Badge,\n SimpleTooltip,\n Button,\n} from \"@petrarca/sonnet-ui\";\nimport {\n FormSelect,\n FormCheckbox,\n JsonSchemaFormRenderer,\n type UISchema,\n} from \"@petrarca/sonnet-forms\";\nimport { JsonEditor } from \"@petrarca/sonnet-ui/json-editor\";\nimport {\n ArrowRight,\n ChevronLeft,\n ChevronRight as ChevronRightIcon,\n} from \"lucide-react\";\nimport type { JsonSchema, UILayoutConfig } from \"@petrarca/sonnet-core/schema\";\n\n// Sample schemas\nconst SAMPLE_SCHEMA: JsonSchema = {\n title: \"Practitioner\",\n type: \"object\",\n properties: {\n name: { type: \"string\", title: \"Full Name\" },\n npi: { type: \"string\", title: \"NPI\" },\n specialty: {\n type: \"string\",\n title: \"Specialty\",\n enum: [\"cardiology\", \"neurology\", \"oncology\", \"radiology\", \"general\"],\n },\n notes: {\n type: \"string\",\n title: \"Notes\",\n \"x-ui-widget\": \"textarea\",\n },\n years_experience: {\n type: \"integer\",\n title: \"Years of Experience\",\n minimum: 0,\n maximum: 60,\n },\n active: { type: \"boolean\", title: \"Active\" },\n },\n required: [\"name\", \"npi\"],\n};\n\n// Nested object (1:1)\nconst NESTED_OBJECT_SCHEMA: JsonSchema = {\n title: \"Patient\",\n type: \"object\",\n properties: {\n family_name: { type: \"string\", title: \"Family Name\" },\n given_name: { type: \"string\", title: \"Given Name\" },\n birth_date: { type: \"string\", title: \"Date of Birth\", format: \"date\" },\n contact: {\n type: \"object\",\n title: \"Contact\",\n properties: {\n phone: { type: \"string\", title: \"Phone\" },\n email: { type: \"string\", title: \"Email\", format: \"email\" },\n address: { type: \"string\", title: \"Address\" },\n city: { type: \"string\", title: \"City\" },\n country: {\n type: \"string\",\n title: \"Country\",\n enum: [\"DE\", \"AT\", \"CH\", \"US\", \"GB\"],\n },\n },\n required: [\"phone\"],\n },\n },\n required: [\"family_name\", \"given_name\"],\n};\n\n// Discriminated union (oneOf) -- a variant field that swaps shape by branch.\nconst ONEOF_SCHEMA: JsonSchema = {\n title: \"Payment\",\n type: \"object\",\n properties: {\n amount: { type: \"number\", title: \"Amount\" },\n method: {\n type: \"object\",\n title: \"Payment method\",\n discriminator: { propertyName: \"kind\" },\n oneOf: [\n {\n title: \"Credit card\",\n properties: {\n kind: { const: \"card\" },\n cardNumber: { type: \"string\", title: \"Card number\" },\n expiry: { type: \"string\", title: \"Expiry (MM/YY)\" },\n },\n required: [\"cardNumber\"],\n },\n {\n title: \"Bank transfer\",\n properties: {\n kind: { const: \"bank\" },\n iban: { type: \"string\", title: \"IBAN\" },\n },\n required: [\"iban\"],\n },\n {\n title: \"Cash\",\n properties: {\n kind: { const: \"cash\" },\n note: { type: \"string\", title: \"Note\" },\n },\n },\n ],\n },\n },\n required: [\"amount\"],\n};\n\n// Array of objects (1:n)\nconst ARRAY_OF_OBJECTS_SCHEMA: JsonSchema = {\n title: \"Medication Request\",\n type: \"object\",\n properties: {\n patient_id: { type: \"string\", title: \"Patient ID\" },\n prescriber: { type: \"string\", title: \"Prescriber\" },\n medications: {\n type: \"array\",\n title: \"Medications\",\n \"x-ui-options\": {\n addLabel: \"Add Medication\",\n emptyMessage: \"No medications added\",\n orderable: true,\n },\n items: {\n type: \"object\",\n properties: {\n drug_name: { type: \"string\", title: \"Drug Name\" },\n dose: { type: \"string\", title: \"Dose\" },\n route: {\n type: \"string\",\n title: \"Route\",\n enum: [\"oral\", \"IV\", \"subcutaneous\", \"topical\", \"inhaled\"],\n },\n frequency: { type: \"string\", title: \"Frequency\" },\n active: { type: \"boolean\", title: \"Active\" },\n },\n required: [\"drug_name\", \"dose\"],\n },\n minItems: 1,\n maxItems: 10,\n },\n },\n required: [\"patient_id\", \"prescriber\"],\n};\n\n// $ref with $defs\nconst REF_SCHEMA: JsonSchema = {\n title: \"Care Plan\",\n type: \"object\",\n $defs: {\n period: {\n type: \"object\",\n properties: {\n start: { type: \"string\", title: \"Start Date\", format: \"date\" },\n end: { type: \"string\", title: \"End Date\", format: \"date\" },\n },\n required: [\"start\"],\n },\n },\n properties: {\n patient_id: { type: \"string\", title: \"Patient ID\" },\n title: { type: \"string\", title: \"Plan Title\" },\n validity: {\n $ref: \"#/$defs/period\",\n title: \"Validity Period\",\n },\n activities: {\n type: \"array\",\n title: \"Activities\",\n \"x-ui-options\": {\n addLabel: \"Add Activity\",\n orderable: true,\n },\n items: {\n type: \"object\",\n properties: {\n description: { type: \"string\", title: \"Description\" },\n schedule: {\n $ref: \"#/$defs/period\",\n title: \"Schedule\",\n },\n },\n required: [\"description\"],\n },\n maxItems: 5,\n },\n },\n required: [\"patient_id\", \"title\"],\n};\n\n// Horizontal array layout -- inline grid rows\nconst HORIZONTAL_ARRAY_SCHEMA: JsonSchema = {\n title: \"Observation Panel\",\n type: \"object\",\n properties: {\n subject: { type: \"string\", title: \"Subject ID\" },\n observations: {\n type: \"array\",\n title: \"Observations\",\n \"x-ui-layout\": {\n direction: \"horizontal\",\n columns: \"1fr 1fr 1fr 80px\",\n gap: 8,\n compact: true,\n },\n \"x-ui-options\": {\n addLabel: \"Add Observation\",\n emptyMessage: \"No observations recorded\",\n orderable: true,\n },\n items: {\n type: \"object\",\n properties: {\n code: {\n type: \"string\",\n title: \"LOINC Code\",\n enum: [\"8310-5\", \"8867-4\", \"9279-1\", \"29463-7\"],\n },\n value: { type: \"string\", title: \"Value\" },\n unit: {\n type: \"string\",\n title: \"Unit\",\n enum: [\"Cel\", \"/min\", \"kg\", \"mmHg\", \"%\"],\n },\n abnormal: { type: \"boolean\", title: \"Abnormal\" },\n },\n required: [\"code\", \"value\"],\n },\n minItems: 0,\n maxItems: 20,\n },\n },\n required: [\"subject\"],\n};\n\n// Horizontal array layout -- full-height rows, no compact sizing\nconst HORIZONTAL_FULL_SCHEMA: JsonSchema = {\n title: \"Allergy List\",\n type: \"object\",\n properties: {\n patient_id: { type: \"string\", title: \"Patient ID\" },\n allergies: {\n type: \"array\",\n title: \"Allergies\",\n \"x-ui-layout\": {\n direction: \"horizontal\",\n columns: \"2fr 1fr 1fr\",\n gap: 12,\n },\n \"x-ui-options\": {\n addLabel: \"Add Allergy\",\n emptyMessage: \"No allergies recorded\",\n orderable: true,\n },\n items: {\n type: \"object\",\n properties: {\n substance: { type: \"string\", title: \"Substance\" },\n severity: {\n type: \"string\",\n title: \"Severity\",\n enum: [\"mild\", \"moderate\", \"severe\"],\n },\n reaction: { type: \"string\", title: \"Reaction\" },\n },\n required: [\"substance\"],\n },\n },\n },\n required: [\"patient_id\"],\n};\n\n// Mixed: flat fields + nested object + array with variants\nconst MIXED_SCHEMA: JsonSchema = {\n title: \"Healthcare Organization\",\n type: \"object\",\n properties: {\n name: { type: \"string\", title: \"Name\" },\n type: {\n type: \"string\",\n title: \"Type\",\n enum: [\"hospital\", \"clinic\", \"lab\", \"pharmacy\"],\n },\n active: { type: \"boolean\", title: \"Active\" },\n location: {\n type: \"object\",\n title: \"Location\",\n \"x-ui-options\": { variant: \"card\" },\n properties: {\n address: { type: \"string\", title: \"Address\" },\n city: { type: \"string\", title: \"City\" },\n postal_code: { type: \"string\", title: \"Postal Code\" },\n country: {\n type: \"string\",\n title: \"Country\",\n enum: [\"DE\", \"AT\", \"CH\", \"US\", \"GB\"],\n },\n },\n required: [\"address\", \"city\"],\n },\n contacts: {\n type: \"array\",\n title: \"Contacts\",\n \"x-ui-options\": {\n addLabel: \"Add Contact\",\n orderable: true,\n emptyMessage: \"No contacts defined\",\n },\n items: {\n type: \"object\",\n properties: {\n name: { type: \"string\", title: \"Name\" },\n role: {\n type: \"string\",\n title: \"Role\",\n enum: [\"admin\", \"clinical\", \"billing\", \"technical\"],\n },\n email: { type: \"string\", title: \"Email\", format: \"email\" },\n phone: { type: \"string\", title: \"Phone\" },\n },\n required: [\"name\", \"email\"],\n },\n minItems: 1,\n },\n },\n required: [\"name\", \"type\"],\n};\n\n// Row layout: fields grouped into multi-column rows via x-ui-layout.rows\nconst ROW_LAYOUT_SCHEMA: JsonSchema = {\n title: \"Practitioner Registration\",\n type: \"object\",\n properties: {\n given_name: { type: \"string\", title: \"Given Name\" },\n family_name: { type: \"string\", title: \"Family Name\" },\n npi: { type: \"string\", title: \"NPI\" },\n specialty: {\n type: \"string\",\n title: \"Specialty\",\n enum: [\"cardiology\", \"neurology\", \"oncology\", \"radiology\", \"general\"],\n },\n email: { type: \"string\", title: \"Email\", format: \"email\" },\n phone: { type: \"string\", title: \"Phone\" },\n start_date: { type: \"string\", title: \"Start Date\" },\n end_date: { type: \"string\", title: \"End Date\" },\n notes: { type: \"string\", title: \"Notes\", \"x-ui-widget\": \"textarea\" },\n active: { type: \"boolean\", title: \"Active\" },\n },\n required: [\"given_name\", \"family_name\", \"npi\"],\n};\n\n// x-ui-layout is a top-level meta-key, not a per-field UISchema.\n// The renderer reads it via index access so the cast is safe here.\nconst ROW_LAYOUT_UISCHEMA: Record<string, UISchema> = {\n \"x-ui-layout\": {\n rows: [\n { fields: [\"given_name\", \"family_name\"], columns: \"1fr 1fr\" },\n { fields: [\"npi\", \"specialty\"], columns: \"1fr 1fr\" },\n { fields: [\"email\", \"phone\"], columns: \"1fr 1fr\" },\n { fields: [\"start_date\", \"end_date\"], columns: \"1fr 1fr\" },\n ],\n } as unknown as UISchema,\n};\n\n// Tabbed layout over the same registration schema: rows nest inside tabs, one\n// tab appears only when `active` is checked, and required fields left empty\n// badge their tab with an error count (visible from any tab).\nconst GROUP_LAYOUT_UISCHEMA: Record<string, UISchema> = {\n \"x-ui-layout\": {\n groups: [\n {\n label: \"Identity\",\n rows: [\n { fields: [\"given_name\", \"family_name\"], columns: \"1fr 1fr\" },\n { fields: [\"npi\", \"specialty\"], columns: \"1fr 1fr\" },\n ],\n },\n {\n label: \"Contact\",\n rows: [{ fields: [\"email\", \"phone\"], columns: \"1fr 1fr\" }],\n },\n {\n label: \"Engagement\",\n rows: [\n { fields: [\"start_date\", \"end_date\"], columns: \"1fr 1fr\" },\n { fields: [\"active\"] },\n ],\n },\n {\n label: \"Notes\",\n rows: [{ fields: [\"notes\"] }],\n rule: {\n effect: \"show\",\n condition: { scope: \"/active\", schema: { const: true } },\n },\n },\n ],\n } as unknown as UISchema,\n};\n\n// The same groups presented as a wizard: only `variant` differs, proving the\n// presentation is a swappable template rather than a second layout model.\nconst STEPPER_LAYOUT_UISCHEMA: Record<string, UISchema> = {\n \"x-ui-layout\": {\n variant: \"stepper\",\n groups: (GROUP_LAYOUT_UISCHEMA[\"x-ui-layout\"] as unknown as UILayoutConfig)\n .groups,\n } as unknown as UISchema,\n};\n\n// The same groups again, stacked as sections: every group visible at once,\n// each spanning as many rows as it declares.\nconst SECTIONS_LAYOUT_UISCHEMA: Record<string, UISchema> = {\n \"x-ui-layout\": {\n variant: \"sections\",\n groups: (GROUP_LAYOUT_UISCHEMA[\"x-ui-layout\"] as unknown as UILayoutConfig)\n .groups,\n } as unknown as UISchema,\n};\n\nconst sampleSchemas: Record<string, JsonSchema> = {\n flat: SAMPLE_SCHEMA,\n nested_object: NESTED_OBJECT_SCHEMA,\n one_of: ONEOF_SCHEMA,\n array_of_objects: ARRAY_OF_OBJECTS_SCHEMA,\n ref_defs: REF_SCHEMA,\n mixed: MIXED_SCHEMA,\n horizontal_array: HORIZONTAL_ARRAY_SCHEMA,\n horizontal_full: HORIZONTAL_FULL_SCHEMA,\n row_layout: ROW_LAYOUT_SCHEMA,\n tab_layout: ROW_LAYOUT_SCHEMA,\n stepper_layout: ROW_LAYOUT_SCHEMA,\n sections_layout: ROW_LAYOUT_SCHEMA,\n};\n\n// Schema presets that ship with a matching uiSchema (layout demos).\nconst PAIRED_UISCHEMAS: Record<string, Record<string, UISchema>> = {\n row_layout: ROW_LAYOUT_UISCHEMA,\n tab_layout: GROUP_LAYOUT_UISCHEMA,\n stepper_layout: STEPPER_LAYOUT_UISCHEMA,\n sections_layout: SECTIONS_LAYOUT_UISCHEMA,\n};\n\n// Sample UI Schemas\nconst sampleUiSchemas: Record<string, string> = {\n empty: \"{}\",\n hideLabels: JSON.stringify(\n {\n \"x-ui-globalOptions\": {\n label: false,\n },\n },\n null,\n 2,\n ),\n disableAll: JSON.stringify(\n {\n \"x-ui-globalOptions\": {\n disabled: true,\n },\n },\n null,\n 2,\n ),\n readonlyAll: JSON.stringify(\n {\n \"x-ui-globalOptions\": {\n readonly: true,\n },\n },\n null,\n 2,\n ),\n fieldOverride: JSON.stringify(\n {\n \"x-ui-globalOptions\": {\n disabled: true,\n },\n name: {\n \"x-ui-options\": {\n disabled: false, // Override: enable this field\n },\n },\n },\n null,\n 2,\n ),\n customWidget: JSON.stringify(\n {\n description: {\n \"x-ui-widget\": \"textarea\",\n \"x-ui-options\": {\n rows: 5,\n },\n },\n },\n null,\n 2,\n ),\n};\n\n// -- State hook ----------------------------------------------------------\n\nfunction usePlayFormsState() {\n const [schemaText, setSchemaText] = useState(\n JSON.stringify(SAMPLE_SCHEMA, null, 2),\n );\n const [uiSchemaText, setUiSchemaText] = useState(\"{}\");\n const [activeSchema, setActiveSchema] = useState<JsonSchema | null>(\n SAMPLE_SCHEMA,\n );\n const [activeUiSchema, setActiveUiSchema] = useState<\n Record<string, UISchema>\n >({});\n const [dataText, setDataText] = useState(\"{}\");\n const [formData, setFormData] = useState<Record<string, unknown>>({});\n const [validationErrors, setValidationErrors] = useState<string[]>([]);\n const [isValid, setIsValid] = useState(true);\n const [schemaError, setSchemaError] = useState(\"\");\n const [uiSchemaError, setUiSchemaError] = useState(\"\");\n const [dataError, setDataError] = useState(\"\");\n const [activeTab, setActiveTab] = useState(\"schema\");\n const [deferStateUpdates, setDeferStateUpdates] = useState(false);\n const [dataCollapsed, setDataCollapsed] = useState(false);\n const [lastDiff, setLastDiff] = useState<FormDiff | null>(null);\n const toggleDataPanel = useCallback(() => setDataCollapsed((v) => !v), []);\n\n const loadSchemaPreset = useCallback((value: string | null) => {\n if (!value || !sampleSchemas[value]) return;\n const text = JSON.stringify(sampleSchemas[value], null, 2);\n setSchemaText(text);\n setActiveSchema(sampleSchemas[value]);\n setSchemaError(\"\");\n setFormData({});\n setDataText(\"{}\");\n const pairedUi = PAIRED_UISCHEMAS[value] ?? {};\n setUiSchemaText(JSON.stringify(pairedUi, null, 2));\n setActiveUiSchema(pairedUi);\n setUiSchemaError(\"\");\n }, []);\n\n const loadUiSchemaPreset = useCallback(\n (value: string | null) => {\n if (!value) return;\n setUiSchemaText(sampleUiSchemas[value]);\n setUiSchemaError(\"\");\n },\n [setUiSchemaText],\n );\n\n return {\n schemaText,\n uiSchemaText,\n activeSchema,\n activeUiSchema,\n dataText,\n formData,\n validationErrors,\n isValid,\n schemaError,\n uiSchemaError,\n dataError,\n activeTab,\n deferStateUpdates,\n dataCollapsed,\n lastDiff,\n setSchemaText,\n setUiSchemaText,\n setActiveSchema,\n setActiveUiSchema,\n setDataText,\n setFormData,\n setValidationErrors,\n setIsValid,\n setSchemaError,\n setUiSchemaError,\n setDataError,\n setActiveTab,\n setDeferStateUpdates,\n toggleDataPanel,\n setLastDiff,\n loadSchemaPreset,\n loadUiSchemaPreset,\n };\n}\n\n// -- JSON parse helpers --------------------------------------------------\n\nfunction tryParseAndSet(\n value: string,\n setError: (e: string) => void,\n errorMessage = \"Invalid JSON\",\n) {\n try {\n JSON.parse(value);\n setError(\"\");\n } catch {\n setError(errorMessage);\n }\n}\n\nfunction tryParseAndLoad<T>(\n text: string,\n onSuccess: (parsed: T) => void,\n onError: (msg: string) => void,\n) {\n try {\n onSuccess(JSON.parse(text));\n onError(\"\");\n } catch {\n onError(\"Invalid JSON - cannot load to form\");\n }\n}\n\n// -- Shared panel arrow button -------------------------------------------\n\ninterface PanelArrowButtonProps {\n label: string;\n onClick: () => void;\n mirrored?: boolean;\n}\n\nfunction PanelArrowButton({\n label,\n onClick,\n mirrored = false,\n}: PanelArrowButtonProps) {\n return (\n <SimpleTooltip label={label}>\n <Button\n variant=\"default\"\n size=\"icon\"\n className=\"absolute -right-5 top-1/2 -translate-y-1/2 z-[100]\"\n onClick={onClick}\n >\n <ArrowRight\n size={20}\n className={mirrored ? \"scale-x-[-1]\" : undefined}\n />\n </Button>\n </SimpleTooltip>\n );\n}\n\n// -- Left column: Schema / UI Schema editors -----------------------------\n\nfunction SchemaEditorColumn({\n state,\n}: {\n state: ReturnType<typeof usePlayFormsState>;\n}) {\n const handleSchemaTextChange = (value: string) => {\n state.setSchemaText(value);\n tryParseAndSet(value, state.setSchemaError);\n };\n\n const handleUiSchemaTextChange = (value: string) => {\n state.setUiSchemaText(value);\n tryParseAndSet(value, state.setUiSchemaError);\n };\n\n const handleLoadSchemaToForm = () => {\n tryParseAndLoad<JsonSchema>(\n state.schemaText,\n (parsed) => {\n state.setActiveSchema(parsed);\n state.setFormData({});\n state.setDataText(\"{}\");\n state.setValidationErrors([]);\n state.setIsValid(true);\n state.setLastDiff(null);\n },\n state.setSchemaError,\n );\n };\n\n const handleLoadUiSchemaToForm = () => {\n tryParseAndLoad<Record<string, UISchema>>(\n state.uiSchemaText,\n state.setActiveUiSchema,\n state.setUiSchemaError,\n );\n };\n\n return (\n <div\n style={{\n flex: 1,\n position: \"relative\",\n display: \"flex\",\n flexDirection: \"column\",\n minWidth: 0,\n }}\n >\n <Card className=\"border shadow-sm p-4 flex-1 min-h-0 flex flex-col\">\n <Tabs\n value={state.activeTab}\n onValueChange={state.setActiveTab}\n style={{\n flex: 1,\n minHeight: 0,\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n <TabsList className=\"mb-1\">\n <TabsTrigger value=\"schema\">JSON Schema</TabsTrigger>\n <TabsTrigger value=\"uischema\">UI Schema</TabsTrigger>\n </TabsList>\n\n <TabsContent\n value=\"schema\"\n className=\"flex-1 min-h-0 flex flex-col mt-0\"\n >\n <FormSelect\n placeholder=\"Load example schema...\"\n options={SCHEMA_PRESET_OPTIONS}\n onChange={state.loadSchemaPreset}\n className=\"text-xs\"\n wrapperClassName=\"mb-2\"\n />\n {state.schemaError && (\n <Badge variant=\"destructive\" className=\"text-xs mb-2\">\n {state.schemaError}\n </Badge>\n )}\n <JsonEditor\n value={state.schemaText}\n editablePaths={[\"/\"]}\n onChange={handleSchemaTextChange}\n height=\"100%\"\n className=\"flex-1 min-h-0 rounded-md border overflow-hidden\"\n />\n </TabsContent>\n\n <TabsContent\n value=\"uischema\"\n className=\"flex-1 min-h-0 flex flex-col mt-0\"\n >\n <FormSelect\n placeholder=\"Load example...\"\n options={UISCHEMA_PRESET_OPTIONS}\n onChange={state.loadUiSchemaPreset}\n className=\"text-xs\"\n wrapperClassName=\"mb-2\"\n />\n {state.uiSchemaError && (\n <Badge variant=\"destructive\" className=\"text-xs mb-2\">\n {state.uiSchemaError}\n </Badge>\n )}\n <JsonEditor\n value={state.uiSchemaText}\n editablePaths={[\"/\"]}\n onChange={handleUiSchemaTextChange}\n height=\"100%\"\n className=\"flex-1 min-h-0 rounded-md border overflow-hidden\"\n />\n </TabsContent>\n </Tabs>\n </Card>\n\n <PanelArrowButton\n label={\n state.activeTab === \"schema\"\n ? \"Load Schema to Form\"\n : \"Load UI Schema to Form\"\n }\n onClick={\n state.activeTab === \"schema\"\n ? handleLoadSchemaToForm\n : handleLoadUiSchemaToForm\n }\n />\n </div>\n );\n}\n\n// Preset option arrays (static, avoids re-creation).\nconst SCHEMA_PRESET_OPTIONS = [\n { value: \"flat\", label: \"Practitioner (flat fields)\" },\n { value: \"nested_object\", label: \"Patient (nested object)\" },\n { value: \"one_of\", label: \"Payment (oneOf variant)\" },\n { value: \"array_of_objects\", label: \"Medication Request (array)\" },\n { value: \"ref_defs\", label: \"Care Plan ($ref / $defs)\" },\n { value: \"mixed\", label: \"Organization (mixed)\" },\n { value: \"horizontal_array\", label: \"Observations (horizontal, compact)\" },\n { value: \"horizontal_full\", label: \"Allergies (horizontal, full height)\" },\n { value: \"row_layout\", label: \"Registration (row layout)\" },\n { value: \"tab_layout\", label: \"Registration (tab layout)\" },\n { value: \"stepper_layout\", label: \"Registration (stepper layout)\" },\n { value: \"sections_layout\", label: \"Registration (sections layout)\" },\n];\n\nconst UISCHEMA_PRESET_OPTIONS = [\n { value: \"empty\", label: \"Empty (no customization)\" },\n { value: \"hideLabels\", label: \"Hide all labels\" },\n { value: \"disableAll\", label: \"Disable all fields\" },\n { value: \"readonlyAll\", label: \"Readonly all fields\" },\n { value: \"fieldOverride\", label: \"Field-level override\" },\n { value: \"customWidget\", label: \"Custom widget\" },\n];\n\n// -- Middle column: Rendered form ----------------------------------------\n\nfunction FormColumn({\n state,\n}: {\n state: ReturnType<typeof usePlayFormsState>;\n}) {\n const handleUpdate = (\n data: Record<string, unknown>,\n _changedFields: Record<string, unknown>,\n diff: FormDiff,\n ) => {\n state.setDataText(JSON.stringify(data, null, 2));\n state.setFormData(data);\n state.setLastDiff(diff);\n };\n\n const handleCancel = () => {\n state.setFormData({});\n state.setDataText(\"{}\");\n state.setValidationErrors([]);\n state.setIsValid(true);\n state.setLastDiff(null);\n };\n\n const handleValidationChange = (errors: string[], valid: boolean) => {\n state.setValidationErrors(errors);\n state.setIsValid(valid);\n };\n\n const handleLoadDataToForm = () => {\n tryParseAndLoad(state.dataText, state.setFormData, state.setDataError);\n };\n\n return (\n <div\n style={{\n flex: 1,\n position: \"relative\",\n display: \"flex\",\n flexDirection: \"column\",\n minWidth: 0,\n }}\n >\n <Card className=\"border shadow-sm p-4 flex-1 min-h-0 flex flex-col\">\n <SimpleStack\n gap=\"md\"\n style={{\n flex: 1,\n minHeight: 0,\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n <div>\n <p className=\"text-sm font-semibold mb-1\">Rendered Form</p>\n <SimpleGroup gap=\"xs\" align=\"center\" className=\"mb-1\">\n <Badge\n variant={state.isValid ? \"default\" : \"destructive\"}\n className=\"text-xs\"\n >\n {state.isValid ? \"Valid\" : \"Invalid\"}\n </Badge>\n <FormCheckbox\n label=\"Defer state updates (change on blur)\"\n checked={state.deferStateUpdates}\n onChange={(checked) => {\n if (checked !== \"indeterminate\") {\n state.setDeferStateUpdates(checked);\n }\n }}\n />\n </SimpleGroup>\n {state.validationErrors.length > 0 && (\n <div style={{ marginTop: \"4px\" }}>\n {state.validationErrors.map((err, idx) => (\n <p key={idx} className=\"text-xs text-destructive\">\n {err}\n </p>\n ))}\n </div>\n )}\n </div>\n\n <div\n style={{\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n paddingRight: \"4px\",\n }}\n >\n {state.activeSchema && (\n <JsonSchemaFormRenderer\n schema={state.activeSchema}\n data={state.formData}\n onUpdate={handleUpdate}\n onCancel={handleCancel}\n onValidationChange={handleValidationChange}\n showActions={true}\n deferStateUpdates={state.deferStateUpdates}\n saveLabel=\"Save Changes\"\n cancelLabel=\"Reset\"\n showExtraProperties={true}\n uiSchema={state.activeUiSchema}\n />\n )}\n {!state.activeSchema && (\n <p className=\"text-sm text-muted-foreground text-center mt-8\">\n Edit the JSON Schema on the left and click the arrow to load it\n </p>\n )}\n </div>\n </SimpleStack>\n </Card>\n\n {!state.dataCollapsed && (\n <PanelArrowButton\n label=\"Load JSON Data into Form\"\n onClick={handleLoadDataToForm}\n mirrored\n />\n )}\n </div>\n );\n}\n\n// -- Right column: JSON data + diff --------------------------------------\n\nfunction DataColumn({\n state,\n}: {\n state: ReturnType<typeof usePlayFormsState>;\n}) {\n const handleDataTextChange = (value: string) => {\n state.setDataText(value);\n tryParseAndSet(value, state.setDataError);\n };\n\n return (\n <div\n style={{\n flex: state.dataCollapsed ? \"0 0 2.25rem\" : 1,\n display: \"flex\",\n flexDirection: \"column\",\n minWidth: 0,\n gap: \"0.75rem\",\n transition: \"flex 200ms ease\",\n }}\n >\n <Card\n className=\"border shadow-sm min-h-0 flex flex-col overflow-hidden\"\n style={{ flex: \"1 1 50%\" }}\n >\n <div className=\"flex items-center justify-between px-4 py-3 shrink-0\">\n {!state.dataCollapsed && (\n <p className=\"text-sm font-semibold\">JSON Data</p>\n )}\n <SimpleTooltip\n label={\n state.dataCollapsed ? \"Expand JSON data\" : \"Collapse JSON data\"\n }\n >\n <Button\n variant=\"ghost\"\n size=\"compact\"\n onClick={state.toggleDataPanel}\n className=\"ml-auto\"\n >\n {state.dataCollapsed ? (\n <ChevronLeft className=\"h-4 w-4\" />\n ) : (\n <ChevronRightIcon className=\"h-4 w-4\" />\n )}\n </Button>\n </SimpleTooltip>\n </div>\n\n {!state.dataCollapsed && (\n <div className=\"flex-1 min-h-0 flex flex-col px-4 pb-4\">\n {state.dataError && (\n <Badge variant=\"destructive\" className=\"text-xs mb-2\">\n {state.dataError}\n </Badge>\n )}\n <JsonEditor\n value={state.dataText}\n editablePaths={[\"/\"]}\n onChange={handleDataTextChange}\n height=\"100%\"\n className=\"flex-1 min-h-0 rounded-md border overflow-hidden\"\n />\n </div>\n )}\n </Card>\n\n {!state.dataCollapsed && (\n <Card\n className=\"border shadow-sm min-h-0 flex flex-col overflow-hidden\"\n style={{ flex: \"1 1 50%\" }}\n >\n <div className=\"flex items-center justify-between px-4 py-3 shrink-0\">\n <p className=\"text-sm font-semibold\">Diff</p>\n </div>\n <div className=\"flex-1 min-h-0 flex flex-col px-4 pb-4\">\n <JsonEditor\n value={JSON.stringify(state.lastDiff ?? [], null, 2)}\n editablePaths={[\"/\"]}\n height=\"100%\"\n className=\"flex-1 min-h-0 rounded-md border overflow-hidden\"\n />\n </div>\n </Card>\n )}\n </div>\n );\n}\n\n// -- Main component ------------------------------------------------------\n\nexport default function PlayForms() {\n const state = usePlayFormsState();\n\n return (\n <div className=\"w-full flex flex-col gap-3 h-[calc(100vh-8rem)]\">\n <div>\n <h1>Forms Playground</h1>\n <p className=\"text-sm text-muted-foreground mb-3\">\n Test and experiment with JsonSchemaFormRenderer. Edit the JSON Schema\n on the left, then load it into the form.\n </p>\n </div>\n\n <div\n style={{\n flex: 1,\n minHeight: 0,\n display: \"flex\",\n gap: \"1.5rem\",\n }}\n >\n <SchemaEditorColumn state={state} />\n <FormColumn state={state} />\n <DataColumn state={state} />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -93,13 +93,6 @@ declare class PlaygroundRegistry {
93
93
  get size(): number;
94
94
  }
95
95
 
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
96
  declare function createPlaygroundModule(registry: PlaygroundRegistry, options?: PlaygroundModuleOptions): ShellModule;
104
97
 
105
98
  /**
@@ -140,6 +133,45 @@ interface PlaygroundSectionProps {
140
133
  /** Titled section wrapper used across playground pages. */
141
134
  declare function PlaygroundSection({ title, description, children, variant, }: PlaygroundSectionProps): React$1.ReactElement;
142
135
 
136
+ /**
137
+ * Playground-scoped settings (locale, ...).
138
+ *
139
+ * A self-contained provider that wraps all playground routes. It owns a small
140
+ * settings object, persists it to a namespaced localStorage key, and renders a
141
+ * SonnetConfigProvider so the settings flow to every playground page.
142
+ *
143
+ * Scope and containment: the provider is nested under any host-app provider and
144
+ * merges onto it, so a playground override shadows the app/browser value only
145
+ * within the playground subtree -- it never mutates the host app's global
146
+ * config. The default is "inherit" (empty locale), so out of the box the
147
+ * playground changes nothing.
148
+ */
149
+
150
+ interface PlaygroundSettings {
151
+ /** BCP-47 locale override, or "" to inherit the app/browser locale. */
152
+ locale: string;
153
+ }
154
+ interface PlaygroundSettingsContextValue {
155
+ settings: PlaygroundSettings;
156
+ setSettings: (next: Partial<PlaygroundSettings>) => void;
157
+ }
158
+ interface PlaygroundSettingsProviderProps {
159
+ children: React$1.ReactNode;
160
+ }
161
+ declare function PlaygroundSettingsProvider({ children, }: PlaygroundSettingsProviderProps): React$1.ReactElement;
162
+ /** Access playground settings. Returns defaults when no provider is present. */
163
+ declare function usePlaygroundSettings(): PlaygroundSettingsContextValue;
164
+
165
+ /**
166
+ * PlaygroundSettingsPanel -- gear button that opens a right-side settings sheet.
167
+ *
168
+ * Hosts playground-wide settings (currently locale). Edits flow through
169
+ * usePlaygroundSettings, which drives the SonnetConfigProvider wrapping all
170
+ * playground routes.
171
+ */
172
+
173
+ declare function PlaygroundSettingsPanel(): React$1.ReactElement;
174
+
143
175
  declare const builtinEntries: PlaygroundEntry[];
144
176
 
145
177
  /**
@@ -168,4 +200,4 @@ declare const builtinEntries: PlaygroundEntry[];
168
200
  */
169
201
  declare function createPlaygroundRegistry(): PlaygroundRegistry;
170
202
 
171
- export { type PlaygroundColor, type PlaygroundEntry, type PlaygroundModuleOptions, PlaygroundOverview, PlaygroundRegistry, PlaygroundSection, builtinEntries, createPlaygroundModule, createPlaygroundRegistry };
203
+ export { type PlaygroundColor, type PlaygroundEntry, type PlaygroundModuleOptions, PlaygroundOverview, PlaygroundRegistry, PlaygroundSection, type PlaygroundSettings, PlaygroundSettingsPanel, PlaygroundSettingsProvider, builtinEntries, createPlaygroundModule, createPlaygroundRegistry, usePlaygroundSettings };
package/dist/index.js CHANGED
@@ -119,7 +119,7 @@ var builtinEntries = [
119
119
  icon: Grid,
120
120
  color: "indigo",
121
121
  path: "core-components",
122
- component: lazy(() => import("./PlayCoreComponents-AG5D4SBS.js")),
122
+ component: lazy(() => import("./PlayCoreComponents-YTEAS3GL.js")),
123
123
  group: "Components",
124
124
  order: 0
125
125
  },
@@ -163,7 +163,7 @@ var builtinEntries = [
163
163
  icon: Edit,
164
164
  color: "purple",
165
165
  path: "forms",
166
- component: lazy(() => import("./PlayForms-FOF3XE6G.js")),
166
+ component: lazy(() => import("./PlayForms-2G7PROCH.js")),
167
167
  group: "Forms",
168
168
  order: 1
169
169
  },
@@ -174,7 +174,7 @@ var builtinEntries = [
174
174
  icon: Package,
175
175
  color: "indigo",
176
176
  path: "form-widgets",
177
- component: lazy(() => import("./PlayFormWidgets-IWJJQ5XL.js")),
177
+ component: lazy(() => import("./PlayFormWidgets-6JYFRTAL.js")),
178
178
  group: "Forms",
179
179
  order: 2
180
180
  },
@@ -185,7 +185,7 @@ var builtinEntries = [
185
185
  icon: PencilRuler,
186
186
  color: "teal",
187
187
  path: "schema-designer",
188
- component: lazy(() => import("./PlaySchemaDesigner-B2RVRRCH.js")),
188
+ component: lazy(() => import("./PlaySchemaDesigner-ZM4F7KBU.js")),
189
189
  group: "Schemas",
190
190
  order: 0
191
191
  },
@@ -226,14 +226,147 @@ var builtinEntries = [
226
226
 
227
227
  // src/createPlaygroundModule.tsx
228
228
  import { Suspense } from "react";
229
+ import { Outlet } from "react-router-dom";
229
230
  import { FlaskConical } from "lucide-react";
230
231
 
231
232
  // src/PlaygroundOverview.tsx
232
- import { useState } from "react";
233
+ import { useState as useState3 } from "react";
233
234
  import { useNavigate } from "react-router-dom";
234
235
  import { LayoutGrid, List } from "lucide-react";
235
236
  import { Card, Button, SimpleTooltip } from "@petrarca/sonnet-ui";
236
- import { jsx, jsxs } from "react/jsx-runtime";
237
+
238
+ // src/PlaygroundSettingsPanel.tsx
239
+ import { useState as useState2 } from "react";
240
+ import { Settings } from "lucide-react";
241
+ import {
242
+ IconButton,
243
+ Label,
244
+ Sheet,
245
+ SheetContent,
246
+ SheetHeader,
247
+ SheetTitle,
248
+ SheetDescription,
249
+ SheetBody,
250
+ Select,
251
+ SelectTrigger,
252
+ SelectValue,
253
+ SelectContent,
254
+ SelectItem
255
+ } from "@petrarca/sonnet-ui";
256
+
257
+ // src/PlaygroundSettings.tsx
258
+ import {
259
+ createContext,
260
+ useCallback,
261
+ useContext,
262
+ useMemo,
263
+ useState
264
+ } from "react";
265
+ import { SonnetConfigProvider } from "@petrarca/sonnet-core/config";
266
+ import { jsx } from "react/jsx-runtime";
267
+ var STORAGE_KEY = "sonnet.playground.settings";
268
+ var DEFAULT_SETTINGS = { locale: "" };
269
+ var PlaygroundSettingsContext = createContext(null);
270
+ var storage = {
271
+ get(key) {
272
+ try {
273
+ return typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
274
+ } catch {
275
+ return null;
276
+ }
277
+ },
278
+ set(key, value) {
279
+ try {
280
+ if (typeof localStorage !== "undefined") localStorage.setItem(key, value);
281
+ } catch {
282
+ }
283
+ }
284
+ };
285
+ function loadSettings() {
286
+ const raw = storage.get(STORAGE_KEY);
287
+ if (!raw) return DEFAULT_SETTINGS;
288
+ try {
289
+ return { ...DEFAULT_SETTINGS, ...JSON.parse(raw) };
290
+ } catch {
291
+ return DEFAULT_SETTINGS;
292
+ }
293
+ }
294
+ function persistSettings(settings) {
295
+ storage.set(STORAGE_KEY, JSON.stringify(settings));
296
+ }
297
+ function PlaygroundSettingsProvider({
298
+ children
299
+ }) {
300
+ const [settings, setSettingsState] = useState(loadSettings);
301
+ const setSettings = useCallback(
302
+ (next) => setSettingsState((prev) => {
303
+ const merged = { ...prev, ...next };
304
+ persistSettings(merged);
305
+ return merged;
306
+ }),
307
+ []
308
+ );
309
+ const contextValue = useMemo(
310
+ () => ({ settings, setSettings }),
311
+ [settings, setSettings]
312
+ );
313
+ const config = useMemo(
314
+ () => ({ globals: { locale: settings.locale || void 0 } }),
315
+ [settings.locale]
316
+ );
317
+ return /* @__PURE__ */ jsx(PlaygroundSettingsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(SonnetConfigProvider, { value: config, children }) });
318
+ }
319
+ function usePlaygroundSettings() {
320
+ return useContext(PlaygroundSettingsContext) ?? {
321
+ settings: DEFAULT_SETTINGS,
322
+ setSettings: () => {
323
+ }
324
+ };
325
+ }
326
+
327
+ // src/PlaygroundSettingsPanel.tsx
328
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
329
+ var INHERIT = "__inherit__";
330
+ var LOCALE_OPTIONS = [
331
+ { code: INHERIT, label: "Inherit (app / browser)" },
332
+ { code: "en-US", label: "English (US) - MM/DD, Sun" },
333
+ { code: "en-GB", label: "English (UK) - DD/MM, Mon" },
334
+ { code: "de-DE", label: "German - DD.MM, Mon" },
335
+ { code: "fr-FR", label: "French - DD/MM, Mon" },
336
+ { code: "sv-SE", label: "Swedish - YYYY-MM-DD, Mon" },
337
+ { code: "ja-JP", label: "Japanese - YYYY/MM/DD, Sun" }
338
+ ];
339
+ function PlaygroundSettingsPanel() {
340
+ const [open, setOpen] = useState2(false);
341
+ const { settings, setSettings } = usePlaygroundSettings();
342
+ return /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
343
+ /* @__PURE__ */ jsx2(IconButton, { label: "Playground settings", onClick: () => setOpen(true), children: /* @__PURE__ */ jsx2(Settings, {}) }),
344
+ /* @__PURE__ */ jsxs(SheetContent, { side: "right", children: [
345
+ /* @__PURE__ */ jsxs(SheetHeader, { children: [
346
+ /* @__PURE__ */ jsx2(SheetTitle, { children: "Playground settings" }),
347
+ /* @__PURE__ */ jsx2(SheetDescription, { children: "Scoped to the playground. Values exchanged with components stay locale-independent (ISO); only display and input parsing change." })
348
+ ] }),
349
+ /* @__PURE__ */ jsx2(SheetBody, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
350
+ /* @__PURE__ */ jsx2(Label, { htmlFor: "playground-locale", children: "Locale" }),
351
+ /* @__PURE__ */ jsxs(
352
+ Select,
353
+ {
354
+ value: settings.locale || INHERIT,
355
+ onValueChange: (value) => setSettings({ locale: value === INHERIT ? "" : value }),
356
+ children: [
357
+ /* @__PURE__ */ jsx2(SelectTrigger, { id: "playground-locale", children: /* @__PURE__ */ jsx2(SelectValue, {}) }),
358
+ /* @__PURE__ */ jsx2(SelectContent, { children: LOCALE_OPTIONS.map((opt) => /* @__PURE__ */ jsx2(SelectItem, { value: opt.code, children: opt.label }, opt.code)) })
359
+ ]
360
+ }
361
+ ),
362
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-tertiary-foreground", children: "Drives locale-sensitive components (e.g. Date Input) across every playground page." })
363
+ ] }) })
364
+ ] })
365
+ ] });
366
+ }
367
+
368
+ // src/PlaygroundOverview.tsx
369
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
237
370
  var COLOR_CLASSES = {
238
371
  blue: "bg-blue-100 text-blue-600",
239
372
  violet: "bg-violet-100 text-violet-600",
@@ -248,21 +381,21 @@ var COLOR_CLASSES = {
248
381
  };
249
382
  var TILE_GRID = "grid grid-cols-1 sm:grid-cols-2 2xl:grid-cols-3 gap-6";
250
383
  function PlaygroundTile({ item, onNavigate }) {
251
- return /* @__PURE__ */ jsxs(
384
+ return /* @__PURE__ */ jsxs2(
252
385
  Card,
253
386
  {
254
387
  className: "cursor-pointer shadow-sm border rounded-md p-6 transition-transform duration-200 motion-safe:hover:-translate-y-1",
255
388
  onClick: () => onNavigate(item.path),
256
389
  children: [
257
- /* @__PURE__ */ jsx("div", { className: "flex items-center mb-4", children: /* @__PURE__ */ jsx(
390
+ /* @__PURE__ */ jsx3("div", { className: "flex items-center mb-4", children: /* @__PURE__ */ jsx3(
258
391
  "div",
259
392
  {
260
393
  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 })
394
+ children: /* @__PURE__ */ jsx3(item.icon, { size: 18 })
262
395
  }
263
396
  ) }),
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 })
397
+ /* @__PURE__ */ jsx3("h3", { className: "heading-section mb-1", children: item.title }),
398
+ /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: item.description })
266
399
  ]
267
400
  }
268
401
  );
@@ -275,27 +408,36 @@ function PlaygroundOverview({
275
408
  grouped: initialGrouped = true
276
409
  }) {
277
410
  const navigate = useNavigate();
278
- const [grouped, setGrouped] = useState(initialGrouped);
411
+ const [grouped, setGrouped] = useState3(initialGrouped);
279
412
  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 })
413
+ return /* @__PURE__ */ jsxs2("div", { className: "w-full", children: [
414
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between mb-6", children: [
415
+ /* @__PURE__ */ jsxs2("div", { children: [
416
+ /* @__PURE__ */ jsx3("h1", { className: "mb-1", children: title }),
417
+ /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: subtitle })
285
418
  ] }),
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
- ) })
419
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1", children: [
420
+ /* @__PURE__ */ jsx3(
421
+ SimpleTooltip,
422
+ {
423
+ label: grouped ? "Show flat list" : "Group by category",
424
+ children: /* @__PURE__ */ jsx3(
425
+ Button,
426
+ {
427
+ variant: "ghost",
428
+ size: "icon",
429
+ onClick: () => setGrouped((v) => !v),
430
+ children: grouped ? /* @__PURE__ */ jsx3(LayoutGrid, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx3(List, { className: "h-4 w-4" })
431
+ }
432
+ )
433
+ }
434
+ ),
435
+ /* @__PURE__ */ jsx3(PlaygroundSettingsPanel, {})
436
+ ] })
295
437
  ] }),
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(
438
+ grouped ? registry.getGrouped().map(([groupLabel, entries]) => /* @__PURE__ */ jsxs2("div", { className: "mb-8", children: [
439
+ /* @__PURE__ */ jsx3("h2", { className: "text-sm font-medium text-muted-foreground uppercase tracking-wider mb-4", children: groupLabel }),
440
+ /* @__PURE__ */ jsx3("div", { className: TILE_GRID, children: entries.map((item) => /* @__PURE__ */ jsx3(
299
441
  PlaygroundTile,
300
442
  {
301
443
  item,
@@ -303,7 +445,7 @@ function PlaygroundOverview({
303
445
  },
304
446
  item.id
305
447
  )) })
306
- ] }, groupLabel)) : /* @__PURE__ */ jsx("div", { className: TILE_GRID, children: registry.getAll().map((item) => /* @__PURE__ */ jsx(
448
+ ] }, groupLabel)) : /* @__PURE__ */ jsx3("div", { className: TILE_GRID, children: registry.getAll().map((item) => /* @__PURE__ */ jsx3(
307
449
  PlaygroundTile,
308
450
  {
309
451
  item,
@@ -315,15 +457,14 @@ function PlaygroundOverview({
315
457
  }
316
458
 
317
459
  // src/createPlaygroundModule.tsx
318
- import { jsx as jsx2 } from "react/jsx-runtime";
460
+ import { jsx as jsx4 } from "react/jsx-runtime";
319
461
  function buildNavigation(registry, basePath) {
320
462
  const groups = registry.getGrouped();
321
463
  const navGroups = [];
322
- const overviewGroup = {
464
+ navGroups.push({
323
465
  id: "playground-overview",
324
466
  links: [{ label: "Overview", path: basePath }]
325
- };
326
- navGroups.push(overviewGroup);
467
+ });
327
468
  for (const [groupLabel, entries] of groups) {
328
469
  navGroups.push({
329
470
  id: `playground-${groupLabel.toLowerCase().replace(/\s+/g, "-")}`,
@@ -337,7 +478,10 @@ function buildNavigation(registry, basePath) {
337
478
  return navGroups;
338
479
  }
339
480
  function suspended(Component) {
340
- return /* @__PURE__ */ jsx2(Suspense, { children: /* @__PURE__ */ jsx2(Component, {}) });
481
+ return /* @__PURE__ */ jsx4(Suspense, { children: /* @__PURE__ */ jsx4(Component, {}) });
482
+ }
483
+ function PlaygroundLayout() {
484
+ return /* @__PURE__ */ jsx4(PlaygroundSettingsProvider, { children: /* @__PURE__ */ jsx4(Outlet, {}) });
341
485
  }
342
486
  function createPlaygroundModule(registry, options = {}) {
343
487
  const {
@@ -352,21 +496,27 @@ function createPlaygroundModule(registry, options = {}) {
352
496
  const routes = [
353
497
  {
354
498
  path: routeBase,
355
- element: suspended(() => /* @__PURE__ */ jsx2(
356
- PlaygroundOverview,
499
+ element: /* @__PURE__ */ jsx4(PlaygroundLayout, {}),
500
+ children: [
357
501
  {
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
- }))
502
+ index: true,
503
+ element: suspended(() => /* @__PURE__ */ jsx4(
504
+ PlaygroundOverview,
505
+ {
506
+ registry,
507
+ basePath,
508
+ title: overviewTitle,
509
+ subtitle: overviewSubtitle,
510
+ grouped
511
+ }
512
+ ))
513
+ },
514
+ ...registry.getAll().map((entry) => ({
515
+ path: entry.path,
516
+ element: suspended(entry.component)
517
+ }))
518
+ ]
519
+ }
370
520
  ];
371
521
  return {
372
522
  id: "playground",
@@ -389,8 +539,11 @@ export {
389
539
  PlaygroundOverview,
390
540
  PlaygroundRegistry,
391
541
  PlaygroundSection,
542
+ PlaygroundSettingsPanel,
543
+ PlaygroundSettingsProvider,
392
544
  builtinEntries,
393
545
  createPlaygroundModule,
394
- createPlaygroundRegistry
546
+ createPlaygroundRegistry,
547
+ usePlaygroundSettings
395
548
  };
396
549
  //# sourceMappingURL=index.js.map