@flanksource/clicky-ui 0.3.5 → 0.3.7
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.
- package/README.md +42 -0
- package/dist/ai.cjs +15 -0
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.js +15 -0
- package/dist/ai.js.map +1 -1
- package/dist/components/DateField.d.ts +1 -1
- package/dist/components/DatePicker.d.ts +1 -1
- package/dist/components/DateTimePicker.d.ts +1 -1
- package/dist/components/FormLookupProvider.cjs +12 -0
- package/dist/components/FormLookupProvider.cjs.map +1 -0
- package/dist/components/FormLookupProvider.d.ts +7 -0
- package/dist/components/FormLookupProvider.d.ts.map +1 -0
- package/dist/components/FormLookupProvider.js +12 -0
- package/dist/components/FormLookupProvider.js.map +1 -0
- package/dist/components/JsonSchemaForm.cjs +2 -2
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.js +1 -1
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/ListMenu.cjs +145 -0
- package/dist/components/ListMenu.cjs.map +1 -0
- package/dist/components/ListMenu.d.ts +54 -0
- package/dist/components/ListMenu.d.ts.map +1 -0
- package/dist/components/ListMenu.js +145 -0
- package/dist/components/ListMenu.js.map +1 -0
- package/dist/components/MdxEditorField.cjs +128 -0
- package/dist/components/MdxEditorField.cjs.map +1 -0
- package/dist/components/MdxEditorField.d.ts +4 -0
- package/dist/components/MdxEditorField.d.ts.map +1 -0
- package/dist/components/MdxEditorField.js +106 -0
- package/dist/components/MdxEditorField.js.map +1 -0
- package/dist/components/MdxEditorToolbar.cjs +76 -0
- package/dist/components/MdxEditorToolbar.cjs.map +1 -0
- package/dist/components/MdxEditorToolbar.d.ts +8 -0
- package/dist/components/MdxEditorToolbar.d.ts.map +1 -0
- package/dist/components/MdxEditorToolbar.js +76 -0
- package/dist/components/MdxEditorToolbar.js.map +1 -0
- package/dist/components/button-variants.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/form-lookup-context.cjs +1 -8
- package/dist/components/form-lookup-context.cjs.map +1 -1
- package/dist/components/form-lookup-context.d.ts +1 -5
- package/dist/components/form-lookup-context.d.ts.map +1 -1
- package/dist/components/form-lookup-context.js +1 -8
- package/dist/components/form-lookup-context.js.map +1 -1
- package/dist/components/jotai-bindings-core.cjs +197 -0
- package/dist/components/jotai-bindings-core.cjs.map +1 -0
- package/dist/components/jotai-bindings-core.d.ts +45 -0
- package/dist/components/jotai-bindings-core.d.ts.map +1 -0
- package/dist/components/jotai-bindings-core.js +197 -0
- package/dist/components/jotai-bindings-core.js.map +1 -0
- package/dist/components/jotai-bindings.cjs +17 -0
- package/dist/components/jotai-bindings.cjs.map +1 -0
- package/dist/components/jotai-bindings.d.ts +4 -0
- package/dist/components/jotai-bindings.d.ts.map +1 -0
- package/dist/components/jotai-bindings.js +17 -0
- package/dist/components/jotai-bindings.js.map +1 -0
- package/dist/components/json-schema-form-fields.cjs +37 -0
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts +6 -0
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +38 -1
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-render.cjs +3 -1
- package/dist/components/json-schema-form-render.cjs.map +1 -1
- package/dist/components/json-schema-form-render.d.ts.map +1 -1
- package/dist/components/json-schema-form-render.js +4 -2
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +9 -0
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
- package/dist/components/json-schema-form-resolve.js +9 -0
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components/json-schema-form-types.d.ts +4 -1
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components/mdx-editor-field-plugins.cjs +124 -0
- package/dist/components/mdx-editor-field-plugins.cjs.map +1 -0
- package/dist/components/mdx-editor-field-plugins.d.ts +6 -0
- package/dist/components/mdx-editor-field-plugins.d.ts.map +1 -0
- package/dist/components/mdx-editor-field-plugins.js +124 -0
- package/dist/components/mdx-editor-field-plugins.js.map +1 -0
- package/dist/components/mdx-editor-options.d.ts +77 -0
- package/dist/components/mdx-editor-options.d.ts.map +1 -0
- package/dist/components/use-list-menu-selection.cjs +77 -0
- package/dist/components/use-list-menu-selection.cjs.map +1 -0
- package/dist/components/use-list-menu-selection.d.ts +40 -0
- package/dist/components/use-list-menu-selection.d.ts.map +1 -0
- package/dist/components/use-list-menu-selection.js +77 -0
- package/dist/components/use-list-menu-selection.js.map +1 -0
- package/dist/components.cjs +10 -1
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +4 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +10 -1
- package/dist/components.js.map +1 -1
- package/dist/data/MarkdownEditor.model.d.ts +1 -1
- package/dist/data/ProgressBars.cjs +194 -0
- package/dist/data/ProgressBars.cjs.map +1 -0
- package/dist/data/ProgressBars.d.ts +85 -0
- package/dist/data/ProgressBars.d.ts.map +1 -0
- package/dist/data/ProgressBars.js +194 -0
- package/dist/data/ProgressBars.js.map +1 -0
- package/dist/data/ProgressBars.model.cjs +27 -0
- package/dist/data/ProgressBars.model.cjs.map +1 -0
- package/dist/data/ProgressBars.model.d.ts +20 -0
- package/dist/data/ProgressBars.model.d.ts.map +1 -0
- package/dist/data/ProgressBars.model.js +27 -0
- package/dist/data/ProgressBars.model.js.map +1 -0
- package/dist/data/PromptBanner.cjs +199 -0
- package/dist/data/PromptBanner.cjs.map +1 -0
- package/dist/data/PromptBanner.d.ts +17 -0
- package/dist/data/PromptBanner.d.ts.map +1 -0
- package/dist/data/PromptBanner.js +199 -0
- package/dist/data/PromptBanner.js.map +1 -0
- package/dist/data/PromptBanner.model.cjs +132 -0
- package/dist/data/PromptBanner.model.cjs.map +1 -0
- package/dist/data/PromptBanner.model.d.ts +23 -0
- package/dist/data/PromptBanner.model.d.ts.map +1 -0
- package/dist/data/PromptBanner.model.js +132 -0
- package/dist/data/PromptBanner.model.js.map +1 -0
- package/dist/data/PromptDialog.cjs +43 -0
- package/dist/data/PromptDialog.cjs.map +1 -0
- package/dist/data/PromptDialog.d.ts +14 -0
- package/dist/data/PromptDialog.d.ts.map +1 -0
- package/dist/data/PromptDialog.js +43 -0
- package/dist/data/PromptDialog.js.map +1 -0
- package/dist/data/TaskManager.cjs +8 -1
- package/dist/data/TaskManager.cjs.map +1 -1
- package/dist/data/TaskManager.d.ts.map +1 -1
- package/dist/data/TaskManager.js +8 -1
- package/dist/data/TaskManager.js.map +1 -1
- package/dist/data/TaskProgress.cjs +15 -2
- package/dist/data/TaskProgress.cjs.map +1 -1
- package/dist/data/TaskProgress.d.ts +0 -10
- package/dist/data/TaskProgress.d.ts.map +1 -1
- package/dist/data/TaskProgress.js +15 -2
- package/dist/data/TaskProgress.js.map +1 -1
- package/dist/data/TimeseriesCoreBars.cjs +19 -173
- package/dist/data/TimeseriesCoreBars.cjs.map +1 -1
- package/dist/data/TimeseriesCoreBars.d.ts +9 -26
- package/dist/data/TimeseriesCoreBars.d.ts.map +1 -1
- package/dist/data/TimeseriesCoreBars.js +20 -174
- package/dist/data/TimeseriesCoreBars.js.map +1 -1
- package/dist/data/WorkloadCard.model.cjs.map +1 -1
- package/dist/data/WorkloadCard.model.d.ts +2 -2
- package/dist/data/WorkloadCard.model.d.ts.map +1 -1
- package/dist/data/WorkloadCard.model.js.map +1 -1
- package/dist/data/ai/ChatWindow.cjs +53 -9
- package/dist/data/ai/ChatWindow.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.js +53 -9
- package/dist/data/ai/ChatWindow.js.map +1 -1
- package/dist/data/ai/SessionViewer.cjs +275 -0
- package/dist/data/ai/SessionViewer.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.d.ts +33 -0
- package/dist/data/ai/SessionViewer.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.fixtures.d.ts +4 -0
- package/dist/data/ai/SessionViewer.fixtures.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.js +275 -0
- package/dist/data/ai/SessionViewer.js.map +1 -0
- package/dist/data/ai/SessionViewer.model.cjs +275 -0
- package/dist/data/ai/SessionViewer.model.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.model.d.ts +87 -0
- package/dist/data/ai/SessionViewer.model.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.model.js +275 -0
- package/dist/data/ai/SessionViewer.model.js.map +1 -0
- package/dist/data/ai/SessionViewerMenu.cjs +190 -0
- package/dist/data/ai/SessionViewerMenu.cjs.map +1 -0
- package/dist/data/ai/SessionViewerMenu.d.ts +24 -0
- package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -0
- package/dist/data/ai/SessionViewerMenu.js +190 -0
- package/dist/data/ai/SessionViewerMenu.js.map +1 -0
- package/dist/data/ai/ToolPreferences.cjs +232 -39
- package/dist/data/ai/ToolPreferences.cjs.map +1 -1
- package/dist/data/ai/ToolPreferences.d.ts +4 -7
- package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
- package/dist/data/ai/ToolPreferences.js +234 -41
- package/dist/data/ai/ToolPreferences.js.map +1 -1
- package/dist/data/ai/index.d.ts +3 -0
- package/dist/data/ai/index.d.ts.map +1 -1
- package/dist/data/ai/session-categories.cjs +219 -0
- package/dist/data/ai/session-categories.cjs.map +1 -0
- package/dist/data/ai/session-categories.d.ts +36 -0
- package/dist/data/ai/session-categories.d.ts.map +1 -0
- package/dist/data/ai/session-categories.js +219 -0
- package/dist/data/ai/session-categories.js.map +1 -0
- package/dist/data/chat/clickyOperationsToTools.cjs +89 -3
- package/dist/data/chat/clickyOperationsToTools.cjs.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.d.ts +1 -1
- package/dist/data/chat/clickyOperationsToTools.d.ts.map +1 -1
- package/dist/data/chat/clickyOperationsToTools.js +89 -3
- package/dist/data/chat/clickyOperationsToTools.js.map +1 -1
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +7 -1
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/task-status.cjs +19 -12
- package/dist/data/task-status.cjs.map +1 -1
- package/dist/data/task-status.d.ts +2 -1
- package/dist/data/task-status.d.ts.map +1 -1
- package/dist/data/task-status.js +19 -12
- package/dist/data/task-status.js.map +1 -1
- package/dist/data/test-runner/TestRunner.fixtures.d.ts +11 -4
- package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.cjs.map +1 -1
- package/dist/data/version-info.js +3 -3
- package/dist/data/version-info.js.map +1 -1
- package/dist/data.cjs +11 -2
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +6 -2
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +11 -2
- package/dist/data.js.map +1 -1
- package/dist/hooks/use-prompts.cjs +83 -0
- package/dist/hooks/use-prompts.cjs.map +1 -0
- package/dist/hooks/use-prompts.d.ts +43 -0
- package/dist/hooks/use-prompts.d.ts.map +1 -0
- package/dist/hooks/use-prompts.js +83 -0
- package/dist/hooks/use-prompts.js.map +1 -0
- package/dist/hooks.cjs +3 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +3 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +21 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/jotai.cjs +9 -0
- package/dist/jotai.cjs.map +1 -0
- package/dist/jotai.d.ts +4 -0
- package/dist/jotai.d.ts.map +1 -0
- package/dist/jotai.js +9 -0
- package/dist/jotai.js.map +1 -0
- package/dist/lib/utils.cjs +18 -1
- package/dist/lib/utils.cjs.map +1 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +18 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/mdx-editor.cjs +5 -0
- package/dist/mdx-editor.cjs.map +1 -0
- package/dist/mdx-editor.css +2 -0
- package/dist/mdx-editor.d.ts +2 -0
- package/dist/mdx-editor.d.ts.map +1 -0
- package/dist/mdx-editor.js +5 -0
- package/dist/mdx-editor.js.map +1 -0
- package/dist/rpc/apiClient.cjs +1 -1
- package/dist/rpc/apiClient.cjs.map +1 -1
- package/dist/rpc/apiClient.js +1 -1
- package/dist/rpc/apiClient.js.map +1 -1
- package/dist/rpc/surfaceIconMap.cjs +12 -1
- package/dist/rpc/surfaceIconMap.cjs.map +1 -1
- package/dist/rpc/surfaceIconMap.d.ts.map +1 -1
- package/dist/rpc/surfaceIconMap.js +12 -1
- package/dist/rpc/surfaceIconMap.js.map +1 -1
- package/dist/rpc/types.cjs.map +1 -1
- package/dist/rpc/types.d.ts +1 -0
- package/dist/rpc/types.d.ts.map +1 -1
- package/dist/rpc/types.js.map +1 -1
- package/dist/styles.css +1 -1
- package/oxlint-plugins/README.md +148 -0
- package/oxlint-plugins/clicky-ui-no-adhoc-overlay.js +88 -0
- package/oxlint-plugins/clicky-ui-prefer-components.js +46 -0
- package/oxlint-plugins/clicky-ui-prefer-icons.js +121 -0
- package/oxlint-plugins/clicky-ui-prefer-tailwind.js +98 -0
- package/oxlint-plugins/clicky-ui-prefer-theme.js +134 -0
- package/oxlint-plugins/clicky-ui-shared.js +132 -0
- package/oxlint-plugins/clicky-ui.js +34 -0
- package/oxlint-plugins/no-iconify-names.js +37 -0
- package/package.json +21 -1
- package/dist/data/TimeseriesCoreBars.model.cjs +0 -27
- package/dist/data/TimeseriesCoreBars.model.cjs.map +0 -1
- package/dist/data/TimeseriesCoreBars.model.d.ts +0 -20
- package/dist/data/TimeseriesCoreBars.model.d.ts.map +0 -1
- package/dist/data/TimeseriesCoreBars.model.js +0 -27
- package/dist/data/TimeseriesCoreBars.model.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-fields.js","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { LabelIcon, type LabelIconSpec } from \"../data/Icon\";\nimport { formatDateTimeRelative } from \"../data/cells/timestamp-format\";\nimport { Combobox } from \"./Combobox\";\nimport { DateTimePicker } from \"./DateTimePicker\";\nimport { GridControl } from \"./json-schema-form-grid\";\nimport { resolveLookupScope, useLookupFetcher } from \"./form-lookup-context\";\nimport type { FieldControl, FieldOption, FormLayout } from \"./json-schema-form-types\";\nimport {\n defaultPlaceholder,\n inputClass,\n toText,\n withSyntheticValue,\n} from \"./json-schema-form-utils\";\nimport {\n controlHeightClass,\n controlMinHeightClass,\n fieldInnerGapClass,\n inlineRowGapClass,\n labelSizeClass,\n stackedRowGapClass,\n type FormSize,\n} from \"./json-schema-form-size\";\n\n// FieldsGrid is the container every group of field rows renders into — the\n// top-level form and each nested object/map. In inline mode it owns the single\n// 2-column track definition: `fit-content(labelMaxWidth)` for the label column,\n// `minmax(0, valueMaxWidth)` for the value column. Every field row is a\n// `subgrid` that inherits these tracks, so all labels share one column width and\n// every value lines up — a real form grid, not per-row independent grids.\n// (`fit-content()` is the only valid CSS for \"size to content, clamped to a max\"\n// — `min(w, max-content)` is rejected by the browser, which silently drops the\n// whole declaration and collapses every row to a stacked-looking column. The\n// template is an inline style because Tailwind can't interpolate runtime widths.)\n// Stacked mode is a plain single-column grid.\nexport function FieldsGrid({ layout, size, children }: { layout: FormLayout; size: FormSize; children: ReactNode }) {\n if (layout.mode === \"inline\") {\n const labelMaxWidth = layout.labelMaxWidth ?? \"40ch\";\n const valueMaxWidth = layout.valueMaxWidth ?? \"600px\";\n return (\n <div\n className={cn(\"grid\", inlineRowGapClass[size])}\n style={{ gridTemplateColumns: `fit-content(${labelMaxWidth}) minmax(0, ${valueMaxWidth})` }}\n >\n {children}\n </div>\n );\n }\n return <div className={cn(\"grid\", stackedRowGapClass[size])}>{children}</div>;\n}\n\n// FieldWrapper lays out a single label + value (+ helper/error). In inline mode\n// it is a `subgrid` row spanning the parent FieldsGrid's two columns, so its\n// label and value snap to the shared label/value tracks (helper/error sit under\n// the value column). In stacked mode the label sits tight above its control as\n// one unit, capped at valueMaxWidth so controls don't stretch edge to edge.\nexport function FieldWrapper({\n label,\n value,\n helper,\n error,\n layout,\n size,\n}: {\n label: ReactNode;\n value: ReactNode;\n helper?: ReactNode;\n error?: ReactNode;\n layout: FormLayout;\n size: FormSize;\n}) {\n if (layout.mode === \"inline\") {\n return (\n <div className=\"col-span-2 grid grid-cols-subgrid items-start gap-x-3 gap-y-0.5\">\n <div className={cn(\"flex min-w-0 items-center\", controlMinHeightClass[size])}>{label}</div>\n <div className=\"min-w-0\">{value}</div>\n {helper && <p className=\"col-start-2 text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"col-start-2 text-xs text-destructive\">{error}</p>}\n </div>\n );\n }\n return (\n <div\n className=\"flex w-full flex-col gap-1\"\n style={{ maxWidth: layout.valueMaxWidth ?? \"600px\" }}\n >\n {label}\n {value}\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\nexport function FieldLabel({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n return (\n <label htmlFor={fieldId} className={cn(\"flex min-w-0 items-center gap-2 font-medium\", labelSizeClass[size])}>\n <LabelIcon icon={field.labelIcon} className=\"shrink-0 text-[15px] text-muted-foreground\" />\n <span className=\"truncate\" title={field.label !== field.key ? field.key : undefined}>\n {field.label}\n </span>\n {field.required && <span className=\"shrink-0 text-destructive\">*</span>}\n {field.badge && (\n <span className=\"shrink-0 rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {field.badge}\n </span>\n )}\n </label>\n );\n}\n\n// ObjectSection renders a nested object as a labelled section: a header row\n// (the field label + required/badge) above its fields, which fill the full\n// width below. It replaces the inline label + bordered box so nested objects\n// read as flat, headed groups rather than indented sub-forms. `col-span-full`\n// makes it span both tracks of an inline FieldsGrid (full width, not crammed\n// into the value column); in a stacked single-column grid it is a no-op.\nexport function ObjectSection({\n label,\n required,\n size,\n badge,\n helper,\n labelIcon,\n children,\n}: {\n label: string;\n required: boolean;\n size: FormSize;\n badge?: string;\n helper?: string;\n labelIcon?: LabelIconSpec;\n children: ReactNode;\n}) {\n return (\n <div className={cn(\"col-span-full flex flex-col\", fieldInnerGapClass[size])}>\n <div className={cn(\"flex items-center gap-2 border-b border-border pb-1 font-semibold\", labelSizeClass[size])}>\n <LabelIcon icon={labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{label}</span>\n {required && <span className=\"text-destructive\">*</span>}\n {badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {children}\n </div>\n );\n}\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nexport function ReadOnlyValue({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const display = field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\n// FieldAdornmentWrapper positions a field's leading/trailing in-field adornments\n// (FieldControl.prefix at the left edge, FieldControl.suffix at the right). The\n// container is tagged data-jsf-control so an adornment can locate its sibling\n// input[data-jsf-input] (e.g. for caret-aware insertion). With neither adornment\n// it renders the input bare, so unadorned fields are byte-for-byte unchanged.\nfunction FieldAdornmentWrapper({\n prefix,\n suffix,\n children,\n}: {\n prefix?: ReactNode;\n suffix?: ReactNode;\n children: ReactNode;\n}) {\n if (!prefix && !suffix) return <>{children}</>;\n return (\n <div data-jsf-control className=\"relative\">\n {prefix && <div className=\"absolute inset-y-0 left-1.5 flex items-center\">{prefix}</div>}\n {children}\n {suffix && <div className=\"absolute inset-y-0 right-1.5 flex items-center\">{suffix}</div>}\n </div>\n );\n}\n\nexport function StringControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <input\n id={fieldId}\n type=\"text\"\n data-jsf-input\n className={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function NumberControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // type=\"text\" (not number) so non-numeric values a consumer permits — e.g.\n // template tokens — are not silently dropped by the browser.\n const coerce = field.coerceNumber !== false;\n // A static unit (e.g. \"%\") rides the right edge of the input as a display-only\n // suffix; a consumer-set `suffix` (e.g. an insert-snippet button) wins if both\n // are present (number insert triggers mount on the left as `prefix`).\n const suffix = field.suffix ?? (field.unit ? (\n <span className=\"pointer-events-none select-none text-muted-foreground\">{field.unit}</span>\n ) : undefined);\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={suffix}>\n <input\n id={fieldId}\n type=\"text\"\n inputMode=\"decimal\"\n data-jsf-input\n className={cn(inputClass(size), field.prefix && \"pl-8\", suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n // Coerce mid-typing ONLY when the parse round-trips to the same text\n // (e.g. \"100\", \"33.5\") — so an in-progress decimal like \"33.\" or a\n // trailing-zero \"33.30\" keeps its raw text instead of collapsing to a\n // number and stranding the caret. Non-numeric tokens fall through to\n // the raw string. Blur finalizes any still-uncoerced numeric text.\n if (coerce && raw.trim() !== \"\" && String(Number(raw)) === raw.trim()) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n onBlur={(e) => {\n const raw = e.target.value;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n }\n }}\n />\n </FieldAdornmentWrapper>\n );\n}\n\n// DateControl edits a `format: date`/`date-time` string. Read-only, it shows the\n// human-readable absolute + relative form (e.g. \"Apr 15, 2026, 12:00 PM (2h\n// ago)\"); editable, a DateTimePicker. The raw string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nexport function DateControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateTimePicker\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n inputClassName={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix ? \"pr-14\" : \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n prefix={field.prefix}\n suffix={field.suffix}\n />\n );\n}\n\nexport function BooleanControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className={cn(\"flex items-center\", controlHeightClass[size])}>\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n}\n\nexport function EnumControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"grid\") {\n return <GridControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n if (field.display === \"radio\") {\n return (\n <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} size={size} />\n );\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n prefix={field.prefix}\n suffix={field.suffix}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// LookupControl is the async entity-reference picker for an `x-clicky-lookup`\n// field. It wraps Combobox and fetches options lazily through the form's\n// LookupFetcher (from context): the head set loads when the menu opens and the\n// (debounced) typed query drives server-side search. Single-select keeps\n// allowCustomValue on so a value outside the option set still commits (e.g. an\n// inline DSN). When no fetcher is wired it degrades to a free-text combobox.\nexport function LookupControl({\n field,\n fieldId,\n readOnly,\n size,\n rootValue,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n rootValue?: Record<string, unknown>;\n}) {\n const fetcher = useLookupFetcher();\n const descriptor = field.lookup;\n const value = toText(field.value);\n const [options, setOptions] = useState<FieldOption[]>([]);\n const [loading, setLoading] = useState(false);\n\n // rootValue is read through a ref so onSearch stays referentially stable: a new\n // onSearch each render would retrigger Combobox's search effect on every\n // setOptions, looping. The scopeKey effect below re-fetches when scope changes.\n const rootRef = useRef(rootValue);\n rootRef.current = rootValue;\n\n const onSearch = useCallback(\n (query: string) => {\n if (!descriptor || !fetcher) return;\n setLoading(true);\n const root = rootRef.current;\n fetcher({ descriptor, query, ...(root ? { rootValue: root } : {}) })\n .then((next) => setOptions(next))\n .catch(() => setOptions([]))\n .finally(() => setLoading(false));\n },\n [descriptor, fetcher],\n );\n\n // Re-fetch the head set when the scope (a sibling field, e.g. provider type)\n // changes so the out-of-scope set is replaced rather than shown stale.\n const scopeKey = descriptor ? JSON.stringify(resolveLookupScope(descriptor, rootValue)) : \"\";\n useEffect(() => {\n if (descriptor && fetcher) onSearch(\"\");\n else setOptions([]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scopeKey, onSearch]);\n\n if (!descriptor || !fetcher) {\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue([], value)}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n }\n\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue(options, value)}\n value={value}\n disabled={readOnly}\n size={size}\n loading={loading}\n allowCustomValue={field.allowCustomValue ?? false}\n onSearch={onSearch}\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n size: FormSize;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className=\"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\"\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1\",\n labelSizeClass[size],\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// TextareaControl edits a long-form string in a multi-line box. Read-only, it\n// shows the value with line breaks preserved; editable, a resizable <textarea>.\n// The raw string is committed unchanged so a consumer-permitted template token\n// survives.\nexport function TextareaControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"block whitespace-pre-wrap break-words text-foreground\", labelSizeClass[size])}\n title={text || undefined}\n >\n {text || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n }\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <textarea\n id={fieldId}\n data-jsf-input\n rows={4}\n className={cn(inputClass(size), \"h-auto min-h-[5rem] resize-y\", field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={text}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\n// DisplayControl renders a static, non-editable presentation element:\n// Label/Title (heading), Message (info text), Line (divider), or Blank/Filler\n// (spacer). It never collects a value; the heading/text source is the field's\n// title (label) and, for \"text\", its description. Rendered identically in the\n// form and the read-only Viewer.\nexport function DisplayControl({ field, size }: { field: FieldControl; size: FormSize }) {\n const variant = field.displayVariant ?? \"text\";\n if (variant === \"divider\") {\n return <hr data-jsf-input className=\"my-1 w-full border-t border-border\" />;\n }\n if (variant === \"spacer\") {\n return <div data-jsf-input aria-hidden className=\"h-2\" />;\n }\n if (variant === \"heading\") {\n return (\n <div\n data-jsf-input\n className={cn(\"border-b border-border pb-1 font-semibold text-foreground\", labelSizeClass[size])}\n >\n {field.label}\n </div>\n );\n }\n const text = field.description ?? toText(field.value) ?? field.label;\n return (\n <p data-jsf-input className={cn(\"text-muted-foreground\", labelSizeClass[size])}>\n {text || field.label}\n </p>\n );\n}\n\n// LinkControl renders a read-only external hyperlink. The\n// href is field.href, falling back to the value when it is an absolute URL; with\n// neither it degrades to a plain read-only value.\nexport function LinkControl({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const href = field.href ?? (/^https?:\\/\\//i.test(text) ? text : undefined);\n if (!href) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={size} />;\n }\n return (\n <a\n id={fieldId}\n data-jsf-input\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className={cn(\"inline-flex items-center text-primary underline underline-offset-2\", controlHeightClass[size], labelSizeClass[size])}\n >\n {text || field.label || href}\n </a>\n );\n}\n\n// HMR probe\n// HMR probe 2\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-fields.js","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { LabelIcon, type LabelIconSpec } from \"../data/Icon\";\nimport { formatDateTimeRelative } from \"../data/cells/timestamp-format\";\nimport { Combobox } from \"./Combobox\";\nimport { DateTimePicker } from \"./DateTimePicker\";\nimport { GridControl } from \"./json-schema-form-grid\";\nimport { resolveLookupScope, useLookupFetcher } from \"./form-lookup-context\";\nimport type { FieldControl, FieldOption, FormLayout } from \"./json-schema-form-types\";\nimport {\n defaultPlaceholder,\n inputClass,\n toText,\n withSyntheticValue,\n} from \"./json-schema-form-utils\";\nimport {\n controlHeightClass,\n controlMinHeightClass,\n fieldInnerGapClass,\n inlineRowGapClass,\n labelSizeClass,\n stackedRowGapClass,\n type FormSize,\n} from \"./json-schema-form-size\";\n\nconst LazyMdxEditorField = lazy(async () => {\n const mod = await import(\"./MdxEditorField\");\n return { default: mod.MdxEditorField };\n});\n\n// FieldsGrid is the container every group of field rows renders into — the\n// top-level form and each nested object/map. In inline mode it owns the single\n// 2-column track definition: `fit-content(labelMaxWidth)` for the label column,\n// `minmax(0, valueMaxWidth)` for the value column. Every field row is a\n// `subgrid` that inherits these tracks, so all labels share one column width and\n// every value lines up — a real form grid, not per-row independent grids.\n// (`fit-content()` is the only valid CSS for \"size to content, clamped to a max\"\n// — `min(w, max-content)` is rejected by the browser, which silently drops the\n// whole declaration and collapses every row to a stacked-looking column. The\n// template is an inline style because Tailwind can't interpolate runtime widths.)\n// Stacked mode is a plain single-column grid.\nexport function FieldsGrid({ layout, size, children }: { layout: FormLayout; size: FormSize; children: ReactNode }) {\n if (layout.mode === \"inline\") {\n const labelMaxWidth = layout.labelMaxWidth ?? \"40ch\";\n const valueMaxWidth = layout.valueMaxWidth ?? \"600px\";\n return (\n <div\n className={cn(\"grid\", inlineRowGapClass[size])}\n style={{ gridTemplateColumns: `fit-content(${labelMaxWidth}) minmax(0, ${valueMaxWidth})` }}\n >\n {children}\n </div>\n );\n }\n return <div className={cn(\"grid\", stackedRowGapClass[size])}>{children}</div>;\n}\n\n// FieldWrapper lays out a single label + value (+ helper/error). In inline mode\n// it is a `subgrid` row spanning the parent FieldsGrid's two columns, so its\n// label and value snap to the shared label/value tracks (helper/error sit under\n// the value column). In stacked mode the label sits tight above its control as\n// one unit, capped at valueMaxWidth so controls don't stretch edge to edge.\nexport function FieldWrapper({\n label,\n value,\n helper,\n error,\n layout,\n size,\n}: {\n label: ReactNode;\n value: ReactNode;\n helper?: ReactNode;\n error?: ReactNode;\n layout: FormLayout;\n size: FormSize;\n}) {\n if (layout.mode === \"inline\") {\n return (\n <div className=\"col-span-2 grid grid-cols-subgrid items-start gap-x-3 gap-y-0.5\">\n <div className={cn(\"flex min-w-0 items-center\", controlMinHeightClass[size])}>{label}</div>\n <div className=\"min-w-0\">{value}</div>\n {helper && <p className=\"col-start-2 text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"col-start-2 text-xs text-destructive\">{error}</p>}\n </div>\n );\n }\n return (\n <div\n className=\"flex w-full flex-col gap-1\"\n style={{ maxWidth: layout.valueMaxWidth ?? \"600px\" }}\n >\n {label}\n {value}\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\nexport function FieldLabel({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n return (\n <label htmlFor={fieldId} className={cn(\"flex min-w-0 items-center gap-2 font-medium\", labelSizeClass[size])}>\n <LabelIcon icon={field.labelIcon} className=\"shrink-0 text-[15px] text-muted-foreground\" />\n <span className=\"truncate\" title={field.label !== field.key ? field.key : undefined}>\n {field.label}\n </span>\n {field.required && <span className=\"shrink-0 text-destructive\">*</span>}\n {field.badge && (\n <span className=\"shrink-0 rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {field.badge}\n </span>\n )}\n </label>\n );\n}\n\n// ObjectSection renders a nested object as a labelled section: a header row\n// (the field label + required/badge) above its fields, which fill the full\n// width below. It replaces the inline label + bordered box so nested objects\n// read as flat, headed groups rather than indented sub-forms. `col-span-full`\n// makes it span both tracks of an inline FieldsGrid (full width, not crammed\n// into the value column); in a stacked single-column grid it is a no-op.\nexport function ObjectSection({\n label,\n required,\n size,\n badge,\n helper,\n labelIcon,\n children,\n}: {\n label: string;\n required: boolean;\n size: FormSize;\n badge?: string;\n helper?: string;\n labelIcon?: LabelIconSpec;\n children: ReactNode;\n}) {\n return (\n <div className={cn(\"col-span-full flex flex-col\", fieldInnerGapClass[size])}>\n <div className={cn(\"flex items-center gap-2 border-b border-border pb-1 font-semibold\", labelSizeClass[size])}>\n <LabelIcon icon={labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{label}</span>\n {required && <span className=\"text-destructive\">*</span>}\n {badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {children}\n </div>\n );\n}\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nexport function ReadOnlyValue({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const display = field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\n// FieldAdornmentWrapper positions a field's leading/trailing in-field adornments\n// (FieldControl.prefix at the left edge, FieldControl.suffix at the right). The\n// container is tagged data-jsf-control so an adornment can locate its sibling\n// input[data-jsf-input] (e.g. for caret-aware insertion). With neither adornment\n// it renders the input bare, so unadorned fields are byte-for-byte unchanged.\nfunction FieldAdornmentWrapper({\n prefix,\n suffix,\n children,\n}: {\n prefix?: ReactNode;\n suffix?: ReactNode;\n children: ReactNode;\n}) {\n if (!prefix && !suffix) return <>{children}</>;\n return (\n <div data-jsf-control className=\"relative\">\n {prefix && <div className=\"absolute inset-y-0 left-1.5 flex items-center\">{prefix}</div>}\n {children}\n {suffix && <div className=\"absolute inset-y-0 right-1.5 flex items-center\">{suffix}</div>}\n </div>\n );\n}\n\nexport function StringControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <input\n id={fieldId}\n type=\"text\"\n data-jsf-input\n className={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function NumberControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // type=\"text\" (not number) so non-numeric values a consumer permits — e.g.\n // template tokens — are not silently dropped by the browser.\n const coerce = field.coerceNumber !== false;\n // A static unit (e.g. \"%\") rides the right edge of the input as a display-only\n // suffix; a consumer-set `suffix` (e.g. an insert-snippet button) wins if both\n // are present (number insert triggers mount on the left as `prefix`).\n const suffix = field.suffix ?? (field.unit ? (\n <span className=\"pointer-events-none select-none text-muted-foreground\">{field.unit}</span>\n ) : undefined);\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={suffix}>\n <input\n id={fieldId}\n type=\"text\"\n inputMode=\"decimal\"\n data-jsf-input\n className={cn(inputClass(size), field.prefix && \"pl-8\", suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n // Coerce mid-typing ONLY when the parse round-trips to the same text\n // (e.g. \"100\", \"33.5\") — so an in-progress decimal like \"33.\" or a\n // trailing-zero \"33.30\" keeps its raw text instead of collapsing to a\n // number and stranding the caret. Non-numeric tokens fall through to\n // the raw string. Blur finalizes any still-uncoerced numeric text.\n if (coerce && raw.trim() !== \"\" && String(Number(raw)) === raw.trim()) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n onBlur={(e) => {\n const raw = e.target.value;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n }\n }}\n />\n </FieldAdornmentWrapper>\n );\n}\n\n// DateControl edits a `format: date`/`date-time` string. Read-only, it shows the\n// human-readable absolute + relative form (e.g. \"Apr 15, 2026, 12:00 PM (2h\n// ago)\"); editable, a DateTimePicker. The raw string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nexport function DateControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateTimePicker\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n inputClassName={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix ? \"pr-14\" : \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n prefix={field.prefix}\n suffix={field.suffix}\n />\n );\n}\n\nexport function BooleanControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className={cn(\"flex items-center\", controlHeightClass[size])}>\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n}\n\nexport function EnumControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"grid\") {\n return <GridControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n if (field.display === \"radio\") {\n return (\n <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} size={size} />\n );\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n prefix={field.prefix}\n suffix={field.suffix}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// LookupControl is the async entity-reference picker for an `x-clicky-lookup`\n// field. It wraps Combobox and fetches options lazily through the form's\n// LookupFetcher (from context): the head set loads when the menu opens and the\n// (debounced) typed query drives server-side search. Single-select keeps\n// allowCustomValue on so a value outside the option set still commits (e.g. an\n// inline DSN). When no fetcher is wired it degrades to a free-text combobox.\nexport function LookupControl({\n field,\n fieldId,\n readOnly,\n size,\n rootValue,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n rootValue?: Record<string, unknown>;\n}) {\n const fetcher = useLookupFetcher();\n const descriptor = field.lookup;\n const value = toText(field.value);\n const [options, setOptions] = useState<FieldOption[]>([]);\n const [loading, setLoading] = useState(false);\n\n // rootValue is read through a ref so onSearch stays referentially stable: a new\n // onSearch each render would retrigger Combobox's search effect on every\n // setOptions, looping. The scopeKey effect below re-fetches when scope changes.\n const rootRef = useRef(rootValue);\n rootRef.current = rootValue;\n\n const onSearch = useCallback(\n (query: string) => {\n if (!descriptor || !fetcher) return;\n setLoading(true);\n const root = rootRef.current;\n fetcher({ descriptor, query, ...(root ? { rootValue: root } : {}) })\n .then((next) => setOptions(next))\n .catch(() => setOptions([]))\n .finally(() => setLoading(false));\n },\n [descriptor, fetcher],\n );\n\n // Re-fetch the head set when the scope (a sibling field, e.g. provider type)\n // changes so the out-of-scope set is replaced rather than shown stale.\n const scopeKey = descriptor ? JSON.stringify(resolveLookupScope(descriptor, rootValue)) : \"\";\n useEffect(() => {\n if (descriptor && fetcher) onSearch(\"\");\n else setOptions([]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scopeKey, onSearch]);\n\n if (!descriptor || !fetcher) {\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue([], value)}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n }\n\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue(options, value)}\n value={value}\n disabled={readOnly}\n size={size}\n loading={loading}\n allowCustomValue={field.allowCustomValue ?? false}\n onSearch={onSearch}\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n size: FormSize;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className=\"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\"\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1\",\n labelSizeClass[size],\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// TextareaControl edits a long-form string in a multi-line box. Read-only, it\n// shows the value with line breaks preserved; editable, a resizable <textarea>.\n// The raw string is committed unchanged so a consumer-permitted template token\n// survives.\nexport function TextareaControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"block whitespace-pre-wrap break-words text-foreground\", labelSizeClass[size])}\n title={text || undefined}\n >\n {text || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n }\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <textarea\n id={fieldId}\n data-jsf-input\n rows={4}\n className={cn(inputClass(size), \"h-auto min-h-[5rem] resize-y\", field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={text}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function MarkdownControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const fallback = (\n <textarea\n id={fieldId}\n data-jsf-input\n rows={6}\n className={cn(inputClass(size), \"h-auto resize-y font-mono\", field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n\n return (\n <Suspense fallback={fallback}>\n <LazyMdxEditorField\n id={fieldId}\n value={toText(field.value)}\n readOnly={readOnly}\n size={size}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(next) => field.onChange(next)}\n {...field.markdownOptions}\n />\n </Suspense>\n );\n}\n\n// DisplayControl renders a static, non-editable presentation element:\n// Label/Title (heading), Message (info text), Line (divider), or Blank/Filler\n// (spacer). It never collects a value; the heading/text source is the field's\n// title (label) and, for \"text\", its description. Rendered identically in the\n// form and the read-only Viewer.\nexport function DisplayControl({ field, size }: { field: FieldControl; size: FormSize }) {\n const variant = field.displayVariant ?? \"text\";\n if (variant === \"divider\") {\n return <hr data-jsf-input className=\"my-1 w-full border-t border-border\" />;\n }\n if (variant === \"spacer\") {\n return <div data-jsf-input aria-hidden className=\"h-2\" />;\n }\n if (variant === \"heading\") {\n return (\n <div\n data-jsf-input\n className={cn(\"border-b border-border pb-1 font-semibold text-foreground\", labelSizeClass[size])}\n >\n {field.label}\n </div>\n );\n }\n const text = field.description ?? toText(field.value) ?? field.label;\n return (\n <p data-jsf-input className={cn(\"text-muted-foreground\", labelSizeClass[size])}>\n {text || field.label}\n </p>\n );\n}\n\n// LinkControl renders a read-only external hyperlink. The\n// href is field.href, falling back to the value when it is an absolute URL; with\n// neither it degrades to a plain read-only value.\nexport function LinkControl({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const href = field.href ?? (/^https?:\\/\\//i.test(text) ? text : undefined);\n if (!href) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={size} />;\n }\n return (\n <a\n id={fieldId}\n data-jsf-input\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className={cn(\"inline-flex items-center text-primary underline underline-offset-2\", controlHeightClass[size], labelSizeClass[size])}\n >\n {text || field.label || href}\n </a>\n );\n}\n\n// HMR probe\n// HMR probe 2\n"],"names":[],"mappings":"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"}
|
|
@@ -39,6 +39,8 @@ function renderValueControl(field, ctx) {
|
|
|
39
39
|
return /* @__PURE__ */ jsxRuntime.jsx(jsonSchemaFormFields.DateControl, { field, fieldId, readOnly, size });
|
|
40
40
|
case "textarea":
|
|
41
41
|
return /* @__PURE__ */ jsxRuntime.jsx(jsonSchemaFormFields.TextareaControl, { field, fieldId, readOnly, size });
|
|
42
|
+
case "markdown":
|
|
43
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsonSchemaFormFields.MarkdownControl, { field, fieldId, readOnly, size });
|
|
42
44
|
case "display":
|
|
43
45
|
return /* @__PURE__ */ jsxRuntime.jsx(jsonSchemaFormFields.DisplayControl, { field, size });
|
|
44
46
|
case "link":
|
|
@@ -54,7 +56,7 @@ function renderValueControl(field, ctx) {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
function ownsReadOnlyRendering(kind) {
|
|
57
|
-
return kind === "array" || kind === "object" || kind === "string-map" || kind === "textarea" || kind === "display" || kind === "link";
|
|
59
|
+
return kind === "array" || kind === "object" || kind === "string-map" || kind === "textarea" || kind === "markdown" || kind === "display" || kind === "link";
|
|
58
60
|
}
|
|
59
61
|
function buildField(args, ctx) {
|
|
60
62
|
const base = jsonSchemaFormResolve.resolveControl(args);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-render.cjs","sources":["../../src/components/json-schema-form-render.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { LabelIcon } from \"../data/Icon\";\nimport {\n BooleanControl,\n DateControl,\n DisplayControl,\n EnumControl,\n FieldLabel,\n FieldWrapper,\n LinkControl,\n LookupControl,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\n TextareaControl,\n} from \"./json-schema-form-fields\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { ObjectControl, StringMapControl } from \"./json-schema-form-object\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldArgs,\n FieldControl,\n JsonSchemaObject,\n RenderApi,\n RenderContext,\n} from \"./json-schema-form-types\";\nimport {\n fieldInputId,\n orderByClickyOrder,\n orderByPriority,\n orderByXOrder,\n orderRequiredFirst,\n softError,\n} from \"./json-schema-form-utils\";\nimport { labelSizeClass } from \"./json-schema-form-size\";\n\n// This module is the top of the json-schema-form graph: it imports the control\n// components and dispatches into them, while container controls recurse back in\n// only through ctx.render (see RenderApi). Nothing here is a React component,\n// so the component modules stay Fast-Refresh-eligible and cycle-free.\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface, and textarea/display/link own their non-editable rendering\n // (multi-line text / static element / hyperlink), so all of these are excluded\n // from the plain ReadOnlyValue fallback.\n if (field.readOnly && !ownsReadOnlyRendering(field.kind)) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly || field.readOnly === true;\n const size = ctx.size;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"lookup\":\n return (\n <LookupControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n {...(ctx.rootValue ? { rootValue: ctx.rootValue } : {})}\n />\n );\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"textarea\":\n return <TextareaControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"display\":\n return <DisplayControl field={field} size={size} />;\n case \"link\":\n return <LinkControl field={field} fieldId={fieldId} size={size} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n}\n\n// ownsReadOnlyRendering reports whether a control renders its own non-editable\n// form, so the renderer must not pre-empt it with the plain ReadOnlyValue text:\n// containers recurse structurally, and textarea/display/link have bespoke\n// read-only output.\nfunction ownsReadOnlyRendering(kind: FieldControl[\"kind\"]): boolean {\n return (\n kind === \"array\" ||\n kind === \"object\" ||\n kind === \"string-map\" ||\n kind === \"textarea\" ||\n kind === \"display\" ||\n kind === \"link\"\n );\n}\n\n// buildField resolves a control, applies the pre-extensions (any returning\n// null drops the field), renders the value node, then applies the\n// post-extensions to the {label, value} node pair.\nfunction buildField(\n args: FieldArgs,\n ctx: RenderContext,\n): { field: FieldControl; label: ReactNode; value: ReactNode } | null {\n const base = resolveControl(args);\n let field: FieldControl | null = base;\n for (const ext of ctx.pre) {\n if (!field) break;\n field = ext(field, {\n key: args.key,\n prop: args.prop,\n value: args.value,\n ...(ctx.rootValue ? { rootValue: ctx.rootValue } : {}),\n });\n }\n if (!field) return null;\n // Drop read-only fields entirely when the form opts out of displaying them.\n // Checked after pre-extensions so an extension that sets/clears readOnly wins.\n if (ctx.hideReadOnlyFields && field.readOnly) return null;\n\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n let label: ReactNode = <FieldLabel field={field} fieldId={fieldId} size={ctx.size} />;\n // A field's `x-layout: inline|stack` overrides the form-level layout for its\n // own value subtree (the field's own row keeps the parent layout). \"table\" is\n // handled structurally inside the array/string-map controls, not here.\n const overrideMode =\n field.layout === \"inline\" ? \"inline\" : field.layout === \"stack\" ? \"stacked\" : undefined;\n const valueCtx: RenderContext = overrideMode\n ? { ...ctx, layout: { ...ctx.layout, mode: overrideMode } }\n : ctx;\n let value: ReactNode = renderValueControl(field, valueCtx);\n const postCtx = ctx.rootValue ? { rootValue: ctx.rootValue } : {};\n for (const ext of ctx.post) {\n const next = ext(field, { label, value }, postCtx);\n label = next.label;\n value = next.value;\n }\n return { field, label, value };\n}\n\n// renderFieldNodes runs the full pipeline and returns the raw {label, value}\n// nodes (no FieldWrapper). Used where the caller arranges layout itself — map\n// rows (value only) and scalar array items.\nexport function renderFieldNodes(\n args: FieldArgs,\n ctx: RenderContext,\n): { label: ReactNode; value: ReactNode } | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n return { label: built.label, value: built.value };\n}\n\n// renderFieldRow runs the pipeline and wraps it in a FieldWrapper with the soft\n// validation hint. `labelOverride` lets a container relabel a field that has no\n// natural key (e.g. array items → \"Item 1\").\nexport function renderFieldRow(\n args: FieldArgs,\n ctx: RenderContext,\n opts?: { labelOverride?: string },\n): ReactNode | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n const { field } = built;\n // Object fields — and table-laid-out arrays/string-maps — render as a flat\n // section: a header followed by their body at full width, rather than an\n // inline label + narrow value column. This keeps deep schemas (e.g. policy →\n // shape, asfile → params) readable as a single column of labelled sections,\n // and gives a `x-layout: \"table\"` array the full width its columns need\n // instead of cramming it into the inline value column.\n if (field.kind === \"object\" || field.layout === \"table\") {\n return (\n <ObjectSection\n label={opts?.labelOverride ?? field.label}\n required={field.required}\n size={ctx.size}\n {...(field.badge ? { badge: field.badge } : {})}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(field.labelIcon != null ? { labelIcon: field.labelIcon } : {})}\n >\n {built.value}\n </ObjectSection>\n );\n }\n // A display field (heading/divider/info/spacer) is the label — it carries no\n // value column, so it spans the full grid width with no inline label cell.\n if (field.kind === \"display\") {\n return <div className=\"col-span-full\">{built.value}</div>;\n }\n const label = opts?.labelOverride ? (\n <span className={cn(\"flex items-center gap-2 font-medium\", labelSizeClass[ctx.size])}>\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{opts.labelOverride}</span>\n {field.required && <span className=\"text-destructive\">*</span>}\n {field.badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {field.badge}\n </span>\n )}\n </span>\n ) : (\n built.label\n );\n const err = softError(field);\n return (\n <FieldWrapper\n layout={ctx.layout}\n size={ctx.size}\n label={label}\n value={built.value}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(err ? { error: err } : {})}\n />\n );\n}\n\n// renderObjectFields maps an object subschema's effective properties to field\n// rows. It is the recursive heart, shared by the top-level form and the nested\n// ObjectControl. Edits spread immutably onto the object.\nexport function renderObjectFields(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n onChange: (next: Record<string, unknown>) => void,\n ctx: RenderContext,\n opts?: { hiddenKeys?: string[] },\n): ReactNode[] {\n const { properties, required } = effectiveProperties(schema, value);\n const hidden = new Set(opts?.hiddenKeys ?? []);\n // Per-property `x-clicky-order` wins (composes across merged branches); the\n // object-level `x-order` array is the fallback; document order otherwise.\n const ordered = orderByClickyOrder(orderByXOrder(Object.entries(properties), schema[\"x-order\"]));\n const entries =\n ctx.sortMode === \"required-first\"\n ? orderRequiredFirst(ordered, required)\n : ctx.sortMode === \"priority\"\n ? orderByPriority(ordered, required, value)\n : ordered;\n return entries.flatMap(([key, prop]) => {\n if (hidden.has(key)) return [];\n const row = renderFieldRow(\n {\n key,\n prop,\n required: required.includes(key),\n value: value[key],\n onChange: (next) => onChange({ ...value, [key]: next }),\n },\n ctx,\n );\n // `contents` keeps the keyed wrapper out of the box tree so the row's own\n // node (a subgrid FieldWrapper or a full-width ObjectSection) is a direct\n // child of the FieldsGrid and snaps to its label/value tracks.\n return row ? [<div key={key} className=\"contents\">{row}</div>] : [];\n });\n}\n\n// renderApi is the RenderContext injection bundle: the root form stores it on\n// the context so container controls can recurse without importing this module.\nexport const renderApi: RenderApi = {\n renderFieldNodes,\n renderFieldRow,\n renderObjectFields,\n};\n"],"names":["fieldInputId","ReadOnlyValue","jsx","EnumControl","LookupControl","BooleanControl","NumberControl","DateControl","TextareaControl","DisplayControl","LinkControl","ArrayControl","ObjectControl","StringMapControl","StringControl","resolveControl","FieldLabel","ObjectSection","jsxs","cn","labelSizeClass","LabelIcon","softError","FieldWrapper","effectiveProperties","orderByClickyOrder","orderByXOrder","orderRequiredFirst","orderByPriority"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-render.cjs","sources":["../../src/components/json-schema-form-render.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { LabelIcon } from \"../data/Icon\";\nimport {\n BooleanControl,\n DateControl,\n DisplayControl,\n EnumControl,\n FieldLabel,\n FieldWrapper,\n LinkControl,\n LookupControl,\n MarkdownControl,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\n TextareaControl,\n} from \"./json-schema-form-fields\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { ObjectControl, StringMapControl } from \"./json-schema-form-object\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldArgs,\n FieldControl,\n JsonSchemaObject,\n RenderApi,\n RenderContext,\n} from \"./json-schema-form-types\";\nimport {\n fieldInputId,\n orderByClickyOrder,\n orderByPriority,\n orderByXOrder,\n orderRequiredFirst,\n softError,\n} from \"./json-schema-form-utils\";\nimport { labelSizeClass } from \"./json-schema-form-size\";\n\n// This module is the top of the json-schema-form graph: it imports the control\n// components and dispatches into them, while container controls recurse back in\n// only through ctx.render (see RenderApi). Nothing here is a React component,\n// so the component modules stay Fast-Refresh-eligible and cycle-free.\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface, and textarea/display/link own their non-editable rendering\n // (multi-line text / static element / hyperlink), so all of these are excluded\n // from the plain ReadOnlyValue fallback.\n if (field.readOnly && !ownsReadOnlyRendering(field.kind)) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly || field.readOnly === true;\n const size = ctx.size;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"lookup\":\n return (\n <LookupControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n {...(ctx.rootValue ? { rootValue: ctx.rootValue } : {})}\n />\n );\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"textarea\":\n return <TextareaControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"markdown\":\n return <MarkdownControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"display\":\n return <DisplayControl field={field} size={size} />;\n case \"link\":\n return <LinkControl field={field} fieldId={fieldId} size={size} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n}\n\n// ownsReadOnlyRendering reports whether a control renders its own non-editable\n// form, so the renderer must not pre-empt it with the plain ReadOnlyValue text:\n// containers recurse structurally, and textarea/display/link have bespoke\n// read-only output.\nfunction ownsReadOnlyRendering(kind: FieldControl[\"kind\"]): boolean {\n return (\n kind === \"array\" ||\n kind === \"object\" ||\n kind === \"string-map\" ||\n kind === \"textarea\" ||\n kind === \"markdown\" ||\n kind === \"display\" ||\n kind === \"link\"\n );\n}\n\n// buildField resolves a control, applies the pre-extensions (any returning\n// null drops the field), renders the value node, then applies the\n// post-extensions to the {label, value} node pair.\nfunction buildField(\n args: FieldArgs,\n ctx: RenderContext,\n): { field: FieldControl; label: ReactNode; value: ReactNode } | null {\n const base = resolveControl(args);\n let field: FieldControl | null = base;\n for (const ext of ctx.pre) {\n if (!field) break;\n field = ext(field, {\n key: args.key,\n prop: args.prop,\n value: args.value,\n ...(ctx.rootValue ? { rootValue: ctx.rootValue } : {}),\n });\n }\n if (!field) return null;\n // Drop read-only fields entirely when the form opts out of displaying them.\n // Checked after pre-extensions so an extension that sets/clears readOnly wins.\n if (ctx.hideReadOnlyFields && field.readOnly) return null;\n\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n let label: ReactNode = <FieldLabel field={field} fieldId={fieldId} size={ctx.size} />;\n // A field's `x-layout: inline|stack` overrides the form-level layout for its\n // own value subtree (the field's own row keeps the parent layout). \"table\" is\n // handled structurally inside the array/string-map controls, not here.\n const overrideMode =\n field.layout === \"inline\" ? \"inline\" : field.layout === \"stack\" ? \"stacked\" : undefined;\n const valueCtx: RenderContext = overrideMode\n ? { ...ctx, layout: { ...ctx.layout, mode: overrideMode } }\n : ctx;\n let value: ReactNode = renderValueControl(field, valueCtx);\n const postCtx = ctx.rootValue ? { rootValue: ctx.rootValue } : {};\n for (const ext of ctx.post) {\n const next = ext(field, { label, value }, postCtx);\n label = next.label;\n value = next.value;\n }\n return { field, label, value };\n}\n\n// renderFieldNodes runs the full pipeline and returns the raw {label, value}\n// nodes (no FieldWrapper). Used where the caller arranges layout itself — map\n// rows (value only) and scalar array items.\nexport function renderFieldNodes(\n args: FieldArgs,\n ctx: RenderContext,\n): { label: ReactNode; value: ReactNode } | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n return { label: built.label, value: built.value };\n}\n\n// renderFieldRow runs the pipeline and wraps it in a FieldWrapper with the soft\n// validation hint. `labelOverride` lets a container relabel a field that has no\n// natural key (e.g. array items → \"Item 1\").\nexport function renderFieldRow(\n args: FieldArgs,\n ctx: RenderContext,\n opts?: { labelOverride?: string },\n): ReactNode | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n const { field } = built;\n // Object fields — and table-laid-out arrays/string-maps — render as a flat\n // section: a header followed by their body at full width, rather than an\n // inline label + narrow value column. This keeps deep schemas (e.g. policy →\n // shape, asfile → params) readable as a single column of labelled sections,\n // and gives a `x-layout: \"table\"` array the full width its columns need\n // instead of cramming it into the inline value column.\n if (field.kind === \"object\" || field.layout === \"table\") {\n return (\n <ObjectSection\n label={opts?.labelOverride ?? field.label}\n required={field.required}\n size={ctx.size}\n {...(field.badge ? { badge: field.badge } : {})}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(field.labelIcon != null ? { labelIcon: field.labelIcon } : {})}\n >\n {built.value}\n </ObjectSection>\n );\n }\n // A display field (heading/divider/info/spacer) is the label — it carries no\n // value column, so it spans the full grid width with no inline label cell.\n if (field.kind === \"display\") {\n return <div className=\"col-span-full\">{built.value}</div>;\n }\n const label = opts?.labelOverride ? (\n <span className={cn(\"flex items-center gap-2 font-medium\", labelSizeClass[ctx.size])}>\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{opts.labelOverride}</span>\n {field.required && <span className=\"text-destructive\">*</span>}\n {field.badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {field.badge}\n </span>\n )}\n </span>\n ) : (\n built.label\n );\n const err = softError(field);\n return (\n <FieldWrapper\n layout={ctx.layout}\n size={ctx.size}\n label={label}\n value={built.value}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(err ? { error: err } : {})}\n />\n );\n}\n\n// renderObjectFields maps an object subschema's effective properties to field\n// rows. It is the recursive heart, shared by the top-level form and the nested\n// ObjectControl. Edits spread immutably onto the object.\nexport function renderObjectFields(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n onChange: (next: Record<string, unknown>) => void,\n ctx: RenderContext,\n opts?: { hiddenKeys?: string[] },\n): ReactNode[] {\n const { properties, required } = effectiveProperties(schema, value);\n const hidden = new Set(opts?.hiddenKeys ?? []);\n // Per-property `x-clicky-order` wins (composes across merged branches); the\n // object-level `x-order` array is the fallback; document order otherwise.\n const ordered = orderByClickyOrder(orderByXOrder(Object.entries(properties), schema[\"x-order\"]));\n const entries =\n ctx.sortMode === \"required-first\"\n ? orderRequiredFirst(ordered, required)\n : ctx.sortMode === \"priority\"\n ? orderByPriority(ordered, required, value)\n : ordered;\n return entries.flatMap(([key, prop]) => {\n if (hidden.has(key)) return [];\n const row = renderFieldRow(\n {\n key,\n prop,\n required: required.includes(key),\n value: value[key],\n onChange: (next) => onChange({ ...value, [key]: next }),\n },\n ctx,\n );\n // `contents` keeps the keyed wrapper out of the box tree so the row's own\n // node (a subgrid FieldWrapper or a full-width ObjectSection) is a direct\n // child of the FieldsGrid and snaps to its label/value tracks.\n return row ? [<div key={key} className=\"contents\">{row}</div>] : [];\n });\n}\n\n// renderApi is the RenderContext injection bundle: the root form stores it on\n// the context so container controls can recurse without importing this module.\nexport const renderApi: RenderApi = {\n renderFieldNodes,\n renderFieldRow,\n renderObjectFields,\n};\n"],"names":["fieldInputId","ReadOnlyValue","jsx","EnumControl","LookupControl","BooleanControl","NumberControl","DateControl","TextareaControl","MarkdownControl","DisplayControl","LinkControl","ArrayControl","ObjectControl","StringMapControl","StringControl","resolveControl","FieldLabel","ObjectSection","jsxs","cn","labelSizeClass","LabelIcon","softError","FieldWrapper","effectiveProperties","orderByClickyOrder","orderByXOrder","orderRequiredFirst","orderByPriority"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-render.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-render.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"json-schema-form-render.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-render.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAsBvC,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACd,MAAM,0BAA0B,CAAC;AAmBlC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,SAAS,CAkDrF;AAgED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,aAAa,GACjB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAAG,IAAI,CAI/C;AAKD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,EACf,GAAG,EAAE,aAAa,EAClB,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,SAAS,GAAG,IAAI,CAsDlB;AAKD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EACjD,GAAG,EAAE,aAAa,EAClB,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC/B,SAAS,EAAE,CA6Bb;AAID,eAAO,MAAM,SAAS,EAAE,SAIvB,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import "react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { LabelIcon } from "../data/Icon.js";
|
|
5
|
-
import { ObjectSection, FieldWrapper, FieldLabel, ReadOnlyValue, StringControl, LinkControl, DisplayControl, TextareaControl, DateControl, NumberControl, BooleanControl, LookupControl, EnumControl } from "./json-schema-form-fields.js";
|
|
5
|
+
import { ObjectSection, FieldWrapper, FieldLabel, ReadOnlyValue, StringControl, LinkControl, DisplayControl, MarkdownControl, TextareaControl, DateControl, NumberControl, BooleanControl, LookupControl, EnumControl } from "./json-schema-form-fields.js";
|
|
6
6
|
import { ArrayControl } from "./json-schema-form-array.js";
|
|
7
7
|
import { StringMapControl, ObjectControl } from "./json-schema-form-object.js";
|
|
8
8
|
import { effectiveProperties, resolveControl } from "./json-schema-form-resolve.js";
|
|
@@ -37,6 +37,8 @@ function renderValueControl(field, ctx) {
|
|
|
37
37
|
return /* @__PURE__ */ jsx(DateControl, { field, fieldId, readOnly, size });
|
|
38
38
|
case "textarea":
|
|
39
39
|
return /* @__PURE__ */ jsx(TextareaControl, { field, fieldId, readOnly, size });
|
|
40
|
+
case "markdown":
|
|
41
|
+
return /* @__PURE__ */ jsx(MarkdownControl, { field, fieldId, readOnly, size });
|
|
40
42
|
case "display":
|
|
41
43
|
return /* @__PURE__ */ jsx(DisplayControl, { field, size });
|
|
42
44
|
case "link":
|
|
@@ -52,7 +54,7 @@ function renderValueControl(field, ctx) {
|
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
function ownsReadOnlyRendering(kind) {
|
|
55
|
-
return kind === "array" || kind === "object" || kind === "string-map" || kind === "textarea" || kind === "display" || kind === "link";
|
|
57
|
+
return kind === "array" || kind === "object" || kind === "string-map" || kind === "textarea" || kind === "markdown" || kind === "display" || kind === "link";
|
|
56
58
|
}
|
|
57
59
|
function buildField(args, ctx) {
|
|
58
60
|
const base = resolveControl(args);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-render.js","sources":["../../src/components/json-schema-form-render.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { LabelIcon } from \"../data/Icon\";\nimport {\n BooleanControl,\n DateControl,\n DisplayControl,\n EnumControl,\n FieldLabel,\n FieldWrapper,\n LinkControl,\n LookupControl,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\n TextareaControl,\n} from \"./json-schema-form-fields\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { ObjectControl, StringMapControl } from \"./json-schema-form-object\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldArgs,\n FieldControl,\n JsonSchemaObject,\n RenderApi,\n RenderContext,\n} from \"./json-schema-form-types\";\nimport {\n fieldInputId,\n orderByClickyOrder,\n orderByPriority,\n orderByXOrder,\n orderRequiredFirst,\n softError,\n} from \"./json-schema-form-utils\";\nimport { labelSizeClass } from \"./json-schema-form-size\";\n\n// This module is the top of the json-schema-form graph: it imports the control\n// components and dispatches into them, while container controls recurse back in\n// only through ctx.render (see RenderApi). Nothing here is a React component,\n// so the component modules stay Fast-Refresh-eligible and cycle-free.\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface, and textarea/display/link own their non-editable rendering\n // (multi-line text / static element / hyperlink), so all of these are excluded\n // from the plain ReadOnlyValue fallback.\n if (field.readOnly && !ownsReadOnlyRendering(field.kind)) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly || field.readOnly === true;\n const size = ctx.size;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"lookup\":\n return (\n <LookupControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n {...(ctx.rootValue ? { rootValue: ctx.rootValue } : {})}\n />\n );\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"textarea\":\n return <TextareaControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"display\":\n return <DisplayControl field={field} size={size} />;\n case \"link\":\n return <LinkControl field={field} fieldId={fieldId} size={size} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n}\n\n// ownsReadOnlyRendering reports whether a control renders its own non-editable\n// form, so the renderer must not pre-empt it with the plain ReadOnlyValue text:\n// containers recurse structurally, and textarea/display/link have bespoke\n// read-only output.\nfunction ownsReadOnlyRendering(kind: FieldControl[\"kind\"]): boolean {\n return (\n kind === \"array\" ||\n kind === \"object\" ||\n kind === \"string-map\" ||\n kind === \"textarea\" ||\n kind === \"display\" ||\n kind === \"link\"\n );\n}\n\n// buildField resolves a control, applies the pre-extensions (any returning\n// null drops the field), renders the value node, then applies the\n// post-extensions to the {label, value} node pair.\nfunction buildField(\n args: FieldArgs,\n ctx: RenderContext,\n): { field: FieldControl; label: ReactNode; value: ReactNode } | null {\n const base = resolveControl(args);\n let field: FieldControl | null = base;\n for (const ext of ctx.pre) {\n if (!field) break;\n field = ext(field, {\n key: args.key,\n prop: args.prop,\n value: args.value,\n ...(ctx.rootValue ? { rootValue: ctx.rootValue } : {}),\n });\n }\n if (!field) return null;\n // Drop read-only fields entirely when the form opts out of displaying them.\n // Checked after pre-extensions so an extension that sets/clears readOnly wins.\n if (ctx.hideReadOnlyFields && field.readOnly) return null;\n\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n let label: ReactNode = <FieldLabel field={field} fieldId={fieldId} size={ctx.size} />;\n // A field's `x-layout: inline|stack` overrides the form-level layout for its\n // own value subtree (the field's own row keeps the parent layout). \"table\" is\n // handled structurally inside the array/string-map controls, not here.\n const overrideMode =\n field.layout === \"inline\" ? \"inline\" : field.layout === \"stack\" ? \"stacked\" : undefined;\n const valueCtx: RenderContext = overrideMode\n ? { ...ctx, layout: { ...ctx.layout, mode: overrideMode } }\n : ctx;\n let value: ReactNode = renderValueControl(field, valueCtx);\n const postCtx = ctx.rootValue ? { rootValue: ctx.rootValue } : {};\n for (const ext of ctx.post) {\n const next = ext(field, { label, value }, postCtx);\n label = next.label;\n value = next.value;\n }\n return { field, label, value };\n}\n\n// renderFieldNodes runs the full pipeline and returns the raw {label, value}\n// nodes (no FieldWrapper). Used where the caller arranges layout itself — map\n// rows (value only) and scalar array items.\nexport function renderFieldNodes(\n args: FieldArgs,\n ctx: RenderContext,\n): { label: ReactNode; value: ReactNode } | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n return { label: built.label, value: built.value };\n}\n\n// renderFieldRow runs the pipeline and wraps it in a FieldWrapper with the soft\n// validation hint. `labelOverride` lets a container relabel a field that has no\n// natural key (e.g. array items → \"Item 1\").\nexport function renderFieldRow(\n args: FieldArgs,\n ctx: RenderContext,\n opts?: { labelOverride?: string },\n): ReactNode | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n const { field } = built;\n // Object fields — and table-laid-out arrays/string-maps — render as a flat\n // section: a header followed by their body at full width, rather than an\n // inline label + narrow value column. This keeps deep schemas (e.g. policy →\n // shape, asfile → params) readable as a single column of labelled sections,\n // and gives a `x-layout: \"table\"` array the full width its columns need\n // instead of cramming it into the inline value column.\n if (field.kind === \"object\" || field.layout === \"table\") {\n return (\n <ObjectSection\n label={opts?.labelOverride ?? field.label}\n required={field.required}\n size={ctx.size}\n {...(field.badge ? { badge: field.badge } : {})}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(field.labelIcon != null ? { labelIcon: field.labelIcon } : {})}\n >\n {built.value}\n </ObjectSection>\n );\n }\n // A display field (heading/divider/info/spacer) is the label — it carries no\n // value column, so it spans the full grid width with no inline label cell.\n if (field.kind === \"display\") {\n return <div className=\"col-span-full\">{built.value}</div>;\n }\n const label = opts?.labelOverride ? (\n <span className={cn(\"flex items-center gap-2 font-medium\", labelSizeClass[ctx.size])}>\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{opts.labelOverride}</span>\n {field.required && <span className=\"text-destructive\">*</span>}\n {field.badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {field.badge}\n </span>\n )}\n </span>\n ) : (\n built.label\n );\n const err = softError(field);\n return (\n <FieldWrapper\n layout={ctx.layout}\n size={ctx.size}\n label={label}\n value={built.value}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(err ? { error: err } : {})}\n />\n );\n}\n\n// renderObjectFields maps an object subschema's effective properties to field\n// rows. It is the recursive heart, shared by the top-level form and the nested\n// ObjectControl. Edits spread immutably onto the object.\nexport function renderObjectFields(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n onChange: (next: Record<string, unknown>) => void,\n ctx: RenderContext,\n opts?: { hiddenKeys?: string[] },\n): ReactNode[] {\n const { properties, required } = effectiveProperties(schema, value);\n const hidden = new Set(opts?.hiddenKeys ?? []);\n // Per-property `x-clicky-order` wins (composes across merged branches); the\n // object-level `x-order` array is the fallback; document order otherwise.\n const ordered = orderByClickyOrder(orderByXOrder(Object.entries(properties), schema[\"x-order\"]));\n const entries =\n ctx.sortMode === \"required-first\"\n ? orderRequiredFirst(ordered, required)\n : ctx.sortMode === \"priority\"\n ? orderByPriority(ordered, required, value)\n : ordered;\n return entries.flatMap(([key, prop]) => {\n if (hidden.has(key)) return [];\n const row = renderFieldRow(\n {\n key,\n prop,\n required: required.includes(key),\n value: value[key],\n onChange: (next) => onChange({ ...value, [key]: next }),\n },\n ctx,\n );\n // `contents` keeps the keyed wrapper out of the box tree so the row's own\n // node (a subgrid FieldWrapper or a full-width ObjectSection) is a direct\n // child of the FieldsGrid and snaps to its label/value tracks.\n return row ? [<div key={key} className=\"contents\">{row}</div>] : [];\n });\n}\n\n// renderApi is the RenderContext injection bundle: the root form stores it on\n// the context so container controls can recurse without importing this module.\nexport const renderApi: RenderApi = {\n renderFieldNodes,\n renderFieldRow,\n renderObjectFields,\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-render.js","sources":["../../src/components/json-schema-form-render.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { LabelIcon } from \"../data/Icon\";\nimport {\n BooleanControl,\n DateControl,\n DisplayControl,\n EnumControl,\n FieldLabel,\n FieldWrapper,\n LinkControl,\n LookupControl,\n MarkdownControl,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\n TextareaControl,\n} from \"./json-schema-form-fields\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { ObjectControl, StringMapControl } from \"./json-schema-form-object\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldArgs,\n FieldControl,\n JsonSchemaObject,\n RenderApi,\n RenderContext,\n} from \"./json-schema-form-types\";\nimport {\n fieldInputId,\n orderByClickyOrder,\n orderByPriority,\n orderByXOrder,\n orderRequiredFirst,\n softError,\n} from \"./json-schema-form-utils\";\nimport { labelSizeClass } from \"./json-schema-form-size\";\n\n// This module is the top of the json-schema-form graph: it imports the control\n// components and dispatches into them, while container controls recurse back in\n// only through ctx.render (see RenderApi). Nothing here is a React component,\n// so the component modules stay Fast-Refresh-eligible and cycle-free.\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface, and textarea/display/link own their non-editable rendering\n // (multi-line text / static element / hyperlink), so all of these are excluded\n // from the plain ReadOnlyValue fallback.\n if (field.readOnly && !ownsReadOnlyRendering(field.kind)) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly || field.readOnly === true;\n const size = ctx.size;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"lookup\":\n return (\n <LookupControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n {...(ctx.rootValue ? { rootValue: ctx.rootValue } : {})}\n />\n );\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"textarea\":\n return <TextareaControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"markdown\":\n return <MarkdownControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n case \"display\":\n return <DisplayControl field={field} size={size} />;\n case \"link\":\n return <LinkControl field={field} fieldId={fieldId} size={size} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n}\n\n// ownsReadOnlyRendering reports whether a control renders its own non-editable\n// form, so the renderer must not pre-empt it with the plain ReadOnlyValue text:\n// containers recurse structurally, and textarea/display/link have bespoke\n// read-only output.\nfunction ownsReadOnlyRendering(kind: FieldControl[\"kind\"]): boolean {\n return (\n kind === \"array\" ||\n kind === \"object\" ||\n kind === \"string-map\" ||\n kind === \"textarea\" ||\n kind === \"markdown\" ||\n kind === \"display\" ||\n kind === \"link\"\n );\n}\n\n// buildField resolves a control, applies the pre-extensions (any returning\n// null drops the field), renders the value node, then applies the\n// post-extensions to the {label, value} node pair.\nfunction buildField(\n args: FieldArgs,\n ctx: RenderContext,\n): { field: FieldControl; label: ReactNode; value: ReactNode } | null {\n const base = resolveControl(args);\n let field: FieldControl | null = base;\n for (const ext of ctx.pre) {\n if (!field) break;\n field = ext(field, {\n key: args.key,\n prop: args.prop,\n value: args.value,\n ...(ctx.rootValue ? { rootValue: ctx.rootValue } : {}),\n });\n }\n if (!field) return null;\n // Drop read-only fields entirely when the form opts out of displaying them.\n // Checked after pre-extensions so an extension that sets/clears readOnly wins.\n if (ctx.hideReadOnlyFields && field.readOnly) return null;\n\n const fieldId = fieldInputId(field.key, ctx.idPrefix);\n let label: ReactNode = <FieldLabel field={field} fieldId={fieldId} size={ctx.size} />;\n // A field's `x-layout: inline|stack` overrides the form-level layout for its\n // own value subtree (the field's own row keeps the parent layout). \"table\" is\n // handled structurally inside the array/string-map controls, not here.\n const overrideMode =\n field.layout === \"inline\" ? \"inline\" : field.layout === \"stack\" ? \"stacked\" : undefined;\n const valueCtx: RenderContext = overrideMode\n ? { ...ctx, layout: { ...ctx.layout, mode: overrideMode } }\n : ctx;\n let value: ReactNode = renderValueControl(field, valueCtx);\n const postCtx = ctx.rootValue ? { rootValue: ctx.rootValue } : {};\n for (const ext of ctx.post) {\n const next = ext(field, { label, value }, postCtx);\n label = next.label;\n value = next.value;\n }\n return { field, label, value };\n}\n\n// renderFieldNodes runs the full pipeline and returns the raw {label, value}\n// nodes (no FieldWrapper). Used where the caller arranges layout itself — map\n// rows (value only) and scalar array items.\nexport function renderFieldNodes(\n args: FieldArgs,\n ctx: RenderContext,\n): { label: ReactNode; value: ReactNode } | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n return { label: built.label, value: built.value };\n}\n\n// renderFieldRow runs the pipeline and wraps it in a FieldWrapper with the soft\n// validation hint. `labelOverride` lets a container relabel a field that has no\n// natural key (e.g. array items → \"Item 1\").\nexport function renderFieldRow(\n args: FieldArgs,\n ctx: RenderContext,\n opts?: { labelOverride?: string },\n): ReactNode | null {\n const built = buildField(args, ctx);\n if (!built) return null;\n const { field } = built;\n // Object fields — and table-laid-out arrays/string-maps — render as a flat\n // section: a header followed by their body at full width, rather than an\n // inline label + narrow value column. This keeps deep schemas (e.g. policy →\n // shape, asfile → params) readable as a single column of labelled sections,\n // and gives a `x-layout: \"table\"` array the full width its columns need\n // instead of cramming it into the inline value column.\n if (field.kind === \"object\" || field.layout === \"table\") {\n return (\n <ObjectSection\n label={opts?.labelOverride ?? field.label}\n required={field.required}\n size={ctx.size}\n {...(field.badge ? { badge: field.badge } : {})}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(field.labelIcon != null ? { labelIcon: field.labelIcon } : {})}\n >\n {built.value}\n </ObjectSection>\n );\n }\n // A display field (heading/divider/info/spacer) is the label — it carries no\n // value column, so it spans the full grid width with no inline label cell.\n if (field.kind === \"display\") {\n return <div className=\"col-span-full\">{built.value}</div>;\n }\n const label = opts?.labelOverride ? (\n <span className={cn(\"flex items-center gap-2 font-medium\", labelSizeClass[ctx.size])}>\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{opts.labelOverride}</span>\n {field.required && <span className=\"text-destructive\">*</span>}\n {field.badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {field.badge}\n </span>\n )}\n </span>\n ) : (\n built.label\n );\n const err = softError(field);\n return (\n <FieldWrapper\n layout={ctx.layout}\n size={ctx.size}\n label={label}\n value={built.value}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(err ? { error: err } : {})}\n />\n );\n}\n\n// renderObjectFields maps an object subschema's effective properties to field\n// rows. It is the recursive heart, shared by the top-level form and the nested\n// ObjectControl. Edits spread immutably onto the object.\nexport function renderObjectFields(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n onChange: (next: Record<string, unknown>) => void,\n ctx: RenderContext,\n opts?: { hiddenKeys?: string[] },\n): ReactNode[] {\n const { properties, required } = effectiveProperties(schema, value);\n const hidden = new Set(opts?.hiddenKeys ?? []);\n // Per-property `x-clicky-order` wins (composes across merged branches); the\n // object-level `x-order` array is the fallback; document order otherwise.\n const ordered = orderByClickyOrder(orderByXOrder(Object.entries(properties), schema[\"x-order\"]));\n const entries =\n ctx.sortMode === \"required-first\"\n ? orderRequiredFirst(ordered, required)\n : ctx.sortMode === \"priority\"\n ? orderByPriority(ordered, required, value)\n : ordered;\n return entries.flatMap(([key, prop]) => {\n if (hidden.has(key)) return [];\n const row = renderFieldRow(\n {\n key,\n prop,\n required: required.includes(key),\n value: value[key],\n onChange: (next) => onChange({ ...value, [key]: next }),\n },\n ctx,\n );\n // `contents` keeps the keyed wrapper out of the box tree so the row's own\n // node (a subgrid FieldWrapper or a full-width ObjectSection) is a direct\n // child of the FieldsGrid and snaps to its label/value tracks.\n return row ? [<div key={key} className=\"contents\">{row}</div>] : [];\n });\n}\n\n// renderApi is the RenderContext injection bundle: the root form stores it on\n// the context so container controls can recurse without importing this module.\nexport const renderApi: RenderApi = {\n renderFieldNodes,\n renderFieldRow,\n renderObjectFields,\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsonSchemaFormUtils = require("./json-schema-form-utils.cjs");
|
|
3
4
|
function isOpenStringMap(prop) {
|
|
4
5
|
if (!schemaHasType(prop, "object")) return false;
|
|
5
6
|
if (typeof prop.additionalProperties === "object" && prop.additionalProperties !== null) {
|
|
@@ -86,6 +87,14 @@ function resolveControl(args) {
|
|
|
86
87
|
if (prop.format === "textarea" && schemaHasType(prop, "string")) {
|
|
87
88
|
return { ...base, kind: "textarea" };
|
|
88
89
|
}
|
|
90
|
+
if (prop.format === "md" && schemaHasType(prop, "string")) {
|
|
91
|
+
const markdownOptions = prop["x-md-editor"];
|
|
92
|
+
return {
|
|
93
|
+
...base,
|
|
94
|
+
kind: "markdown",
|
|
95
|
+
...jsonSchemaFormUtils.isPlainObject(markdownOptions) ? { markdownOptions } : {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
89
98
|
if (schemaHasType(prop, "boolean")) {
|
|
90
99
|
return { ...base, kind: "boolean" };
|
|
91
100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-resolve.cjs","sources":["../../src/components/json-schema-form-resolve.ts"],"sourcesContent":["import type {\n EnumDisplay,\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n LookupDescriptor,\n} from \"./json-schema-form-types\";\n\n// isOpenStringMap reports whether a property is an object whose entries are\n// described by a sub-schema in `additionalProperties` (a typed key/value map) or\n// by `patternProperties` (a per-key-pattern value map). Either makes it an\n// editable key/value control rather than a fixed-property sub-form.\nexport function isOpenStringMap(prop: JsonSchemaProperty): boolean {\n if (!schemaHasType(prop, \"object\")) return false;\n if (typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null) {\n return true;\n }\n return !!prop.patternProperties && Object.keys(prop.patternProperties).length > 0;\n}\n\n// patternSchemasOf compiles a schema's `patternProperties` into the ordered\n// {pattern, schema} list the string-map control matches keys against.\nfunction patternSchemasOf(prop: JsonSchemaProperty): { pattern: string; schema: JsonSchemaProperty }[] | undefined {\n const pp = prop.patternProperties;\n if (!pp || Object.keys(pp).length === 0) return undefined;\n return Object.entries(pp).map(([pattern, schema]) => ({ pattern, schema }));\n}\n\nfunction schemaHasType(prop: JsonSchemaProperty, type: string): boolean {\n if (Array.isArray(prop.type)) return prop.type.includes(type as never);\n return prop.type === type;\n}\n\nfunction enumOptions(prop: JsonSchemaProperty): FieldOption[] {\n const labels = prop[\"x-enum-labels\"];\n const icons = prop[\"x-enum-icons\"];\n return (prop.enum ?? []).map((v) => {\n const value = String(v);\n const desc = labels?.[value];\n const icon = icons?.[value];\n return {\n value,\n label: typeof desc === \"string\" && desc && desc !== value ? `${desc} (${value})` : value,\n ...(typeof icon === \"string\" && icon ? { icon } : {}),\n };\n });\n}\n\n// enumDisplay resolves how an enum should render: an explicit `x-enum-display`\n// wins; otherwise an enum carrying `x-enum-icons` defaults to the icon grid.\n// Returns undefined to keep the combobox default.\nfunction enumDisplay(prop: JsonSchemaProperty): EnumDisplay | undefined {\n const d = prop[\"x-enum-display\"];\n if (d === \"combobox\" || d === \"radio\" || d === \"grid\") return d;\n const icons = prop[\"x-enum-icons\"];\n if (icons && Object.keys(icons).length > 0) return \"grid\";\n return undefined;\n}\n\n// enumBranch returns the first anyOf/oneOf member carrying a non-empty `enum`,\n// for a union of \"an enum value OR a free-form string\" (e.g. a value-or-token\n// field). It lets such a union render as a dropdown. Returns undefined when no\n// branch enumerates values.\nexport function enumBranch(prop: JsonSchemaProperty): JsonSchemaProperty | undefined {\n for (const branch of [...(prop.anyOf ?? []), ...(prop.oneOf ?? [])]) {\n if (Array.isArray(branch.enum) && branch.enum.length > 0) return branch;\n }\n return undefined;\n}\n\n// lookupDescriptor reads the `x-clicky-lookup` extension into a LookupDescriptor,\n// returning undefined when the keyword is absent or lacks its required url/filter.\nfunction lookupDescriptor(prop: JsonSchemaProperty): LookupDescriptor | undefined {\n const raw = prop[\"x-clicky-lookup\"];\n if (!raw || typeof raw !== \"object\") return undefined;\n const d = raw as Record<string, unknown>;\n if (typeof d.url !== \"string\" || typeof d.filter !== \"string\") return undefined;\n return raw as LookupDescriptor;\n}\n\nexport interface ResolveControlArgs {\n key: string;\n prop: JsonSchemaProperty;\n required: boolean;\n value: unknown;\n onChange: (next: unknown) => void;\n}\n\n// resolveControl infers a base, render-ready FieldControl from a property\n// schema. It keys off schema keywords only — never the field name: ascode/token\n// heuristics are layered on by consumer pre-extensions. The one exception is the\n// standard `format: date`/`date-time` keyword, which is a schema-declared signal\n// (not a name guess) and so drives a date control directly. First match wins.\nexport function resolveControl(args: ResolveControlArgs): FieldControl {\n const { key, prop, required, value, onChange } = args;\n const labelIcon = prop[\"x-icon\"];\n const xLayout = prop[\"x-layout\"];\n const layout =\n xLayout === \"inline\" || xLayout === \"stack\" || xLayout === \"table\" ? xLayout : undefined;\n const keyOptions = keyOptionsFor(prop);\n const base: FieldControl = {\n key,\n kind: \"string\",\n label: typeof prop.title === \"string\" && prop.title ? prop.title : key,\n required,\n schema: prop,\n value,\n onChange,\n ...(prop.readOnly === true ? { readOnly: true } : {}),\n ...(typeof prop.description === \"string\" ? { description: prop.description } : {}),\n ...(labelIcon != null && labelIcon !== \"\" ? { labelIcon: labelIcon as FieldControl[\"labelIcon\"] } : {}),\n };\n\n // An `x-clicky-lookup` field is an async entity-reference picker: options load\n // lazily from another entity's list endpoint. Single-select also allows\n // free-form entry so a typed value outside the option set still commits.\n const lookup = lookupDescriptor(prop);\n if (lookup) {\n return { ...base, kind: \"lookup\", lookup, options: [], allowCustomValue: lookup.multi !== true };\n }\n if (Array.isArray(prop.enum) && prop.enum.length > 0) {\n const display = enumDisplay(prop);\n return { ...base, kind: \"enum\", options: enumOptions(prop), ...(display ? { display } : {}) };\n }\n // A value-or-template union: the enum lives in an anyOf/oneOf branch alongside\n // free-form branches. Render it as a dropdown using that branch's enum; the\n // free-form branches are honoured via a consumer's allowCustomValue pre-ext.\n const branch = enumBranch(prop);\n if (branch) {\n return { ...base, kind: \"enum\", options: enumOptions(branch) };\n }\n // A schema-declared date/date-time string renders as a date control.\n if (prop.format === \"date\" || prop.format === \"date-time\") {\n return { ...base, kind: \"date\", dateFormat: prop.format };\n }\n // A long-form string declares `format: textarea` to render a multi-line box.\n if (prop.format === \"textarea\" && schemaHasType(prop, \"string\")) {\n return { ...base, kind: \"textarea\" };\n }\n if (schemaHasType(prop, \"boolean\")) {\n return { ...base, kind: \"boolean\" };\n }\n if (schemaHasType(prop, \"integer\") || schemaHasType(prop, \"number\")) {\n return {\n ...base,\n kind: \"number\",\n coerceNumber: true,\n // A percent number carries a static \"%\" unit shown inside the input.\n ...(prop.format === \"percent\" ? { unit: \"%\" } : {}),\n ...(typeof prop.minimum === \"number\" ? { minimum: prop.minimum } : {}),\n };\n }\n if (schemaHasType(prop, \"array\")) {\n return {\n ...base,\n kind: \"array\",\n ...(prop.items ? { itemSchema: prop.items } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // An open map: object whose entries are described by an additionalProperties\n // sub-schema and/or per-key patternProperties. Renders as editable key/value\n // rows (+ any known properties), with the value form resolved per key.\n if (isOpenStringMap(prop)) {\n const addl =\n typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null\n ? (prop.additionalProperties as JsonSchemaProperty)\n : undefined;\n const patterns = patternSchemasOf(prop);\n // A constrained picker (propertyNames enum) or patternProperties still lets\n // the author ADD keys — the additions are limited to the allowed set, not\n // free-form — so `additionalProperties: false` doesn't disable \"Add field\"\n // in that case. It only closes a plain open map with no key constraints.\n const allowExtraKeys = keyOptions || patterns ? true : prop.additionalProperties !== false;\n return {\n ...base,\n kind: \"string-map\",\n ...(addl ? { valueSchema: addl } : {}),\n ...(patterns ? { valuePatternSchemas: patterns } : {}),\n ...(prop.properties ? { knownProperties: prop.properties } : {}),\n allowExtraKeys,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A structured object: fixed `properties`, not an open map. Renders as a\n // nested sub-form (labels, required, if/then) — recursed into by the renderer.\n if (schemaHasType(prop, \"object\") && prop.properties) {\n return {\n ...base,\n kind: \"object\",\n objectProperties: prop.properties,\n ...(prop.required ? { objectRequired: prop.required } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A bare object with neither properties nor an additionalProperties schema:\n // treat as an open string map unless explicitly closed.\n if (schemaHasType(prop, \"object\")) {\n return {\n ...base,\n kind: \"string-map\",\n allowExtraKeys: prop.additionalProperties !== false,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n return base;\n}\n\n// keyOptionsFor resolves the strict map-key picker options from a map schema's\n// `propertyNames.enum` (e.g. an AsCode-constrained key set). Returns undefined\n// when the keys are unconstrained, so the key stays free-text.\nfunction keyOptionsFor(prop: JsonSchemaProperty): FieldOption[] | undefined {\n const pn = prop.propertyNames as JsonSchemaProperty | undefined;\n if (!pn || !Array.isArray(pn.enum) || pn.enum.length === 0) return undefined;\n return enumOptions(pn);\n}\n\n// isScalarStringItems reports whether an array's item schema is a plain string\n// with no richer shape — the case the array control renders as compact tags.\n// Anything with an enum/const/properties/items/additionalProperties/allOf needs\n// a real per-item control instead.\nexport function isScalarStringItems(items: JsonSchemaProperty | undefined): boolean {\n if (!items) return true; // untyped items default to string tags\n if (items.type !== undefined && !schemaHasType(items, \"string\")) return false;\n return (\n items.enum === undefined &&\n items.const === undefined &&\n items.properties === undefined &&\n items.items === undefined &&\n items.additionalProperties === undefined &&\n items.allOf === undefined\n );\n}\n\n// matchesIf reports whether the `if` sub-schema holds for the current value:\n// every `if.required` key is present AND every `if.properties[k].const` equals\n// value[k].\nexport function matchesIf(\n ifSchema: JsonSchemaProperty | undefined,\n value: Record<string, unknown>,\n): boolean {\n if (!ifSchema) return false;\n for (const k of ifSchema.required ?? []) {\n if (!(k in value)) return false;\n }\n for (const [k, sub] of Object.entries(ifSchema.properties ?? {})) {\n if (\"const\" in sub && value[k] !== sub.const) return false;\n }\n return true;\n}\n\nexport interface EffectiveProperties {\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n// effectiveProperties merges the schema's base `properties` with each `allOf`\n// member's contribution. An `if`/`then` member contributes `then.properties`\n// only when its `if` matches the current value; an unconditional member (e.g.\n// an inlined `$ref` composition, which carries its own `properties` and no\n// `if`) always contributes. Later members win on key collision; required is the\n// union. Pure and idempotent.\nexport function effectiveProperties(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n): EffectiveProperties {\n const properties: Record<string, JsonSchemaProperty> = { ...schema.properties };\n const required = new Set(schema.required ?? []);\n for (const clause of schema.allOf ?? []) {\n // Unconditional composition member: merge its own properties/required.\n if (clause.if === undefined && clause.then === undefined) {\n for (const [k, sub] of Object.entries(clause.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of clause.required ?? []) required.add(k);\n continue;\n }\n if (!matchesIf(clause.if, value)) continue;\n const then = clause.then ?? {};\n for (const [k, sub] of Object.entries(then.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of then.required ?? []) required.add(k);\n }\n return { properties, required: [...required] };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-resolve.cjs","sources":["../../src/components/json-schema-form-resolve.ts"],"sourcesContent":["import type {\n EnumDisplay,\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n LookupDescriptor,\n} from \"./json-schema-form-types\";\nimport { isPlainObject } from \"./json-schema-form-utils\";\n\n// isOpenStringMap reports whether a property is an object whose entries are\n// described by a sub-schema in `additionalProperties` (a typed key/value map) or\n// by `patternProperties` (a per-key-pattern value map). Either makes it an\n// editable key/value control rather than a fixed-property sub-form.\nexport function isOpenStringMap(prop: JsonSchemaProperty): boolean {\n if (!schemaHasType(prop, \"object\")) return false;\n if (typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null) {\n return true;\n }\n return !!prop.patternProperties && Object.keys(prop.patternProperties).length > 0;\n}\n\n// patternSchemasOf compiles a schema's `patternProperties` into the ordered\n// {pattern, schema} list the string-map control matches keys against.\nfunction patternSchemasOf(prop: JsonSchemaProperty): { pattern: string; schema: JsonSchemaProperty }[] | undefined {\n const pp = prop.patternProperties;\n if (!pp || Object.keys(pp).length === 0) return undefined;\n return Object.entries(pp).map(([pattern, schema]) => ({ pattern, schema }));\n}\n\nfunction schemaHasType(prop: JsonSchemaProperty, type: string): boolean {\n if (Array.isArray(prop.type)) return prop.type.includes(type as never);\n return prop.type === type;\n}\n\nfunction enumOptions(prop: JsonSchemaProperty): FieldOption[] {\n const labels = prop[\"x-enum-labels\"];\n const icons = prop[\"x-enum-icons\"];\n return (prop.enum ?? []).map((v) => {\n const value = String(v);\n const desc = labels?.[value];\n const icon = icons?.[value];\n return {\n value,\n label: typeof desc === \"string\" && desc && desc !== value ? `${desc} (${value})` : value,\n ...(typeof icon === \"string\" && icon ? { icon } : {}),\n };\n });\n}\n\n// enumDisplay resolves how an enum should render: an explicit `x-enum-display`\n// wins; otherwise an enum carrying `x-enum-icons` defaults to the icon grid.\n// Returns undefined to keep the combobox default.\nfunction enumDisplay(prop: JsonSchemaProperty): EnumDisplay | undefined {\n const d = prop[\"x-enum-display\"];\n if (d === \"combobox\" || d === \"radio\" || d === \"grid\") return d;\n const icons = prop[\"x-enum-icons\"];\n if (icons && Object.keys(icons).length > 0) return \"grid\";\n return undefined;\n}\n\n// enumBranch returns the first anyOf/oneOf member carrying a non-empty `enum`,\n// for a union of \"an enum value OR a free-form string\" (e.g. a value-or-token\n// field). It lets such a union render as a dropdown. Returns undefined when no\n// branch enumerates values.\nexport function enumBranch(prop: JsonSchemaProperty): JsonSchemaProperty | undefined {\n for (const branch of [...(prop.anyOf ?? []), ...(prop.oneOf ?? [])]) {\n if (Array.isArray(branch.enum) && branch.enum.length > 0) return branch;\n }\n return undefined;\n}\n\n// lookupDescriptor reads the `x-clicky-lookup` extension into a LookupDescriptor,\n// returning undefined when the keyword is absent or lacks its required url/filter.\nfunction lookupDescriptor(prop: JsonSchemaProperty): LookupDescriptor | undefined {\n const raw = prop[\"x-clicky-lookup\"];\n if (!raw || typeof raw !== \"object\") return undefined;\n const d = raw as Record<string, unknown>;\n if (typeof d.url !== \"string\" || typeof d.filter !== \"string\") return undefined;\n return raw as LookupDescriptor;\n}\n\nexport interface ResolveControlArgs {\n key: string;\n prop: JsonSchemaProperty;\n required: boolean;\n value: unknown;\n onChange: (next: unknown) => void;\n}\n\n// resolveControl infers a base, render-ready FieldControl from a property\n// schema. It keys off schema keywords only — never the field name: ascode/token\n// heuristics are layered on by consumer pre-extensions. The one exception is the\n// standard `format: date`/`date-time` keyword, which is a schema-declared signal\n// (not a name guess) and so drives a date control directly. First match wins.\nexport function resolveControl(args: ResolveControlArgs): FieldControl {\n const { key, prop, required, value, onChange } = args;\n const labelIcon = prop[\"x-icon\"];\n const xLayout = prop[\"x-layout\"];\n const layout =\n xLayout === \"inline\" || xLayout === \"stack\" || xLayout === \"table\" ? xLayout : undefined;\n const keyOptions = keyOptionsFor(prop);\n const base: FieldControl = {\n key,\n kind: \"string\",\n label: typeof prop.title === \"string\" && prop.title ? prop.title : key,\n required,\n schema: prop,\n value,\n onChange,\n ...(prop.readOnly === true ? { readOnly: true } : {}),\n ...(typeof prop.description === \"string\" ? { description: prop.description } : {}),\n ...(labelIcon != null && labelIcon !== \"\" ? { labelIcon: labelIcon as FieldControl[\"labelIcon\"] } : {}),\n };\n\n // An `x-clicky-lookup` field is an async entity-reference picker: options load\n // lazily from another entity's list endpoint. Single-select also allows\n // free-form entry so a typed value outside the option set still commits.\n const lookup = lookupDescriptor(prop);\n if (lookup) {\n return { ...base, kind: \"lookup\", lookup, options: [], allowCustomValue: lookup.multi !== true };\n }\n if (Array.isArray(prop.enum) && prop.enum.length > 0) {\n const display = enumDisplay(prop);\n return { ...base, kind: \"enum\", options: enumOptions(prop), ...(display ? { display } : {}) };\n }\n // A value-or-template union: the enum lives in an anyOf/oneOf branch alongside\n // free-form branches. Render it as a dropdown using that branch's enum; the\n // free-form branches are honoured via a consumer's allowCustomValue pre-ext.\n const branch = enumBranch(prop);\n if (branch) {\n return { ...base, kind: \"enum\", options: enumOptions(branch) };\n }\n // A schema-declared date/date-time string renders as a date control.\n if (prop.format === \"date\" || prop.format === \"date-time\") {\n return { ...base, kind: \"date\", dateFormat: prop.format };\n }\n // A long-form string declares `format: textarea` to render a multi-line box.\n if (prop.format === \"textarea\" && schemaHasType(prop, \"string\")) {\n return { ...base, kind: \"textarea\" };\n }\n // A markdown string declares `format: md` to render the MDXEditor-backed\n // editor. Plugin toggles live under `x-md-editor` so schema authors can keep\n // the format signal standard-sized and the editor behavior explicit.\n if (prop.format === \"md\" && schemaHasType(prop, \"string\")) {\n const markdownOptions = prop[\"x-md-editor\"];\n return {\n ...base,\n kind: \"markdown\",\n ...(isPlainObject(markdownOptions) ? { markdownOptions } : {}),\n };\n }\n if (schemaHasType(prop, \"boolean\")) {\n return { ...base, kind: \"boolean\" };\n }\n if (schemaHasType(prop, \"integer\") || schemaHasType(prop, \"number\")) {\n return {\n ...base,\n kind: \"number\",\n coerceNumber: true,\n // A percent number carries a static \"%\" unit shown inside the input.\n ...(prop.format === \"percent\" ? { unit: \"%\" } : {}),\n ...(typeof prop.minimum === \"number\" ? { minimum: prop.minimum } : {}),\n };\n }\n if (schemaHasType(prop, \"array\")) {\n return {\n ...base,\n kind: \"array\",\n ...(prop.items ? { itemSchema: prop.items } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // An open map: object whose entries are described by an additionalProperties\n // sub-schema and/or per-key patternProperties. Renders as editable key/value\n // rows (+ any known properties), with the value form resolved per key.\n if (isOpenStringMap(prop)) {\n const addl =\n typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null\n ? (prop.additionalProperties as JsonSchemaProperty)\n : undefined;\n const patterns = patternSchemasOf(prop);\n // A constrained picker (propertyNames enum) or patternProperties still lets\n // the author ADD keys — the additions are limited to the allowed set, not\n // free-form — so `additionalProperties: false` doesn't disable \"Add field\"\n // in that case. It only closes a plain open map with no key constraints.\n const allowExtraKeys = keyOptions || patterns ? true : prop.additionalProperties !== false;\n return {\n ...base,\n kind: \"string-map\",\n ...(addl ? { valueSchema: addl } : {}),\n ...(patterns ? { valuePatternSchemas: patterns } : {}),\n ...(prop.properties ? { knownProperties: prop.properties } : {}),\n allowExtraKeys,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A structured object: fixed `properties`, not an open map. Renders as a\n // nested sub-form (labels, required, if/then) — recursed into by the renderer.\n if (schemaHasType(prop, \"object\") && prop.properties) {\n return {\n ...base,\n kind: \"object\",\n objectProperties: prop.properties,\n ...(prop.required ? { objectRequired: prop.required } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A bare object with neither properties nor an additionalProperties schema:\n // treat as an open string map unless explicitly closed.\n if (schemaHasType(prop, \"object\")) {\n return {\n ...base,\n kind: \"string-map\",\n allowExtraKeys: prop.additionalProperties !== false,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n return base;\n}\n\n// keyOptionsFor resolves the strict map-key picker options from a map schema's\n// `propertyNames.enum` (e.g. an AsCode-constrained key set). Returns undefined\n// when the keys are unconstrained, so the key stays free-text.\nfunction keyOptionsFor(prop: JsonSchemaProperty): FieldOption[] | undefined {\n const pn = prop.propertyNames as JsonSchemaProperty | undefined;\n if (!pn || !Array.isArray(pn.enum) || pn.enum.length === 0) return undefined;\n return enumOptions(pn);\n}\n\n// isScalarStringItems reports whether an array's item schema is a plain string\n// with no richer shape — the case the array control renders as compact tags.\n// Anything with an enum/const/properties/items/additionalProperties/allOf needs\n// a real per-item control instead.\nexport function isScalarStringItems(items: JsonSchemaProperty | undefined): boolean {\n if (!items) return true; // untyped items default to string tags\n if (items.type !== undefined && !schemaHasType(items, \"string\")) return false;\n return (\n items.enum === undefined &&\n items.const === undefined &&\n items.properties === undefined &&\n items.items === undefined &&\n items.additionalProperties === undefined &&\n items.allOf === undefined\n );\n}\n\n// matchesIf reports whether the `if` sub-schema holds for the current value:\n// every `if.required` key is present AND every `if.properties[k].const` equals\n// value[k].\nexport function matchesIf(\n ifSchema: JsonSchemaProperty | undefined,\n value: Record<string, unknown>,\n): boolean {\n if (!ifSchema) return false;\n for (const k of ifSchema.required ?? []) {\n if (!(k in value)) return false;\n }\n for (const [k, sub] of Object.entries(ifSchema.properties ?? {})) {\n if (\"const\" in sub && value[k] !== sub.const) return false;\n }\n return true;\n}\n\nexport interface EffectiveProperties {\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n// effectiveProperties merges the schema's base `properties` with each `allOf`\n// member's contribution. An `if`/`then` member contributes `then.properties`\n// only when its `if` matches the current value; an unconditional member (e.g.\n// an inlined `$ref` composition, which carries its own `properties` and no\n// `if`) always contributes. Later members win on key collision; required is the\n// union. Pure and idempotent.\nexport function effectiveProperties(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n): EffectiveProperties {\n const properties: Record<string, JsonSchemaProperty> = { ...schema.properties };\n const required = new Set(schema.required ?? []);\n for (const clause of schema.allOf ?? []) {\n // Unconditional composition member: merge its own properties/required.\n if (clause.if === undefined && clause.then === undefined) {\n for (const [k, sub] of Object.entries(clause.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of clause.required ?? []) required.add(k);\n continue;\n }\n if (!matchesIf(clause.if, value)) continue;\n const then = clause.then ?? {};\n for (const [k, sub] of Object.entries(then.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of then.required ?? []) required.add(k);\n }\n return { properties, required: [...required] };\n}\n"],"names":["isPlainObject"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-resolve.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"json-schema-form-resolve.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EAEnB,MAAM,0BAA0B,CAAC;AAOlC,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAMjE;AA6CD,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,SAAS,CAKnF;AAYD,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAOD,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,YAAY,CA8HrE;AAeD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAWlF;AAKD,wBAAgB,SAAS,CACvB,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAST;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC/C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAQD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,mBAAmB,CAoBrB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPlainObject } from "./json-schema-form-utils.js";
|
|
1
2
|
function isOpenStringMap(prop) {
|
|
2
3
|
if (!schemaHasType(prop, "object")) return false;
|
|
3
4
|
if (typeof prop.additionalProperties === "object" && prop.additionalProperties !== null) {
|
|
@@ -84,6 +85,14 @@ function resolveControl(args) {
|
|
|
84
85
|
if (prop.format === "textarea" && schemaHasType(prop, "string")) {
|
|
85
86
|
return { ...base, kind: "textarea" };
|
|
86
87
|
}
|
|
88
|
+
if (prop.format === "md" && schemaHasType(prop, "string")) {
|
|
89
|
+
const markdownOptions = prop["x-md-editor"];
|
|
90
|
+
return {
|
|
91
|
+
...base,
|
|
92
|
+
kind: "markdown",
|
|
93
|
+
...isPlainObject(markdownOptions) ? { markdownOptions } : {}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
87
96
|
if (schemaHasType(prop, "boolean")) {
|
|
88
97
|
return { ...base, kind: "boolean" };
|
|
89
98
|
}
|