@flanksource/clicky-ui 0.2.16 → 0.2.18
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/dist/chat.cjs +16 -0
- package/dist/chat.cjs.map +1 -1
- package/dist/chat.js +17 -1
- package/dist/chat.js.map +1 -1
- package/dist/components/Combobox.cjs +19 -4
- package/dist/components/Combobox.cjs.map +1 -1
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +19 -4
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/FilterBar.cjs +45 -6
- package/dist/components/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar.d.ts +28 -0
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +45 -6
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/JsonSchemaForm.cjs +26 -3
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.d.ts.map +1 -1
- package/dist/components/JsonSchemaForm.js +26 -3
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/json-schema-form-preferences.cjs +4 -0
- package/dist/components/json-schema-form-preferences.cjs.map +1 -1
- package/dist/components/json-schema-form-preferences.d.ts +2 -0
- package/dist/components/json-schema-form-preferences.d.ts.map +1 -1
- package/dist/components/json-schema-form-preferences.js +4 -0
- package/dist/components/json-schema-form-preferences.js.map +1 -1
- package/dist/components/json-schema-form-render.cjs +1 -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 +2 -2
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-types.d.ts +5 -2
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components/json-schema-form-utils.cjs +13 -0
- package/dist/components/json-schema-form-utils.cjs.map +1 -1
- package/dist/components/json-schema-form-utils.d.ts +2 -0
- package/dist/components/json-schema-form-utils.d.ts.map +1 -1
- package/dist/components/json-schema-form-utils.js +13 -0
- package/dist/components/json-schema-form-utils.js.map +1 -1
- package/dist/components/loading.cjs +19 -6
- package/dist/components/loading.cjs.map +1 -1
- package/dist/components/loading.d.ts.map +1 -1
- package/dist/components/loading.js +19 -6
- package/dist/components/loading.js.map +1 -1
- package/dist/components.cjs +1 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +2 -1
- package/dist/data/Markdown.cjs +14 -40
- package/dist/data/Markdown.cjs.map +1 -1
- package/dist/data/Markdown.d.ts +3 -0
- package/dist/data/Markdown.d.ts.map +1 -1
- package/dist/data/Markdown.js +14 -40
- package/dist/data/Markdown.js.map +1 -1
- package/dist/data/TaskProgress.cjs +22 -0
- package/dist/data/TaskProgress.cjs.map +1 -1
- package/dist/data/TaskProgress.js +22 -0
- package/dist/data/TaskProgress.js.map +1 -1
- package/dist/data/TaskSnapshot.cjs.map +1 -1
- package/dist/data/TaskSnapshot.d.ts +5 -0
- package/dist/data/TaskSnapshot.d.ts.map +1 -1
- package/dist/data/TaskSnapshot.js.map +1 -1
- package/dist/data/Tree.cjs +32 -1
- package/dist/data/Tree.cjs.map +1 -1
- package/dist/data/Tree.d.ts +9 -1
- package/dist/data/Tree.d.ts.map +1 -1
- package/dist/data/Tree.js +32 -1
- package/dist/data/Tree.js.map +1 -1
- package/dist/data/chat/Attachment.cjs +79 -0
- package/dist/data/chat/Attachment.cjs.map +1 -0
- package/dist/data/chat/Attachment.d.ts +18 -0
- package/dist/data/chat/Attachment.d.ts.map +1 -0
- package/dist/data/chat/Attachment.js +79 -0
- package/dist/data/chat/Attachment.js.map +1 -0
- package/dist/data/chat/Chat.cjs +71 -14
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.d.ts +30 -12
- package/dist/data/chat/Chat.d.ts.map +1 -1
- package/dist/data/chat/Chat.fixtures.d.ts +9 -0
- package/dist/data/chat/Chat.fixtures.d.ts.map +1 -1
- package/dist/data/chat/Chat.js +73 -16
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/Conversation.cjs +32 -14
- package/dist/data/chat/Conversation.cjs.map +1 -1
- package/dist/data/chat/Conversation.d.ts +5 -3
- package/dist/data/chat/Conversation.d.ts.map +1 -1
- package/dist/data/chat/Conversation.js +34 -16
- package/dist/data/chat/Conversation.js.map +1 -1
- package/dist/data/chat/Message.cjs +73 -14
- package/dist/data/chat/Message.cjs.map +1 -1
- package/dist/data/chat/Message.d.ts +11 -4
- package/dist/data/chat/Message.d.ts.map +1 -1
- package/dist/data/chat/Message.js +75 -16
- package/dist/data/chat/Message.js.map +1 -1
- package/dist/data/chat/MessageActions.cjs +54 -0
- package/dist/data/chat/MessageActions.cjs.map +1 -0
- package/dist/data/chat/MessageActions.d.ts +11 -0
- package/dist/data/chat/MessageActions.d.ts.map +1 -0
- package/dist/data/chat/MessageActions.js +54 -0
- package/dist/data/chat/MessageActions.js.map +1 -0
- package/dist/data/chat/ModelSelector.cjs +43 -0
- package/dist/data/chat/ModelSelector.cjs.map +1 -0
- package/dist/data/chat/ModelSelector.d.ts +22 -0
- package/dist/data/chat/ModelSelector.d.ts.map +1 -0
- package/dist/data/chat/ModelSelector.js +43 -0
- package/dist/data/chat/ModelSelector.js.map +1 -0
- package/dist/data/chat/PromptInput.cjs +28 -15
- package/dist/data/chat/PromptInput.cjs.map +1 -1
- package/dist/data/chat/PromptInput.d.ts +14 -8
- package/dist/data/chat/PromptInput.d.ts.map +1 -1
- package/dist/data/chat/PromptInput.js +28 -15
- package/dist/data/chat/PromptInput.js.map +1 -1
- package/dist/data/chat/Reasoning.cjs +37 -0
- package/dist/data/chat/Reasoning.cjs.map +1 -0
- package/dist/data/chat/Reasoning.d.ts +11 -0
- package/dist/data/chat/Reasoning.d.ts.map +1 -0
- package/dist/data/chat/Reasoning.js +37 -0
- package/dist/data/chat/Reasoning.js.map +1 -0
- package/dist/data/chat/Suggestion.cjs +20 -0
- package/dist/data/chat/Suggestion.cjs.map +1 -0
- package/dist/data/chat/Suggestion.d.ts +10 -0
- package/dist/data/chat/Suggestion.d.ts.map +1 -0
- package/dist/data/chat/Suggestion.js +20 -0
- package/dist/data/chat/Suggestion.js.map +1 -0
- package/dist/data/chat/ToolCall.cjs +26 -3
- package/dist/data/chat/ToolCall.cjs.map +1 -1
- package/dist/data/chat/ToolCall.d.ts +5 -1
- package/dist/data/chat/ToolCall.d.ts.map +1 -1
- package/dist/data/chat/ToolCall.js +26 -3
- package/dist/data/chat/ToolCall.js.map +1 -1
- package/dist/data/chat/index.d.ts +7 -2
- package/dist/data/chat/index.d.ts.map +1 -1
- package/dist/data/chat/types.cjs +16 -0
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +29 -2
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js +16 -0
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.cjs +8 -1
- package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.js +8 -1
- package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
- package/dist/data/test-runner/TestRunner.cjs +6 -0
- package/dist/data/test-runner/TestRunner.cjs.map +1 -1
- package/dist/data/test-runner/TestRunner.d.ts +5 -1
- package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunner.js +6 -0
- package/dist/data/test-runner/TestRunner.js.map +1 -1
- package/dist/data/test-runner/context.cjs.map +1 -1
- package/dist/data/test-runner/context.d.ts +7 -0
- package/dist/data/test-runner/context.d.ts.map +1 -1
- package/dist/data/test-runner/context.js.map +1 -1
- package/dist/data/test-runner/index.d.ts +1 -0
- package/dist/data/test-runner/index.d.ts.map +1 -1
- package/dist/data/test-runner/routePath.cjs +39 -0
- package/dist/data/test-runner/routePath.cjs.map +1 -0
- package/dist/data/test-runner/routePath.d.ts +11 -0
- package/dist/data/test-runner/routePath.d.ts.map +1 -0
- package/dist/data/test-runner/routePath.js +39 -0
- package/dist/data/test-runner/routePath.js.map +1 -0
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +4 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.js +4 -0
- package/dist/data.js.map +1 -1
- package/dist/hooks/use-task-run.cjs +33 -20
- package/dist/hooks/use-task-run.cjs.map +1 -1
- package/dist/hooks/use-task-run.d.ts.map +1 -1
- package/dist/hooks/use-task-run.js +33 -20
- package/dist/hooks/use-task-run.js.map +1 -1
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +6 -1
|
@@ -48,6 +48,7 @@ function JsonSchemaForm({
|
|
|
48
48
|
);
|
|
49
49
|
const effectiveSize = prefs.size ?? size;
|
|
50
50
|
const resolvedLayout = resolveFormLayout(layout, inline, prefs.layoutMode);
|
|
51
|
+
const effectiveSortMode = prefs.sortMode ?? (requiredFirst ? "required-first" : "schema");
|
|
51
52
|
const applyPrefs = (next) => {
|
|
52
53
|
setPrefs(next);
|
|
53
54
|
if (persistPreferences) jsonSchemaFormPreferences.writePreferences(preferencesStorageKey, next);
|
|
@@ -57,7 +58,7 @@ function JsonSchemaForm({
|
|
|
57
58
|
hideReadOnlyFields,
|
|
58
59
|
layout: resolvedLayout,
|
|
59
60
|
size: effectiveSize,
|
|
60
|
-
|
|
61
|
+
sortMode: effectiveSortMode,
|
|
61
62
|
pre: pre ?? [],
|
|
62
63
|
post: post ?? [],
|
|
63
64
|
depth: 0,
|
|
@@ -71,8 +72,10 @@ function JsonSchemaForm({
|
|
|
71
72
|
{
|
|
72
73
|
size: effectiveSize,
|
|
73
74
|
layoutMode: resolvedLayout.mode,
|
|
75
|
+
sortMode: effectiveSortMode,
|
|
74
76
|
onSelectSize: (next) => applyPrefs({ ...prefs, size: next }),
|
|
75
|
-
onSelectLayout: (next) => applyPrefs({ ...prefs, layoutMode: next })
|
|
77
|
+
onSelectLayout: (next) => applyPrefs({ ...prefs, layoutMode: next }),
|
|
78
|
+
onSelectSort: (next) => applyPrefs({ ...prefs, sortMode: next })
|
|
76
79
|
}
|
|
77
80
|
),
|
|
78
81
|
title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: utils.cn("font-semibold", jsonSchemaFormSize.labelSizeClass[effectiveSize]), children: title }),
|
|
@@ -90,11 +93,18 @@ const LAYOUT_OPTIONS = [
|
|
|
90
93
|
{ value: "stacked", label: "Stacked" },
|
|
91
94
|
{ value: "inline", label: "Inline" }
|
|
92
95
|
];
|
|
96
|
+
const SORT_OPTIONS = [
|
|
97
|
+
{ value: "schema", label: "Schema order" },
|
|
98
|
+
{ value: "required-first", label: "Required first" },
|
|
99
|
+
{ value: "priority", label: "Required & filled first" }
|
|
100
|
+
];
|
|
93
101
|
function PreferencesMenu({
|
|
94
102
|
size,
|
|
95
103
|
layoutMode,
|
|
104
|
+
sortMode,
|
|
96
105
|
onSelectSize,
|
|
97
|
-
onSelectLayout
|
|
106
|
+
onSelectLayout,
|
|
107
|
+
onSelectSort
|
|
98
108
|
}) {
|
|
99
109
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
100
110
|
DropdownMenu.DropdownMenu,
|
|
@@ -138,6 +148,19 @@ function PreferencesMenu({
|
|
|
138
148
|
}
|
|
139
149
|
},
|
|
140
150
|
opt.value
|
|
151
|
+
)),
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsx(PreferenceSection, { title: "Sort" }),
|
|
153
|
+
SORT_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
154
|
+
PreferenceItem,
|
|
155
|
+
{
|
|
156
|
+
label: opt.label,
|
|
157
|
+
selected: opt.value === sortMode,
|
|
158
|
+
onSelect: () => {
|
|
159
|
+
onSelectSort(opt.value);
|
|
160
|
+
closeMenu();
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
opt.value
|
|
141
164
|
))
|
|
142
165
|
] })
|
|
143
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonSchemaForm.cjs","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiEllipsis } from \"../icons\";\nimport { DropdownMenu } from \"../overlay/DropdownMenu\";\nimport { FieldsGrid } from \"./json-schema-form-fields\";\nimport { renderApi, renderObjectFields } from \"./json-schema-form-render\";\nimport {\n DEFAULT_FORM_SIZE,\n fieldInnerGapClass,\n labelSizeClass,\n type FormSize,\n} from \"./json-schema-form-size\";\nimport {\n DEFAULT_PREFERENCES_STORAGE_KEY,\n readPreferences,\n writePreferences,\n type FormPreferences,\n type LayoutMode,\n} from \"./json-schema-form-preferences\";\nimport type { FormLayout, JsonSchemaFormProps, RenderContext } from \"./json-schema-form-types\";\n\nconst DEFAULT_LABEL_MAX_WIDTH = \"40ch\";\nconst DEFAULT_VALUE_MAX_WIDTH = \"600px\";\n\n// resolveFormLayout maps the `layout`/`inline` props plus an optional menu-driven\n// `modeOverride` to a single resolved FormLayout. An explicit `layout` sets the\n// base; `inline` is the shorthand for it; `modeOverride` (from the preferences\n// menu) wins over both but only flips the mode — width caps from `layout` are\n// preserved. Both modes fill valueMaxWidth (inline value column / stacked\n// label+value stack); the label cap only applies inline.\nfunction resolveFormLayout(\n layout: FormLayout | undefined,\n inline: boolean,\n modeOverride: LayoutMode | undefined,\n): FormLayout {\n const baseMode = layout?.mode ?? (inline ? \"inline\" : \"stacked\");\n const mode = modeOverride ?? baseMode;\n const valueMaxWidth = layout?.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH;\n if (mode !== \"inline\") return { mode: \"stacked\", valueMaxWidth };\n return {\n mode: \"inline\",\n labelMaxWidth: layout?.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,\n valueMaxWidth,\n };\n}\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n layout,\n size = DEFAULT_FORM_SIZE,\n idPrefix,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n showPreferencesMenu = true,\n persistPreferences = true,\n preferencesStorageKey = DEFAULT_PREFERENCES_STORAGE_KEY,\n}: JsonSchemaFormProps) {\n // When the menu is hidden, never touch localStorage and start from an empty\n // override so behaviour is identical to before this feature existed.\n const [prefs, setPrefs] = useState<FormPreferences>(() =>\n showPreferencesMenu && persistPreferences ? readPreferences(preferencesStorageKey) : {},\n );\n\n const effectiveSize = prefs.size ?? size;\n const resolvedLayout = resolveFormLayout(layout, inline, prefs.layoutMode);\n\n const applyPrefs = (next: FormPreferences) => {\n setPrefs(next);\n if (persistPreferences) writePreferences(preferencesStorageKey, next);\n };\n\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n layout: resolvedLayout,\n size: effectiveSize,\n requiredFirst,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n render: renderApi,\n ...(idPrefix ? { idPrefix } : {}),\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className={cn(\"relative flex flex-col\", fieldInnerGapClass[effectiveSize])}>\n {showPreferencesMenu && (\n <PreferencesMenu\n size={effectiveSize}\n layoutMode={resolvedLayout.mode}\n onSelectSize={(next) => applyPrefs({ ...prefs, size: next })}\n onSelectLayout={(next) => applyPrefs({ ...prefs, layoutMode: next })}\n />\n )}\n {title && <h3 className={cn(\"font-semibold\", labelSizeClass[effectiveSize])}>{title}</h3>}\n <FieldsGrid layout={resolvedLayout} size={effectiveSize}>\n {rows}\n </FieldsGrid>\n </div>\n );\n}\n\nconst SIZE_OPTIONS: { value: FormSize; label: string }[] = [\n { value: \"xs\", label: \"Extra small\" },\n { value: \"sm\", label: \"Small\" },\n { value: \"md\", label: \"Medium\" },\n { value: \"lg\", label: \"Large\" },\n { value: \"xl\", label: \"Extra large\" },\n];\n\nconst LAYOUT_OPTIONS: { value: LayoutMode; label: string }[] = [\n { value: \"stacked\", label: \"Stacked\" },\n { value: \"inline\", label: \"Inline\" },\n];\n\n// PreferencesMenu is the compact top-right ellipsis menu controlling this form's\n// size and layout mode. Selecting an item fires the matching callback and closes\n// the menu; the parent decides whether to persist.\nfunction PreferencesMenu({\n size,\n layoutMode,\n onSelectSize,\n onSelectLayout,\n}: {\n size: FormSize;\n layoutMode: LayoutMode;\n onSelectSize: (size: FormSize) => void;\n onSelectLayout: (mode: LayoutMode) => void;\n}) {\n return (\n <DropdownMenu\n align=\"right\"\n menuLabel=\"Form display options\"\n className=\"absolute right-0 top-0 z-10\"\n trigger={\n <button\n type=\"button\"\n aria-label=\"Form display options\"\n aria-haspopup=\"menu\"\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Icon icon={UiEllipsis} className=\"text-sm\" />\n </button>\n }\n >\n {(closeMenu) => (\n <>\n <PreferenceSection title=\"Size\" />\n {SIZE_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === size}\n onSelect={() => {\n onSelectSize(opt.value);\n closeMenu();\n }}\n />\n ))}\n <PreferenceSection title=\"Layout\" />\n {LAYOUT_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === layoutMode}\n onSelect={() => {\n onSelectLayout(opt.value);\n closeMenu();\n }}\n />\n ))}\n </>\n )}\n </DropdownMenu>\n );\n}\n\nfunction PreferenceSection({ title }: { title: string }) {\n return (\n <div className=\"px-3 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n );\n}\n\nfunction PreferenceItem({\n label,\n selected,\n onSelect,\n}: {\n label: string;\n selected: boolean;\n onSelect: () => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground\"\n onClick={onSelect}\n >\n <span className=\"flex w-3.5 shrink-0 justify-center\">\n {selected && <Icon icon={UiCheck} className=\"text-xs\" />}\n </span>\n {label}\n </button>\n );\n}\n"],"names":["DEFAULT_FORM_SIZE","DEFAULT_PREFERENCES_STORAGE_KEY","useState","readPreferences","writePreferences","renderApi","renderObjectFields","jsxs","cn","fieldInnerGapClass","jsx","labelSizeClass","FieldsGrid","DropdownMenu","Icon","UiEllipsis","Fragment","UiCheck"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JsonSchemaForm.cjs","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiEllipsis } from \"../icons\";\nimport { DropdownMenu } from \"../overlay/DropdownMenu\";\nimport { FieldsGrid } from \"./json-schema-form-fields\";\nimport { renderApi, renderObjectFields } from \"./json-schema-form-render\";\nimport {\n DEFAULT_FORM_SIZE,\n fieldInnerGapClass,\n labelSizeClass,\n type FormSize,\n} from \"./json-schema-form-size\";\nimport {\n DEFAULT_PREFERENCES_STORAGE_KEY,\n readPreferences,\n writePreferences,\n type FormPreferences,\n type LayoutMode,\n type SortMode,\n} from \"./json-schema-form-preferences\";\nimport type { FormLayout, JsonSchemaFormProps, RenderContext } from \"./json-schema-form-types\";\n\nconst DEFAULT_LABEL_MAX_WIDTH = \"40ch\";\nconst DEFAULT_VALUE_MAX_WIDTH = \"600px\";\n\n// resolveFormLayout maps the `layout`/`inline` props plus an optional menu-driven\n// `modeOverride` to a single resolved FormLayout. An explicit `layout` sets the\n// base; `inline` is the shorthand for it; `modeOverride` (from the preferences\n// menu) wins over both but only flips the mode — width caps from `layout` are\n// preserved. Both modes fill valueMaxWidth (inline value column / stacked\n// label+value stack); the label cap only applies inline.\nfunction resolveFormLayout(\n layout: FormLayout | undefined,\n inline: boolean,\n modeOverride: LayoutMode | undefined,\n): FormLayout {\n const baseMode = layout?.mode ?? (inline ? \"inline\" : \"stacked\");\n const mode = modeOverride ?? baseMode;\n const valueMaxWidth = layout?.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH;\n if (mode !== \"inline\") return { mode: \"stacked\", valueMaxWidth };\n return {\n mode: \"inline\",\n labelMaxWidth: layout?.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,\n valueMaxWidth,\n };\n}\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n layout,\n size = DEFAULT_FORM_SIZE,\n idPrefix,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n showPreferencesMenu = true,\n persistPreferences = true,\n preferencesStorageKey = DEFAULT_PREFERENCES_STORAGE_KEY,\n}: JsonSchemaFormProps) {\n // When the menu is hidden, never touch localStorage and start from an empty\n // override so behaviour is identical to before this feature existed.\n const [prefs, setPrefs] = useState<FormPreferences>(() =>\n showPreferencesMenu && persistPreferences ? readPreferences(preferencesStorageKey) : {},\n );\n\n const effectiveSize = prefs.size ?? size;\n const resolvedLayout = resolveFormLayout(layout, inline, prefs.layoutMode);\n // The `requiredFirst` prop sets the base sort; a menu selection overrides it.\n const effectiveSortMode = prefs.sortMode ?? (requiredFirst ? \"required-first\" : \"schema\");\n\n const applyPrefs = (next: FormPreferences) => {\n setPrefs(next);\n if (persistPreferences) writePreferences(preferencesStorageKey, next);\n };\n\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n layout: resolvedLayout,\n size: effectiveSize,\n sortMode: effectiveSortMode,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n render: renderApi,\n ...(idPrefix ? { idPrefix } : {}),\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className={cn(\"relative flex flex-col\", fieldInnerGapClass[effectiveSize])}>\n {showPreferencesMenu && (\n <PreferencesMenu\n size={effectiveSize}\n layoutMode={resolvedLayout.mode}\n sortMode={effectiveSortMode}\n onSelectSize={(next) => applyPrefs({ ...prefs, size: next })}\n onSelectLayout={(next) => applyPrefs({ ...prefs, layoutMode: next })}\n onSelectSort={(next) => applyPrefs({ ...prefs, sortMode: next })}\n />\n )}\n {title && <h3 className={cn(\"font-semibold\", labelSizeClass[effectiveSize])}>{title}</h3>}\n <FieldsGrid layout={resolvedLayout} size={effectiveSize}>\n {rows}\n </FieldsGrid>\n </div>\n );\n}\n\nconst SIZE_OPTIONS: { value: FormSize; label: string }[] = [\n { value: \"xs\", label: \"Extra small\" },\n { value: \"sm\", label: \"Small\" },\n { value: \"md\", label: \"Medium\" },\n { value: \"lg\", label: \"Large\" },\n { value: \"xl\", label: \"Extra large\" },\n];\n\nconst LAYOUT_OPTIONS: { value: LayoutMode; label: string }[] = [\n { value: \"stacked\", label: \"Stacked\" },\n { value: \"inline\", label: \"Inline\" },\n];\n\nconst SORT_OPTIONS: { value: SortMode; label: string }[] = [\n { value: \"schema\", label: \"Schema order\" },\n { value: \"required-first\", label: \"Required first\" },\n { value: \"priority\", label: \"Required & filled first\" },\n];\n\n// PreferencesMenu is the compact top-right ellipsis menu controlling this form's\n// size and layout mode. Selecting an item fires the matching callback and closes\n// the menu; the parent decides whether to persist.\nfunction PreferencesMenu({\n size,\n layoutMode,\n sortMode,\n onSelectSize,\n onSelectLayout,\n onSelectSort,\n}: {\n size: FormSize;\n layoutMode: LayoutMode;\n sortMode: SortMode;\n onSelectSize: (size: FormSize) => void;\n onSelectLayout: (mode: LayoutMode) => void;\n onSelectSort: (mode: SortMode) => void;\n}) {\n return (\n <DropdownMenu\n align=\"right\"\n menuLabel=\"Form display options\"\n className=\"absolute right-0 top-0 z-10\"\n trigger={\n <button\n type=\"button\"\n aria-label=\"Form display options\"\n aria-haspopup=\"menu\"\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Icon icon={UiEllipsis} className=\"text-sm\" />\n </button>\n }\n >\n {(closeMenu) => (\n <>\n <PreferenceSection title=\"Size\" />\n {SIZE_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === size}\n onSelect={() => {\n onSelectSize(opt.value);\n closeMenu();\n }}\n />\n ))}\n <PreferenceSection title=\"Layout\" />\n {LAYOUT_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === layoutMode}\n onSelect={() => {\n onSelectLayout(opt.value);\n closeMenu();\n }}\n />\n ))}\n <PreferenceSection title=\"Sort\" />\n {SORT_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === sortMode}\n onSelect={() => {\n onSelectSort(opt.value);\n closeMenu();\n }}\n />\n ))}\n </>\n )}\n </DropdownMenu>\n );\n}\n\nfunction PreferenceSection({ title }: { title: string }) {\n return (\n <div className=\"px-3 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n );\n}\n\nfunction PreferenceItem({\n label,\n selected,\n onSelect,\n}: {\n label: string;\n selected: boolean;\n onSelect: () => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground\"\n onClick={onSelect}\n >\n <span className=\"flex w-3.5 shrink-0 justify-center\">\n {selected && <Icon icon={UiCheck} className=\"text-xs\" />}\n </span>\n {label}\n </button>\n );\n}\n"],"names":["DEFAULT_FORM_SIZE","DEFAULT_PREFERENCES_STORAGE_KEY","useState","readPreferences","writePreferences","renderApi","renderObjectFields","jsxs","cn","fieldInnerGapClass","jsx","labelSizeClass","FieldsGrid","DropdownMenu","Icon","UiEllipsis","Fragment","UiCheck"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonSchemaForm.d.ts","sourceRoot":"","sources":["../../src/components/JsonSchemaForm.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"JsonSchemaForm.d.ts","sourceRoot":"","sources":["../../src/components/JsonSchemaForm.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAc,mBAAmB,EAAiB,MAAM,0BAA0B,CAAC;AAgC/F,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,MAAc,EACd,MAAM,EACN,IAAwB,EACxB,QAAQ,EACR,kBAA0B,EAC1B,UAAU,EACV,aAAqB,EACrB,KAAK,EACL,GAAG,EACH,IAAI,EACJ,mBAA0B,EAC1B,kBAAyB,EACzB,qBAAuD,GACxD,EAAE,mBAAmB,2CAiDrB"}
|
|
@@ -46,6 +46,7 @@ function JsonSchemaForm({
|
|
|
46
46
|
);
|
|
47
47
|
const effectiveSize = prefs.size ?? size;
|
|
48
48
|
const resolvedLayout = resolveFormLayout(layout, inline, prefs.layoutMode);
|
|
49
|
+
const effectiveSortMode = prefs.sortMode ?? (requiredFirst ? "required-first" : "schema");
|
|
49
50
|
const applyPrefs = (next) => {
|
|
50
51
|
setPrefs(next);
|
|
51
52
|
if (persistPreferences) writePreferences(preferencesStorageKey, next);
|
|
@@ -55,7 +56,7 @@ function JsonSchemaForm({
|
|
|
55
56
|
hideReadOnlyFields,
|
|
56
57
|
layout: resolvedLayout,
|
|
57
58
|
size: effectiveSize,
|
|
58
|
-
|
|
59
|
+
sortMode: effectiveSortMode,
|
|
59
60
|
pre: pre ?? [],
|
|
60
61
|
post: post ?? [],
|
|
61
62
|
depth: 0,
|
|
@@ -69,8 +70,10 @@ function JsonSchemaForm({
|
|
|
69
70
|
{
|
|
70
71
|
size: effectiveSize,
|
|
71
72
|
layoutMode: resolvedLayout.mode,
|
|
73
|
+
sortMode: effectiveSortMode,
|
|
72
74
|
onSelectSize: (next) => applyPrefs({ ...prefs, size: next }),
|
|
73
|
-
onSelectLayout: (next) => applyPrefs({ ...prefs, layoutMode: next })
|
|
75
|
+
onSelectLayout: (next) => applyPrefs({ ...prefs, layoutMode: next }),
|
|
76
|
+
onSelectSort: (next) => applyPrefs({ ...prefs, sortMode: next })
|
|
74
77
|
}
|
|
75
78
|
),
|
|
76
79
|
title && /* @__PURE__ */ jsx("h3", { className: cn("font-semibold", labelSizeClass[effectiveSize]), children: title }),
|
|
@@ -88,11 +91,18 @@ const LAYOUT_OPTIONS = [
|
|
|
88
91
|
{ value: "stacked", label: "Stacked" },
|
|
89
92
|
{ value: "inline", label: "Inline" }
|
|
90
93
|
];
|
|
94
|
+
const SORT_OPTIONS = [
|
|
95
|
+
{ value: "schema", label: "Schema order" },
|
|
96
|
+
{ value: "required-first", label: "Required first" },
|
|
97
|
+
{ value: "priority", label: "Required & filled first" }
|
|
98
|
+
];
|
|
91
99
|
function PreferencesMenu({
|
|
92
100
|
size,
|
|
93
101
|
layoutMode,
|
|
102
|
+
sortMode,
|
|
94
103
|
onSelectSize,
|
|
95
|
-
onSelectLayout
|
|
104
|
+
onSelectLayout,
|
|
105
|
+
onSelectSort
|
|
96
106
|
}) {
|
|
97
107
|
return /* @__PURE__ */ jsx(
|
|
98
108
|
DropdownMenu,
|
|
@@ -136,6 +146,19 @@ function PreferencesMenu({
|
|
|
136
146
|
}
|
|
137
147
|
},
|
|
138
148
|
opt.value
|
|
149
|
+
)),
|
|
150
|
+
/* @__PURE__ */ jsx(PreferenceSection, { title: "Sort" }),
|
|
151
|
+
SORT_OPTIONS.map((opt) => /* @__PURE__ */ jsx(
|
|
152
|
+
PreferenceItem,
|
|
153
|
+
{
|
|
154
|
+
label: opt.label,
|
|
155
|
+
selected: opt.value === sortMode,
|
|
156
|
+
onSelect: () => {
|
|
157
|
+
onSelectSort(opt.value);
|
|
158
|
+
closeMenu();
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
opt.value
|
|
139
162
|
))
|
|
140
163
|
] })
|
|
141
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonSchemaForm.js","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiEllipsis } from \"../icons\";\nimport { DropdownMenu } from \"../overlay/DropdownMenu\";\nimport { FieldsGrid } from \"./json-schema-form-fields\";\nimport { renderApi, renderObjectFields } from \"./json-schema-form-render\";\nimport {\n DEFAULT_FORM_SIZE,\n fieldInnerGapClass,\n labelSizeClass,\n type FormSize,\n} from \"./json-schema-form-size\";\nimport {\n DEFAULT_PREFERENCES_STORAGE_KEY,\n readPreferences,\n writePreferences,\n type FormPreferences,\n type LayoutMode,\n} from \"./json-schema-form-preferences\";\nimport type { FormLayout, JsonSchemaFormProps, RenderContext } from \"./json-schema-form-types\";\n\nconst DEFAULT_LABEL_MAX_WIDTH = \"40ch\";\nconst DEFAULT_VALUE_MAX_WIDTH = \"600px\";\n\n// resolveFormLayout maps the `layout`/`inline` props plus an optional menu-driven\n// `modeOverride` to a single resolved FormLayout. An explicit `layout` sets the\n// base; `inline` is the shorthand for it; `modeOverride` (from the preferences\n// menu) wins over both but only flips the mode — width caps from `layout` are\n// preserved. Both modes fill valueMaxWidth (inline value column / stacked\n// label+value stack); the label cap only applies inline.\nfunction resolveFormLayout(\n layout: FormLayout | undefined,\n inline: boolean,\n modeOverride: LayoutMode | undefined,\n): FormLayout {\n const baseMode = layout?.mode ?? (inline ? \"inline\" : \"stacked\");\n const mode = modeOverride ?? baseMode;\n const valueMaxWidth = layout?.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH;\n if (mode !== \"inline\") return { mode: \"stacked\", valueMaxWidth };\n return {\n mode: \"inline\",\n labelMaxWidth: layout?.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,\n valueMaxWidth,\n };\n}\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n layout,\n size = DEFAULT_FORM_SIZE,\n idPrefix,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n showPreferencesMenu = true,\n persistPreferences = true,\n preferencesStorageKey = DEFAULT_PREFERENCES_STORAGE_KEY,\n}: JsonSchemaFormProps) {\n // When the menu is hidden, never touch localStorage and start from an empty\n // override so behaviour is identical to before this feature existed.\n const [prefs, setPrefs] = useState<FormPreferences>(() =>\n showPreferencesMenu && persistPreferences ? readPreferences(preferencesStorageKey) : {},\n );\n\n const effectiveSize = prefs.size ?? size;\n const resolvedLayout = resolveFormLayout(layout, inline, prefs.layoutMode);\n\n const applyPrefs = (next: FormPreferences) => {\n setPrefs(next);\n if (persistPreferences) writePreferences(preferencesStorageKey, next);\n };\n\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n layout: resolvedLayout,\n size: effectiveSize,\n requiredFirst,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n render: renderApi,\n ...(idPrefix ? { idPrefix } : {}),\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className={cn(\"relative flex flex-col\", fieldInnerGapClass[effectiveSize])}>\n {showPreferencesMenu && (\n <PreferencesMenu\n size={effectiveSize}\n layoutMode={resolvedLayout.mode}\n onSelectSize={(next) => applyPrefs({ ...prefs, size: next })}\n onSelectLayout={(next) => applyPrefs({ ...prefs, layoutMode: next })}\n />\n )}\n {title && <h3 className={cn(\"font-semibold\", labelSizeClass[effectiveSize])}>{title}</h3>}\n <FieldsGrid layout={resolvedLayout} size={effectiveSize}>\n {rows}\n </FieldsGrid>\n </div>\n );\n}\n\nconst SIZE_OPTIONS: { value: FormSize; label: string }[] = [\n { value: \"xs\", label: \"Extra small\" },\n { value: \"sm\", label: \"Small\" },\n { value: \"md\", label: \"Medium\" },\n { value: \"lg\", label: \"Large\" },\n { value: \"xl\", label: \"Extra large\" },\n];\n\nconst LAYOUT_OPTIONS: { value: LayoutMode; label: string }[] = [\n { value: \"stacked\", label: \"Stacked\" },\n { value: \"inline\", label: \"Inline\" },\n];\n\n// PreferencesMenu is the compact top-right ellipsis menu controlling this form's\n// size and layout mode. Selecting an item fires the matching callback and closes\n// the menu; the parent decides whether to persist.\nfunction PreferencesMenu({\n size,\n layoutMode,\n onSelectSize,\n onSelectLayout,\n}: {\n size: FormSize;\n layoutMode: LayoutMode;\n onSelectSize: (size: FormSize) => void;\n onSelectLayout: (mode: LayoutMode) => void;\n}) {\n return (\n <DropdownMenu\n align=\"right\"\n menuLabel=\"Form display options\"\n className=\"absolute right-0 top-0 z-10\"\n trigger={\n <button\n type=\"button\"\n aria-label=\"Form display options\"\n aria-haspopup=\"menu\"\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Icon icon={UiEllipsis} className=\"text-sm\" />\n </button>\n }\n >\n {(closeMenu) => (\n <>\n <PreferenceSection title=\"Size\" />\n {SIZE_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === size}\n onSelect={() => {\n onSelectSize(opt.value);\n closeMenu();\n }}\n />\n ))}\n <PreferenceSection title=\"Layout\" />\n {LAYOUT_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === layoutMode}\n onSelect={() => {\n onSelectLayout(opt.value);\n closeMenu();\n }}\n />\n ))}\n </>\n )}\n </DropdownMenu>\n );\n}\n\nfunction PreferenceSection({ title }: { title: string }) {\n return (\n <div className=\"px-3 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n );\n}\n\nfunction PreferenceItem({\n label,\n selected,\n onSelect,\n}: {\n label: string;\n selected: boolean;\n onSelect: () => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground\"\n onClick={onSelect}\n >\n <span className=\"flex w-3.5 shrink-0 justify-center\">\n {selected && <Icon icon={UiCheck} className=\"text-xs\" />}\n </span>\n {label}\n </button>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JsonSchemaForm.js","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"../data/Icon\";\nimport { UiCheck, UiEllipsis } from \"../icons\";\nimport { DropdownMenu } from \"../overlay/DropdownMenu\";\nimport { FieldsGrid } from \"./json-schema-form-fields\";\nimport { renderApi, renderObjectFields } from \"./json-schema-form-render\";\nimport {\n DEFAULT_FORM_SIZE,\n fieldInnerGapClass,\n labelSizeClass,\n type FormSize,\n} from \"./json-schema-form-size\";\nimport {\n DEFAULT_PREFERENCES_STORAGE_KEY,\n readPreferences,\n writePreferences,\n type FormPreferences,\n type LayoutMode,\n type SortMode,\n} from \"./json-schema-form-preferences\";\nimport type { FormLayout, JsonSchemaFormProps, RenderContext } from \"./json-schema-form-types\";\n\nconst DEFAULT_LABEL_MAX_WIDTH = \"40ch\";\nconst DEFAULT_VALUE_MAX_WIDTH = \"600px\";\n\n// resolveFormLayout maps the `layout`/`inline` props plus an optional menu-driven\n// `modeOverride` to a single resolved FormLayout. An explicit `layout` sets the\n// base; `inline` is the shorthand for it; `modeOverride` (from the preferences\n// menu) wins over both but only flips the mode — width caps from `layout` are\n// preserved. Both modes fill valueMaxWidth (inline value column / stacked\n// label+value stack); the label cap only applies inline.\nfunction resolveFormLayout(\n layout: FormLayout | undefined,\n inline: boolean,\n modeOverride: LayoutMode | undefined,\n): FormLayout {\n const baseMode = layout?.mode ?? (inline ? \"inline\" : \"stacked\");\n const mode = modeOverride ?? baseMode;\n const valueMaxWidth = layout?.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH;\n if (mode !== \"inline\") return { mode: \"stacked\", valueMaxWidth };\n return {\n mode: \"inline\",\n labelMaxWidth: layout?.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,\n valueMaxWidth,\n };\n}\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n layout,\n size = DEFAULT_FORM_SIZE,\n idPrefix,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n showPreferencesMenu = true,\n persistPreferences = true,\n preferencesStorageKey = DEFAULT_PREFERENCES_STORAGE_KEY,\n}: JsonSchemaFormProps) {\n // When the menu is hidden, never touch localStorage and start from an empty\n // override so behaviour is identical to before this feature existed.\n const [prefs, setPrefs] = useState<FormPreferences>(() =>\n showPreferencesMenu && persistPreferences ? readPreferences(preferencesStorageKey) : {},\n );\n\n const effectiveSize = prefs.size ?? size;\n const resolvedLayout = resolveFormLayout(layout, inline, prefs.layoutMode);\n // The `requiredFirst` prop sets the base sort; a menu selection overrides it.\n const effectiveSortMode = prefs.sortMode ?? (requiredFirst ? \"required-first\" : \"schema\");\n\n const applyPrefs = (next: FormPreferences) => {\n setPrefs(next);\n if (persistPreferences) writePreferences(preferencesStorageKey, next);\n };\n\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n layout: resolvedLayout,\n size: effectiveSize,\n sortMode: effectiveSortMode,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n render: renderApi,\n ...(idPrefix ? { idPrefix } : {}),\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className={cn(\"relative flex flex-col\", fieldInnerGapClass[effectiveSize])}>\n {showPreferencesMenu && (\n <PreferencesMenu\n size={effectiveSize}\n layoutMode={resolvedLayout.mode}\n sortMode={effectiveSortMode}\n onSelectSize={(next) => applyPrefs({ ...prefs, size: next })}\n onSelectLayout={(next) => applyPrefs({ ...prefs, layoutMode: next })}\n onSelectSort={(next) => applyPrefs({ ...prefs, sortMode: next })}\n />\n )}\n {title && <h3 className={cn(\"font-semibold\", labelSizeClass[effectiveSize])}>{title}</h3>}\n <FieldsGrid layout={resolvedLayout} size={effectiveSize}>\n {rows}\n </FieldsGrid>\n </div>\n );\n}\n\nconst SIZE_OPTIONS: { value: FormSize; label: string }[] = [\n { value: \"xs\", label: \"Extra small\" },\n { value: \"sm\", label: \"Small\" },\n { value: \"md\", label: \"Medium\" },\n { value: \"lg\", label: \"Large\" },\n { value: \"xl\", label: \"Extra large\" },\n];\n\nconst LAYOUT_OPTIONS: { value: LayoutMode; label: string }[] = [\n { value: \"stacked\", label: \"Stacked\" },\n { value: \"inline\", label: \"Inline\" },\n];\n\nconst SORT_OPTIONS: { value: SortMode; label: string }[] = [\n { value: \"schema\", label: \"Schema order\" },\n { value: \"required-first\", label: \"Required first\" },\n { value: \"priority\", label: \"Required & filled first\" },\n];\n\n// PreferencesMenu is the compact top-right ellipsis menu controlling this form's\n// size and layout mode. Selecting an item fires the matching callback and closes\n// the menu; the parent decides whether to persist.\nfunction PreferencesMenu({\n size,\n layoutMode,\n sortMode,\n onSelectSize,\n onSelectLayout,\n onSelectSort,\n}: {\n size: FormSize;\n layoutMode: LayoutMode;\n sortMode: SortMode;\n onSelectSize: (size: FormSize) => void;\n onSelectLayout: (mode: LayoutMode) => void;\n onSelectSort: (mode: SortMode) => void;\n}) {\n return (\n <DropdownMenu\n align=\"right\"\n menuLabel=\"Form display options\"\n className=\"absolute right-0 top-0 z-10\"\n trigger={\n <button\n type=\"button\"\n aria-label=\"Form display options\"\n aria-haspopup=\"menu\"\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Icon icon={UiEllipsis} className=\"text-sm\" />\n </button>\n }\n >\n {(closeMenu) => (\n <>\n <PreferenceSection title=\"Size\" />\n {SIZE_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === size}\n onSelect={() => {\n onSelectSize(opt.value);\n closeMenu();\n }}\n />\n ))}\n <PreferenceSection title=\"Layout\" />\n {LAYOUT_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === layoutMode}\n onSelect={() => {\n onSelectLayout(opt.value);\n closeMenu();\n }}\n />\n ))}\n <PreferenceSection title=\"Sort\" />\n {SORT_OPTIONS.map((opt) => (\n <PreferenceItem\n key={opt.value}\n label={opt.label}\n selected={opt.value === sortMode}\n onSelect={() => {\n onSelectSort(opt.value);\n closeMenu();\n }}\n />\n ))}\n </>\n )}\n </DropdownMenu>\n );\n}\n\nfunction PreferenceSection({ title }: { title: string }) {\n return (\n <div className=\"px-3 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n );\n}\n\nfunction PreferenceItem({\n label,\n selected,\n onSelect,\n}: {\n label: string;\n selected: boolean;\n onSelect: () => void;\n}) {\n return (\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground\"\n onClick={onSelect}\n >\n <span className=\"flex w-3.5 shrink-0 justify-center\">\n {selected && <Icon icon={UiCheck} className=\"text-xs\" />}\n </span>\n {label}\n </button>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,9 @@ function isFormSize(value) {
|
|
|
8
8
|
function isLayoutMode(value) {
|
|
9
9
|
return value === "stacked" || value === "inline";
|
|
10
10
|
}
|
|
11
|
+
function isSortMode(value) {
|
|
12
|
+
return value === "schema" || value === "required-first" || value === "priority";
|
|
13
|
+
}
|
|
11
14
|
function readPreferences(storageKey) {
|
|
12
15
|
let raw;
|
|
13
16
|
try {
|
|
@@ -27,6 +30,7 @@ function readPreferences(storageKey) {
|
|
|
27
30
|
const prefs = {};
|
|
28
31
|
if (isFormSize(record.size)) prefs.size = record.size;
|
|
29
32
|
if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;
|
|
33
|
+
if (isSortMode(record.sortMode)) prefs.sortMode = record.sortMode;
|
|
30
34
|
return prefs;
|
|
31
35
|
}
|
|
32
36
|
function writePreferences(storageKey, prefs) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-preferences.cjs","sources":["../../src/components/json-schema-form-preferences.ts"],"sourcesContent":["import type { FormSize } from \"./json-schema-form-size\";\n\n// FormPreferences are the form-local appearance overrides the display-options\n// menu persists: the input/label scale and the layout mode. They never touch\n// field values or the global page density — only how one form looks.\nexport interface FormPreferences {\n size?: FormSize;\n layoutMode?: LayoutMode;\n}\n\nexport type LayoutMode = \"stacked\" | \"inline\";\n\nexport const DEFAULT_PREFERENCES_STORAGE_KEY = \"clicky-ui-json-schema-form-preferences\";\n\nconst VALID_SIZES: readonly string[] = [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"];\n\nfunction isFormSize(value: unknown): value is FormSize {\n return typeof value === \"string\" && VALID_SIZES.includes(value);\n}\n\nfunction isLayoutMode(value: unknown): value is LayoutMode {\n return value === \"stacked\" || value === \"inline\";\n}\n\n// readPreferences loads stored preferences, tolerating anything malformed: a\n// missing key, invalid JSON, a non-object payload, out-of-range values, or a\n// localStorage that throws (private mode / storage disabled). Each field is\n// validated independently so one bad value doesn't discard the whole record.\n// Display preferences are best-effort, so a read failure yields {} rather than\n// an error — the form falls back to its props.\nexport function readPreferences(storageKey: string): FormPreferences {\n let raw: string | null;\n try {\n raw = localStorage.getItem(storageKey);\n } catch {\n return {};\n }\n if (!raw) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return {};\n }\n if (typeof parsed !== \"object\" || parsed === null) return {};\n\n const record = parsed as Record<string, unknown>;\n const prefs: FormPreferences = {};\n if (isFormSize(record.size)) prefs.size = record.size;\n if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;\n return prefs;\n}\n\n// writePreferences persists the record as JSON, swallowing localStorage errors\n// (quota exceeded / storage disabled). Like reads, persistence is best-effort:\n// failing to save a display preference must never break the form.\nexport function writePreferences(storageKey: string, prefs: FormPreferences): void {\n try {\n localStorage.setItem(storageKey, JSON.stringify(prefs));\n } catch {\n // Best-effort persistence; ignore storage failures.\n }\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"json-schema-form-preferences.cjs","sources":["../../src/components/json-schema-form-preferences.ts"],"sourcesContent":["import type { FormSize } from \"./json-schema-form-size\";\n\n// FormPreferences are the form-local appearance overrides the display-options\n// menu persists: the input/label scale and the layout mode. They never touch\n// field values or the global page density — only how one form looks.\nexport interface FormPreferences {\n size?: FormSize;\n layoutMode?: LayoutMode;\n sortMode?: SortMode;\n}\n\nexport type LayoutMode = \"stacked\" | \"inline\";\n\n// SortMode controls the order fields render in at every object level:\n// - \"schema\": schema/x-order order (the default).\n// - \"required-first\": required keys first, then optional, each group stable.\n// - \"priority\": required AND non-empty keys bubble to the top — required-and-\n// filled, then required-and-empty, then optional-and-filled, then the rest.\nexport type SortMode = \"schema\" | \"required-first\" | \"priority\";\n\nexport const DEFAULT_PREFERENCES_STORAGE_KEY = \"clicky-ui-json-schema-form-preferences\";\n\nconst VALID_SIZES: readonly string[] = [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"];\n\nfunction isFormSize(value: unknown): value is FormSize {\n return typeof value === \"string\" && VALID_SIZES.includes(value);\n}\n\nfunction isLayoutMode(value: unknown): value is LayoutMode {\n return value === \"stacked\" || value === \"inline\";\n}\n\nfunction isSortMode(value: unknown): value is SortMode {\n return value === \"schema\" || value === \"required-first\" || value === \"priority\";\n}\n\n// readPreferences loads stored preferences, tolerating anything malformed: a\n// missing key, invalid JSON, a non-object payload, out-of-range values, or a\n// localStorage that throws (private mode / storage disabled). Each field is\n// validated independently so one bad value doesn't discard the whole record.\n// Display preferences are best-effort, so a read failure yields {} rather than\n// an error — the form falls back to its props.\nexport function readPreferences(storageKey: string): FormPreferences {\n let raw: string | null;\n try {\n raw = localStorage.getItem(storageKey);\n } catch {\n return {};\n }\n if (!raw) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return {};\n }\n if (typeof parsed !== \"object\" || parsed === null) return {};\n\n const record = parsed as Record<string, unknown>;\n const prefs: FormPreferences = {};\n if (isFormSize(record.size)) prefs.size = record.size;\n if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;\n if (isSortMode(record.sortMode)) prefs.sortMode = record.sortMode;\n return prefs;\n}\n\n// writePreferences persists the record as JSON, swallowing localStorage errors\n// (quota exceeded / storage disabled). Like reads, persistence is best-effort:\n// failing to save a display preference must never break the form.\nexport function writePreferences(storageKey: string, prefs: FormPreferences): void {\n try {\n localStorage.setItem(storageKey, JSON.stringify(prefs));\n } catch {\n // Best-effort persistence; ignore storage failures.\n }\n}\n"],"names":[],"mappings":";;AAoBO,MAAM,kCAAkC;AAE/C,MAAM,cAAiC,CAAC,MAAM,MAAM,MAAM,MAAM,IAAI;AAEpE,SAAS,WAAW,OAAmC;AACrD,SAAO,OAAO,UAAU,YAAY,YAAY,SAAS,KAAK;AAChE;AAEA,SAAS,aAAa,OAAqC;AACzD,SAAO,UAAU,aAAa,UAAU;AAC1C;AAEA,SAAS,WAAW,OAAmC;AACrD,SAAO,UAAU,YAAY,UAAU,oBAAoB,UAAU;AACvE;AAQO,SAAS,gBAAgB,YAAqC;AACnE,MAAI;AACJ,MAAI;AACF,UAAM,aAAa,QAAQ,UAAU;AAAA,EACvC,QAAQ;AACN,WAAO,CAAA;AAAA,EACT;AACA,MAAI,CAAC,IAAK,QAAO,CAAA;AAEjB,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,WAAO,CAAA;AAAA,EACT;AACA,MAAI,OAAO,WAAW,YAAY,WAAW,aAAa,CAAA;AAE1D,QAAM,SAAS;AACf,QAAM,QAAyB,CAAA;AAC/B,MAAI,WAAW,OAAO,IAAI,EAAG,OAAM,OAAO,OAAO;AACjD,MAAI,aAAa,OAAO,UAAU,EAAG,OAAM,aAAa,OAAO;AAC/D,MAAI,WAAW,OAAO,QAAQ,EAAG,OAAM,WAAW,OAAO;AACzD,SAAO;AACT;AAKO,SAAS,iBAAiB,YAAoB,OAA8B;AACjF,MAAI;AACF,iBAAa,QAAQ,YAAY,KAAK,UAAU,KAAK,CAAC;AAAA,EACxD,QAAQ;AAAA,EAER;AACF;;;;"}
|
|
@@ -2,8 +2,10 @@ import { FormSize } from './json-schema-form-size';
|
|
|
2
2
|
export interface FormPreferences {
|
|
3
3
|
size?: FormSize;
|
|
4
4
|
layoutMode?: LayoutMode;
|
|
5
|
+
sortMode?: SortMode;
|
|
5
6
|
}
|
|
6
7
|
export type LayoutMode = "stacked" | "inline";
|
|
8
|
+
export type SortMode = "schema" | "required-first" | "priority";
|
|
7
9
|
export declare const DEFAULT_PREFERENCES_STORAGE_KEY = "clicky-ui-json-schema-form-preferences";
|
|
8
10
|
export declare function readPreferences(storageKey: string): FormPreferences;
|
|
9
11
|
export declare function writePreferences(storageKey: string, prefs: FormPreferences): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-preferences.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-preferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAKxD,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"json-schema-form-preferences.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-preferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAKxD,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAO9C,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,gBAAgB,GAAG,UAAU,CAAC;AAEhE,eAAO,MAAM,+BAA+B,2CAA2C,CAAC;AAsBxF,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAuBnE;AAKD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAMjF"}
|
|
@@ -6,6 +6,9 @@ function isFormSize(value) {
|
|
|
6
6
|
function isLayoutMode(value) {
|
|
7
7
|
return value === "stacked" || value === "inline";
|
|
8
8
|
}
|
|
9
|
+
function isSortMode(value) {
|
|
10
|
+
return value === "schema" || value === "required-first" || value === "priority";
|
|
11
|
+
}
|
|
9
12
|
function readPreferences(storageKey) {
|
|
10
13
|
let raw;
|
|
11
14
|
try {
|
|
@@ -25,6 +28,7 @@ function readPreferences(storageKey) {
|
|
|
25
28
|
const prefs = {};
|
|
26
29
|
if (isFormSize(record.size)) prefs.size = record.size;
|
|
27
30
|
if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;
|
|
31
|
+
if (isSortMode(record.sortMode)) prefs.sortMode = record.sortMode;
|
|
28
32
|
return prefs;
|
|
29
33
|
}
|
|
30
34
|
function writePreferences(storageKey, prefs) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-preferences.js","sources":["../../src/components/json-schema-form-preferences.ts"],"sourcesContent":["import type { FormSize } from \"./json-schema-form-size\";\n\n// FormPreferences are the form-local appearance overrides the display-options\n// menu persists: the input/label scale and the layout mode. They never touch\n// field values or the global page density — only how one form looks.\nexport interface FormPreferences {\n size?: FormSize;\n layoutMode?: LayoutMode;\n}\n\nexport type LayoutMode = \"stacked\" | \"inline\";\n\nexport const DEFAULT_PREFERENCES_STORAGE_KEY = \"clicky-ui-json-schema-form-preferences\";\n\nconst VALID_SIZES: readonly string[] = [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"];\n\nfunction isFormSize(value: unknown): value is FormSize {\n return typeof value === \"string\" && VALID_SIZES.includes(value);\n}\n\nfunction isLayoutMode(value: unknown): value is LayoutMode {\n return value === \"stacked\" || value === \"inline\";\n}\n\n// readPreferences loads stored preferences, tolerating anything malformed: a\n// missing key, invalid JSON, a non-object payload, out-of-range values, or a\n// localStorage that throws (private mode / storage disabled). Each field is\n// validated independently so one bad value doesn't discard the whole record.\n// Display preferences are best-effort, so a read failure yields {} rather than\n// an error — the form falls back to its props.\nexport function readPreferences(storageKey: string): FormPreferences {\n let raw: string | null;\n try {\n raw = localStorage.getItem(storageKey);\n } catch {\n return {};\n }\n if (!raw) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return {};\n }\n if (typeof parsed !== \"object\" || parsed === null) return {};\n\n const record = parsed as Record<string, unknown>;\n const prefs: FormPreferences = {};\n if (isFormSize(record.size)) prefs.size = record.size;\n if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;\n return prefs;\n}\n\n// writePreferences persists the record as JSON, swallowing localStorage errors\n// (quota exceeded / storage disabled). Like reads, persistence is best-effort:\n// failing to save a display preference must never break the form.\nexport function writePreferences(storageKey: string, prefs: FormPreferences): void {\n try {\n localStorage.setItem(storageKey, JSON.stringify(prefs));\n } catch {\n // Best-effort persistence; ignore storage failures.\n }\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"json-schema-form-preferences.js","sources":["../../src/components/json-schema-form-preferences.ts"],"sourcesContent":["import type { FormSize } from \"./json-schema-form-size\";\n\n// FormPreferences are the form-local appearance overrides the display-options\n// menu persists: the input/label scale and the layout mode. They never touch\n// field values or the global page density — only how one form looks.\nexport interface FormPreferences {\n size?: FormSize;\n layoutMode?: LayoutMode;\n sortMode?: SortMode;\n}\n\nexport type LayoutMode = \"stacked\" | \"inline\";\n\n// SortMode controls the order fields render in at every object level:\n// - \"schema\": schema/x-order order (the default).\n// - \"required-first\": required keys first, then optional, each group stable.\n// - \"priority\": required AND non-empty keys bubble to the top — required-and-\n// filled, then required-and-empty, then optional-and-filled, then the rest.\nexport type SortMode = \"schema\" | \"required-first\" | \"priority\";\n\nexport const DEFAULT_PREFERENCES_STORAGE_KEY = \"clicky-ui-json-schema-form-preferences\";\n\nconst VALID_SIZES: readonly string[] = [\"xs\", \"sm\", \"md\", \"lg\", \"xl\"];\n\nfunction isFormSize(value: unknown): value is FormSize {\n return typeof value === \"string\" && VALID_SIZES.includes(value);\n}\n\nfunction isLayoutMode(value: unknown): value is LayoutMode {\n return value === \"stacked\" || value === \"inline\";\n}\n\nfunction isSortMode(value: unknown): value is SortMode {\n return value === \"schema\" || value === \"required-first\" || value === \"priority\";\n}\n\n// readPreferences loads stored preferences, tolerating anything malformed: a\n// missing key, invalid JSON, a non-object payload, out-of-range values, or a\n// localStorage that throws (private mode / storage disabled). Each field is\n// validated independently so one bad value doesn't discard the whole record.\n// Display preferences are best-effort, so a read failure yields {} rather than\n// an error — the form falls back to its props.\nexport function readPreferences(storageKey: string): FormPreferences {\n let raw: string | null;\n try {\n raw = localStorage.getItem(storageKey);\n } catch {\n return {};\n }\n if (!raw) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return {};\n }\n if (typeof parsed !== \"object\" || parsed === null) return {};\n\n const record = parsed as Record<string, unknown>;\n const prefs: FormPreferences = {};\n if (isFormSize(record.size)) prefs.size = record.size;\n if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;\n if (isSortMode(record.sortMode)) prefs.sortMode = record.sortMode;\n return prefs;\n}\n\n// writePreferences persists the record as JSON, swallowing localStorage errors\n// (quota exceeded / storage disabled). Like reads, persistence is best-effort:\n// failing to save a display preference must never break the form.\nexport function writePreferences(storageKey: string, prefs: FormPreferences): void {\n try {\n localStorage.setItem(storageKey, JSON.stringify(prefs));\n } catch {\n // Best-effort persistence; ignore storage failures.\n }\n}\n"],"names":[],"mappings":"AAoBO,MAAM,kCAAkC;AAE/C,MAAM,cAAiC,CAAC,MAAM,MAAM,MAAM,MAAM,IAAI;AAEpE,SAAS,WAAW,OAAmC;AACrD,SAAO,OAAO,UAAU,YAAY,YAAY,SAAS,KAAK;AAChE;AAEA,SAAS,aAAa,OAAqC;AACzD,SAAO,UAAU,aAAa,UAAU;AAC1C;AAEA,SAAS,WAAW,OAAmC;AACrD,SAAO,UAAU,YAAY,UAAU,oBAAoB,UAAU;AACvE;AAQO,SAAS,gBAAgB,YAAqC;AACnE,MAAI;AACJ,MAAI;AACF,UAAM,aAAa,QAAQ,UAAU;AAAA,EACvC,QAAQ;AACN,WAAO,CAAA;AAAA,EACT;AACA,MAAI,CAAC,IAAK,QAAO,CAAA;AAEjB,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,WAAO,CAAA;AAAA,EACT;AACA,MAAI,OAAO,WAAW,YAAY,WAAW,aAAa,CAAA;AAE1D,QAAM,SAAS;AACf,QAAM,QAAyB,CAAA;AAC/B,MAAI,WAAW,OAAO,IAAI,EAAG,OAAM,OAAO,OAAO;AACjD,MAAI,aAAa,OAAO,UAAU,EAAG,OAAM,aAAa,OAAO;AAC/D,MAAI,WAAW,OAAO,QAAQ,EAAG,OAAM,WAAW,OAAO;AACzD,SAAO;AACT;AAKO,SAAS,iBAAiB,YAAoB,OAA8B;AACjF,MAAI;AACF,iBAAa,QAAQ,YAAY,KAAK,UAAU,KAAK,CAAC;AAAA,EACxD,QAAQ;AAAA,EAER;AACF;"}
|
|
@@ -103,7 +103,7 @@ function renderObjectFields(schema, value, onChange, ctx, opts) {
|
|
|
103
103
|
const { properties, required } = jsonSchemaFormResolve.effectiveProperties(schema, value);
|
|
104
104
|
const hidden = new Set((opts == null ? void 0 : opts.hiddenKeys) ?? []);
|
|
105
105
|
const ordered = jsonSchemaFormUtils.orderByXOrder(Object.entries(properties), schema["x-order"]);
|
|
106
|
-
const entries = ctx.
|
|
106
|
+
const entries = ctx.sortMode === "required-first" ? jsonSchemaFormUtils.orderRequiredFirst(ordered, required) : ctx.sortMode === "priority" ? jsonSchemaFormUtils.orderByPriority(ordered, required, value) : ordered;
|
|
107
107
|
return entries.flatMap(([key, prop]) => {
|
|
108
108
|
if (hidden.has(key)) return [];
|
|
109
109
|
const row = renderFieldRow(
|
|
@@ -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 EnumControl,\n FieldLabel,\n FieldWrapper,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\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 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; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly;\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 \"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 \"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// 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, { key: args.key, prop: args.prop, value: args.value });\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 for (const ext of ctx.post) {\n const next = ext(field, { label, value });\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 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 const ordered = orderByXOrder(Object.entries(properties), schema[\"x-order\"]);\n const entries = ctx.requiredFirst ? orderRequiredFirst(ordered, required) : 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","BooleanControl","NumberControl","DateControl","ArrayControl","ObjectControl","StringMapControl","StringControl","resolveControl","FieldLabel","ObjectSection","jsxs","cn","labelSizeClass","LabelIcon","softError","FieldWrapper","effectiveProperties","orderByXOrder","orderRequiredFirst"],"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 EnumControl,\n FieldLabel,\n FieldWrapper,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\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 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; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly;\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 \"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 \"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// 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, { key: args.key, prop: args.prop, value: args.value });\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 for (const ext of ctx.post) {\n const next = ext(field, { label, value });\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 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 const ordered = 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","BooleanControl","NumberControl","DateControl","ArrayControl","ObjectControl","StringMapControl","StringControl","resolveControl","FieldLabel","ObjectSection","jsxs","cn","labelSizeClass","LabelIcon","softError","FieldWrapper","effectiveProperties","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;AAiBvC,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACd,MAAM,0BAA0B,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;AAiBvC,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACd,MAAM,0BAA0B,CAAC;AAkBlC,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,SAAS,CA8BrF;AA0CD,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,CAiDlB;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,CA2Bb;AAID,eAAO,MAAM,SAAS,EAAE,SAIvB,CAAC"}
|
|
@@ -6,7 +6,7 @@ import { ObjectSection, FieldWrapper, ReadOnlyValue, StringControl, DateControl,
|
|
|
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";
|
|
9
|
-
import { orderByXOrder, orderRequiredFirst, softError, fieldInputId } from "./json-schema-form-utils.js";
|
|
9
|
+
import { orderByXOrder, orderRequiredFirst, orderByPriority, softError, fieldInputId } from "./json-schema-form-utils.js";
|
|
10
10
|
import { labelSizeClass } from "./json-schema-form-size.js";
|
|
11
11
|
function renderValueControl(field, ctx) {
|
|
12
12
|
const fieldId = fieldInputId(field.key, ctx.idPrefix);
|
|
@@ -101,7 +101,7 @@ function renderObjectFields(schema, value, onChange, ctx, opts) {
|
|
|
101
101
|
const { properties, required } = effectiveProperties(schema, value);
|
|
102
102
|
const hidden = new Set((opts == null ? void 0 : opts.hiddenKeys) ?? []);
|
|
103
103
|
const ordered = orderByXOrder(Object.entries(properties), schema["x-order"]);
|
|
104
|
-
const entries = ctx.
|
|
104
|
+
const entries = ctx.sortMode === "required-first" ? orderRequiredFirst(ordered, required) : ctx.sortMode === "priority" ? orderByPriority(ordered, required, value) : ordered;
|
|
105
105
|
return entries.flatMap(([key, prop]) => {
|
|
106
106
|
if (hidden.has(key)) return [];
|
|
107
107
|
const row = renderFieldRow(
|
|
@@ -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 EnumControl,\n FieldLabel,\n FieldWrapper,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\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 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; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly;\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 \"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 \"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// 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, { key: args.key, prop: args.prop, value: args.value });\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 for (const ext of ctx.post) {\n const next = ext(field, { label, value });\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 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 const ordered = orderByXOrder(Object.entries(properties), schema[\"x-order\"]);\n const entries = ctx.requiredFirst ? orderRequiredFirst(ordered, required) : 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 EnumControl,\n FieldLabel,\n FieldWrapper,\n NumberControl,\n ObjectSection,\n ReadOnlyValue,\n StringControl,\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 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; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={ctx.size} />;\n }\n const readOnly = ctx.readOnly;\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 \"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 \"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// 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, { key: args.key, prop: args.prop, value: args.value });\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 for (const ext of ctx.post) {\n const next = ext(field, { label, value });\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 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 const ordered = 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,6 +1,7 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { LabelIconSpec } from '../data/Icon';
|
|
3
3
|
import { FormSize } from './json-schema-form-size';
|
|
4
|
+
import { SortMode } from './json-schema-form-preferences';
|
|
4
5
|
export interface JsonSchemaProperty {
|
|
5
6
|
type?: JsonSchemaType | JsonSchemaType[];
|
|
6
7
|
description?: string;
|
|
@@ -33,6 +34,8 @@ export interface JsonSchemaConditional {
|
|
|
33
34
|
then?: JsonSchemaProperty;
|
|
34
35
|
properties?: Record<string, JsonSchemaProperty>;
|
|
35
36
|
required?: string[];
|
|
37
|
+
additionalProperties?: boolean | JsonSchemaProperty;
|
|
38
|
+
description?: string;
|
|
36
39
|
}
|
|
37
40
|
export interface JsonSchemaObject extends JsonSchemaProperty {
|
|
38
41
|
type?: "object";
|
|
@@ -118,7 +121,7 @@ export interface RenderContext {
|
|
|
118
121
|
layout: FormLayout;
|
|
119
122
|
size: FormSize;
|
|
120
123
|
idPrefix?: string;
|
|
121
|
-
|
|
124
|
+
sortMode: SortMode;
|
|
122
125
|
pre: PreExtension[];
|
|
123
126
|
post: PostExtension[];
|
|
124
127
|
depth: number;
|
|
@@ -183,7 +186,7 @@ export interface JsonSchemaFormProps {
|
|
|
183
186
|
pre?: PreExtension[];
|
|
184
187
|
post?: PostExtension[];
|
|
185
188
|
/**
|
|
186
|
-
* Show the top-right three-dot display-options menu (size
|
|
189
|
+
* Show the top-right three-dot display-options menu (size, layout, and sort).
|
|
187
190
|
* Defaults to true. The menu controls only this form's appearance — never
|
|
188
191
|
* global page density or field values. When false the form renders exactly as
|
|
189
192
|
* before and performs no preference reads/writes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-types.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"json-schema-form-types.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-types.ts"],"names":[],"mappings":"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"}
|