@flanksource/clicky-ui 0.2.9 → 0.2.11
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/components/Combobox.cjs +4 -1
- package/dist/components/Combobox.cjs.map +1 -1
- package/dist/components/Combobox.d.ts +6 -0
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +4 -1
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/JsonSchemaForm.cjs +24 -5
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.d.ts +1 -1
- package/dist/components/JsonSchemaForm.d.ts.map +1 -1
- package/dist/components/JsonSchemaForm.js +24 -5
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/json-schema-form-array.cjs +117 -37
- package/dist/components/json-schema-form-array.cjs.map +1 -1
- package/dist/components/json-schema-form-array.d.ts.map +1 -1
- package/dist/components/json-schema-form-array.js +118 -38
- package/dist/components/json-schema-form-array.js.map +1 -1
- package/dist/components/json-schema-form-fields.cjs +121 -51
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts +9 -6
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +121 -51
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-render.cjs +15 -8
- package/dist/components/json-schema-form-render.cjs.map +1 -1
- package/dist/components/json-schema-form-render.d.ts +5 -2
- package/dist/components/json-schema-form-render.d.ts.map +1 -1
- package/dist/components/json-schema-form-render.js +15 -8
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +41 -6
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
- package/dist/components/json-schema-form-resolve.js +41 -6
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components/json-schema-form-size.cjs +61 -0
- package/dist/components/json-schema-form-size.cjs.map +1 -0
- package/dist/components/json-schema-form-size.d.ts +11 -0
- package/dist/components/json-schema-form-size.d.ts.map +1 -0
- package/dist/components/json-schema-form-size.js +61 -0
- package/dist/components/json-schema-form-size.js.map +1 -0
- package/dist/components/json-schema-form-types.d.ts +36 -1
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components.cjs +2 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +3 -1
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +2 -0
- package/dist/components.js.map +1 -1
- package/dist/data/Clicky.cjs +412 -90
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.d.ts +4 -2
- package/dist/data/Clicky.d.ts.map +1 -1
- package/dist/data/Clicky.js +413 -91
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/DataTable.cjs +534 -293
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +12 -0
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +534 -293
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data.d.ts +1 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/rpc/CommandOutput.cjs +101 -20
- package/dist/rpc/CommandOutput.cjs.map +1 -1
- package/dist/rpc/CommandOutput.d.ts +12 -4
- package/dist/rpc/CommandOutput.d.ts.map +1 -1
- package/dist/rpc/CommandOutput.js +102 -21
- package/dist/rpc/CommandOutput.js.map +1 -1
- package/dist/rpc/ExecutionResult.cjs +4 -76
- package/dist/rpc/ExecutionResult.cjs.map +1 -1
- package/dist/rpc/ExecutionResult.d.ts +3 -22
- package/dist/rpc/ExecutionResult.d.ts.map +1 -1
- package/dist/rpc/ExecutionResult.js +4 -76
- package/dist/rpc/ExecutionResult.js.map +1 -1
- package/dist/rpc/OperationCatalog.cjs +22 -13
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +24 -15
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/OperationCommandPage.cjs +10 -20
- package/dist/rpc/OperationCommandPage.cjs.map +1 -1
- package/dist/rpc/OperationCommandPage.d.ts.map +1 -1
- package/dist/rpc/OperationCommandPage.js +11 -21
- package/dist/rpc/OperationCommandPage.js.map +1 -1
- package/dist/rpc/apiClient.cjs +18 -0
- package/dist/rpc/apiClient.cjs.map +1 -1
- package/dist/rpc/apiClient.d.ts.map +1 -1
- package/dist/rpc/apiClient.js +18 -0
- package/dist/rpc/apiClient.js.map +1 -1
- package/dist/rpc/formMetadata.cjs +31 -0
- package/dist/rpc/formMetadata.cjs.map +1 -1
- package/dist/rpc/formMetadata.d.ts +3 -1
- package/dist/rpc/formMetadata.d.ts.map +1 -1
- package/dist/rpc/formMetadata.js +31 -0
- package/dist/rpc/formMetadata.js.map +1 -1
- package/dist/rpc/types.cjs.map +1 -1
- package/dist/rpc/types.d.ts +7 -0
- package/dist/rpc/types.d.ts.map +1 -1
- package/dist/rpc/types.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -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 { LabelIcon, type LabelIconSpec } from \"../data/Icon\";\nimport {\n FieldLabel,\n FieldWrapper,\n fieldInputId,\n renderValueControl,\n} from \"./json-schema-form-fields\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldControl,\n JsonSchemaObject,\n JsonSchemaProperty,\n PostExtension,\n PreExtension,\n} from \"./json-schema-form-types\";\n\n// RenderContext carries everything the recursive renderer needs to descend into\n// array items and object/map values: readOnly/inline layout, the consumer's\n// pre/post extension stacks (so they apply at EVERY depth, not just the top\n// level), and the current depth (for keys/labels).\nexport interface RenderContext {\n readOnly: boolean;\n // Drop fields whose resolved control is read-only (schema `readOnly: true`)\n // instead of rendering them as value displays. Applies at every depth.\n hideReadOnlyFields: boolean;\n inline: boolean;\n // requiredFirst stably reorders each object level so required fields render\n // before optional ones (see JsonSchemaFormProps.requiredFirst).\n requiredFirst: boolean;\n pre: PreExtension[];\n post: PostExtension[];\n depth: number;\n}\n\n// runExtensions 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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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);\n let label: ReactNode = <FieldLabel field={field} fieldId={fieldId} />;\n let value: ReactNode = renderValueControl(field, ctx);\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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 render as a flat section — a header followed by the nested\n // fields at full width — rather than an inline label + bordered sub-form box.\n // This keeps deep schemas (e.g. policy → shape, asfile → params) readable as a\n // single column of labelled sections instead of progressively indented boxes.\n if (field.kind === \"object\") {\n return (\n <ObjectSection\n label={opts?.labelOverride ?? field.label}\n required={field.required}\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=\"flex items-center gap-2 text-sm font-medium\">\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 inline={ctx.inline}\n label={label}\n value={built.value}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(err ? { error: err } : {})}\n />\n );\n}\n\n// ObjectSection renders a nested object as a labelled section: a header row\n// (the field label + required/badge) above its fields, which fill the full\n// width below. It replaces the inline label + bordered box so nested objects\n// read as flat, headed groups rather than indented sub-forms.\nfunction ObjectSection({\n label,\n required,\n badge,\n helper,\n labelIcon,\n children,\n}: {\n label: string;\n required: boolean;\n badge?: string;\n helper?: string;\n labelIcon?: LabelIconSpec;\n children: ReactNode;\n}) {\n return (\n <div className=\"space-y-1.5\">\n <div className=\"flex items-center gap-2 border-b border-border pb-1 text-sm font-semibold\">\n <LabelIcon icon={labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{label}</span>\n {required && <span className=\"text-destructive\">*</span>}\n {badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {children}\n </div>\n );\n}\n\n// 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 entries = ctx.requiredFirst\n ? orderRequiredFirst(Object.entries(properties), required)\n : Object.entries(properties);\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 return row ? [<div key={key}>{row}</div>] : [];\n });\n}\n\n// orderRequiredFirst stably partitions property entries so the keys named in\n// `required` come first (in their original order), then the rest (in theirs).\n// A stable two-pass partition, so it never reshuffles within either group.\nexport function orderRequiredFirst<T>(\n entries: [string, T][],\n required: string[],\n): [string, T][] {\n const isRequired = new Set(required);\n const head = entries.filter(([key]) => isRequired.has(key));\n const tail = entries.filter(([key]) => !isRequired.has(key));\n return [...head, ...tail];\n}\n\n// softError computes a display-only validation hint. It never blocks onChange.\n// Consumers suppress the unknown-enum hint by setting allowCustomValue.\nexport function softError(field: FieldControl): string | undefined {\n const v = field.value;\n const isEmpty = v === undefined || v === null || v === \"\";\n if (field.required && isEmpty) return \"Required\";\n\n if (field.kind === \"number\" && typeof field.minimum === \"number\" && typeof v === \"number\") {\n if (v < field.minimum) return `Must be ≥ ${field.minimum}`;\n }\n\n if (field.kind === \"enum\" && !field.allowCustomValue && !isEmpty) {\n const known = (field.options ?? []).some((o) => o.value === String(v));\n if (!known) return \"Unknown value (allowed)\";\n }\n return undefined;\n}\n\n// Immutable array helpers used by the array control.\nexport function setIndex<T>(arr: T[], i: number, v: T): T[] {\n return arr.map((x, idx) => (idx === i ? v : x));\n}\n\nexport function removeIndex<T>(arr: T[], i: number): T[] {\n return arr.filter((_, idx) => idx !== i);\n}\n\nexport function moveItem<T>(arr: T[], from: number, to: number): T[] {\n if (to < 0 || to >= arr.length) return arr;\n const next = [...arr];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved as T);\n return next;\n}\n\n// seedFromSchema produces the initial value for a freshly-added array item or\n// object field, honouring an explicit default.\nexport function seedFromSchema(schema: JsonSchemaProperty): unknown {\n if (schema.default !== undefined) return schema.default;\n const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;\n if (type === \"array\") return [];\n if (type === \"object\") return {};\n if (type === \"boolean\") return false;\n // Numbers seed as \"\" so the soft Required hint can show without coercion\n // surprises; the number control coerces on first real input.\n return \"\";\n}\n"],"names":["resolveControl","fieldInputId","jsx","FieldLabel","renderValueControl","jsxs","LabelIcon","FieldWrapper","effectiveProperties"],"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, type LabelIconSpec } from \"../data/Icon\";\nimport {\n FieldLabel,\n FieldWrapper,\n fieldInputId,\n renderValueControl,\n} from \"./json-schema-form-fields\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldControl,\n FormLayout,\n JsonSchemaObject,\n JsonSchemaProperty,\n PostExtension,\n PreExtension,\n} from \"./json-schema-form-types\";\nimport { fieldInnerGapClass, labelSizeClass, type FormSize } from \"./json-schema-form-size\";\n\n// RenderContext carries everything the recursive renderer needs to descend into\n// array items and object/map values: readOnly/inline layout, the consumer's\n// pre/post extension stacks (so they apply at EVERY depth, not just the top\n// level), and the current depth (for keys/labels).\nexport interface RenderContext {\n readOnly: boolean;\n // Drop fields whose resolved control is read-only (schema `readOnly: true`)\n // instead of rendering them as value displays. Applies at every depth.\n hideReadOnlyFields: boolean;\n // Resolved form layout (mode + inline width caps); see FormLayout.\n layout: FormLayout;\n // Form-wide size token scaling inputs and labels; see FormSize.\n size: FormSize;\n // Optional namespace for generated input ids, so multiple forms on one page\n // don't collide on duplicate ids (which would break label/input focus).\n idPrefix?: string;\n // requiredFirst stably reorders each object level so required fields render\n // before optional ones (see JsonSchemaFormProps.requiredFirst).\n requiredFirst: boolean;\n pre: PreExtension[];\n post: PostExtension[];\n depth: number;\n}\n\n// runExtensions 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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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// ObjectSection renders a nested object as a labelled section: a header row\n// (the field label + required/badge) above its fields, which fill the full\n// width below. It replaces the inline label + bordered box so nested objects\n// read as flat, headed groups rather than indented sub-forms.\nfunction ObjectSection({\n label,\n required,\n size,\n badge,\n helper,\n labelIcon,\n children,\n}: {\n label: string;\n required: boolean;\n size: FormSize;\n badge?: string;\n helper?: string;\n labelIcon?: LabelIconSpec;\n children: ReactNode;\n}) {\n return (\n <div className={cn(\"flex flex-col\", fieldInnerGapClass[size])}>\n <div className={cn(\"flex items-center gap-2 border-b border-border pb-1 font-semibold\", labelSizeClass[size])}>\n <LabelIcon icon={labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{label}</span>\n {required && <span className=\"text-destructive\">*</span>}\n {badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {children}\n </div>\n );\n}\n\n// 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 entries = ctx.requiredFirst\n ? orderRequiredFirst(Object.entries(properties), required)\n : Object.entries(properties);\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 return row ? [<div key={key}>{row}</div>] : [];\n });\n}\n\n// orderRequiredFirst stably partitions property entries so the keys named in\n// `required` come first (in their original order), then the rest (in theirs).\n// A stable two-pass partition, so it never reshuffles within either group.\nexport function orderRequiredFirst<T>(\n entries: [string, T][],\n required: string[],\n): [string, T][] {\n const isRequired = new Set(required);\n const head = entries.filter(([key]) => isRequired.has(key));\n const tail = entries.filter(([key]) => !isRequired.has(key));\n return [...head, ...tail];\n}\n\n// softError computes a display-only validation hint. It never blocks onChange.\n// Consumers suppress the unknown-enum hint by setting allowCustomValue.\nexport function softError(field: FieldControl): string | undefined {\n const v = field.value;\n const isEmpty = v === undefined || v === null || v === \"\";\n if (field.required && isEmpty) return \"Required\";\n\n if (field.kind === \"number\" && typeof field.minimum === \"number\" && typeof v === \"number\") {\n if (v < field.minimum) return `Must be ≥ ${field.minimum}`;\n }\n\n if (field.kind === \"enum\" && !field.allowCustomValue && !isEmpty) {\n const known = (field.options ?? []).some((o) => o.value === String(v));\n if (!known) return \"Unknown value (allowed)\";\n }\n return undefined;\n}\n\n// Immutable array helpers used by the array control.\nexport function setIndex<T>(arr: T[], i: number, v: T): T[] {\n return arr.map((x, idx) => (idx === i ? v : x));\n}\n\nexport function removeIndex<T>(arr: T[], i: number): T[] {\n return arr.filter((_, idx) => idx !== i);\n}\n\nexport function moveItem<T>(arr: T[], from: number, to: number): T[] {\n if (to < 0 || to >= arr.length) return arr;\n const next = [...arr];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved as T);\n return next;\n}\n\n// seedFromSchema produces the initial value for a freshly-added array item or\n// object field, honouring an explicit default.\nexport function seedFromSchema(schema: JsonSchemaProperty): unknown {\n if (schema.default !== undefined) return schema.default;\n const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;\n if (type === \"array\") return [];\n if (type === \"object\") return {};\n if (type === \"boolean\") return false;\n // Numbers seed as \"\" so the soft Required hint can show without coercion\n // surprises; the number control coerces on first real input.\n return \"\";\n}\n"],"names":["resolveControl","fieldInputId","jsx","FieldLabel","renderValueControl","jsxs","cn","labelSizeClass","LabelIcon","FieldWrapper","fieldInnerGapClass","effectiveProperties"],"mappings":"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"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { FieldControl, JsonSchemaObject, JsonSchemaProperty, PostExtension, PreExtension } from './json-schema-form-types';
|
|
2
|
+
import { FieldControl, FormLayout, JsonSchemaObject, JsonSchemaProperty, PostExtension, PreExtension } from './json-schema-form-types';
|
|
3
|
+
import { FormSize } from './json-schema-form-size';
|
|
3
4
|
export interface RenderContext {
|
|
4
5
|
readOnly: boolean;
|
|
5
6
|
hideReadOnlyFields: boolean;
|
|
6
|
-
|
|
7
|
+
layout: FormLayout;
|
|
8
|
+
size: FormSize;
|
|
9
|
+
idPrefix?: string;
|
|
7
10
|
requiredFirst: boolean;
|
|
8
11
|
pre: PreExtension[];
|
|
9
12
|
post: PostExtension[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-render.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-render.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"json-schema-form-render.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-render.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAsC,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAM5F,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAGlB,kBAAkB,EAAE,OAAO,CAAC;IAE5B,MAAM,EAAE,UAAU,CAAC;IAEnB,IAAI,EAAE,QAAQ,CAAC;IAGf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,aAAa,EAAE,OAAO,CAAC;IACvB,GAAG,EAAE,YAAY,EAAE,CAAC;IACpB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AA0CD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,EACrH,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;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,EACrH,GAAG,EAAE,aAAa,EAClB,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,SAAS,GAAG,IAAI,CAiDlB;AA4CD,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,CAoBb;AAKD,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EACtB,QAAQ,EAAE,MAAM,EAAE,GACjB,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAKf;AAID,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAcjE;AAGD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAE1D;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,CAEvD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,CAMnE;AAID,wBAAgB,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CASlE"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
3
4
|
import { LabelIcon } from "../data/Icon.js";
|
|
4
5
|
import { FieldWrapper, fieldInputId, renderValueControl, FieldLabel } from "./json-schema-form-fields.js";
|
|
5
6
|
import { effectiveProperties, resolveControl } from "./json-schema-form-resolve.js";
|
|
7
|
+
import { labelSizeClass, fieldInnerGapClass } from "./json-schema-form-size.js";
|
|
6
8
|
function buildField(args, ctx) {
|
|
7
9
|
const base = resolveControl(args);
|
|
8
10
|
let field = base;
|
|
@@ -12,9 +14,11 @@ function buildField(args, ctx) {
|
|
|
12
14
|
}
|
|
13
15
|
if (!field) return null;
|
|
14
16
|
if (ctx.hideReadOnlyFields && field.readOnly) return null;
|
|
15
|
-
const fieldId = fieldInputId(field.key);
|
|
16
|
-
let label = /* @__PURE__ */ jsx(FieldLabel, { field, fieldId });
|
|
17
|
-
|
|
17
|
+
const fieldId = fieldInputId(field.key, ctx.idPrefix);
|
|
18
|
+
let label = /* @__PURE__ */ jsx(FieldLabel, { field, fieldId, size: ctx.size });
|
|
19
|
+
const overrideMode = field.layout === "inline" ? "inline" : field.layout === "stack" ? "stacked" : void 0;
|
|
20
|
+
const valueCtx = overrideMode ? { ...ctx, layout: { ...ctx.layout, mode: overrideMode } } : ctx;
|
|
21
|
+
let value = renderValueControl(field, valueCtx);
|
|
18
22
|
for (const ext of ctx.post) {
|
|
19
23
|
const next = ext(field, { label, value });
|
|
20
24
|
label = next.label;
|
|
@@ -31,12 +35,13 @@ function renderFieldRow(args, ctx, opts) {
|
|
|
31
35
|
const built = buildField(args, ctx);
|
|
32
36
|
if (!built) return null;
|
|
33
37
|
const { field } = built;
|
|
34
|
-
if (field.kind === "object") {
|
|
38
|
+
if (field.kind === "object" || field.layout === "table") {
|
|
35
39
|
return /* @__PURE__ */ jsx(
|
|
36
40
|
ObjectSection,
|
|
37
41
|
{
|
|
38
42
|
label: (opts == null ? void 0 : opts.labelOverride) ?? field.label,
|
|
39
43
|
required: field.required,
|
|
44
|
+
size: ctx.size,
|
|
40
45
|
...field.badge ? { badge: field.badge } : {},
|
|
41
46
|
...field.helper ? { helper: field.helper } : {},
|
|
42
47
|
...field.labelIcon != null ? { labelIcon: field.labelIcon } : {},
|
|
@@ -44,7 +49,7 @@ function renderFieldRow(args, ctx, opts) {
|
|
|
44
49
|
}
|
|
45
50
|
);
|
|
46
51
|
}
|
|
47
|
-
const label = (opts == null ? void 0 : opts.labelOverride) ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2
|
|
52
|
+
const label = (opts == null ? void 0 : opts.labelOverride) ? /* @__PURE__ */ jsxs("span", { className: cn("flex items-center gap-2 font-medium", labelSizeClass[ctx.size]), children: [
|
|
48
53
|
/* @__PURE__ */ jsx(LabelIcon, { icon: field.labelIcon, className: "text-[15px] text-muted-foreground" }),
|
|
49
54
|
/* @__PURE__ */ jsx("span", { children: opts.labelOverride }),
|
|
50
55
|
field.required && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" }),
|
|
@@ -54,7 +59,8 @@ function renderFieldRow(args, ctx, opts) {
|
|
|
54
59
|
return /* @__PURE__ */ jsx(
|
|
55
60
|
FieldWrapper,
|
|
56
61
|
{
|
|
57
|
-
|
|
62
|
+
layout: ctx.layout,
|
|
63
|
+
size: ctx.size,
|
|
58
64
|
label,
|
|
59
65
|
value: built.value,
|
|
60
66
|
...field.helper ? { helper: field.helper } : {},
|
|
@@ -65,13 +71,14 @@ function renderFieldRow(args, ctx, opts) {
|
|
|
65
71
|
function ObjectSection({
|
|
66
72
|
label,
|
|
67
73
|
required,
|
|
74
|
+
size,
|
|
68
75
|
badge,
|
|
69
76
|
helper,
|
|
70
77
|
labelIcon,
|
|
71
78
|
children
|
|
72
79
|
}) {
|
|
73
|
-
return /* @__PURE__ */ jsxs("div", { className: "
|
|
74
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border pb-1
|
|
80
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", fieldInnerGapClass[size]), children: [
|
|
81
|
+
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2 border-b border-border pb-1 font-semibold", labelSizeClass[size]), children: [
|
|
75
82
|
/* @__PURE__ */ jsx(LabelIcon, { icon: labelIcon, className: "text-[15px] text-muted-foreground" }),
|
|
76
83
|
/* @__PURE__ */ jsx("span", { children: label }),
|
|
77
84
|
required && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" }),
|
|
@@ -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 { LabelIcon, type LabelIconSpec } from \"../data/Icon\";\nimport {\n FieldLabel,\n FieldWrapper,\n fieldInputId,\n renderValueControl,\n} from \"./json-schema-form-fields\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldControl,\n JsonSchemaObject,\n JsonSchemaProperty,\n PostExtension,\n PreExtension,\n} from \"./json-schema-form-types\";\n\n// RenderContext carries everything the recursive renderer needs to descend into\n// array items and object/map values: readOnly/inline layout, the consumer's\n// pre/post extension stacks (so they apply at EVERY depth, not just the top\n// level), and the current depth (for keys/labels).\nexport interface RenderContext {\n readOnly: boolean;\n // Drop fields whose resolved control is read-only (schema `readOnly: true`)\n // instead of rendering them as value displays. Applies at every depth.\n hideReadOnlyFields: boolean;\n inline: boolean;\n // requiredFirst stably reorders each object level so required fields render\n // before optional ones (see JsonSchemaFormProps.requiredFirst).\n requiredFirst: boolean;\n pre: PreExtension[];\n post: PostExtension[];\n depth: number;\n}\n\n// runExtensions 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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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);\n let label: ReactNode = <FieldLabel field={field} fieldId={fieldId} />;\n let value: ReactNode = renderValueControl(field, ctx);\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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 render as a flat section — a header followed by the nested\n // fields at full width — rather than an inline label + bordered sub-form box.\n // This keeps deep schemas (e.g. policy → shape, asfile → params) readable as a\n // single column of labelled sections instead of progressively indented boxes.\n if (field.kind === \"object\") {\n return (\n <ObjectSection\n label={opts?.labelOverride ?? field.label}\n required={field.required}\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=\"flex items-center gap-2 text-sm font-medium\">\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 inline={ctx.inline}\n label={label}\n value={built.value}\n {...(field.helper ? { helper: field.helper } : {})}\n {...(err ? { error: err } : {})}\n />\n );\n}\n\n// ObjectSection renders a nested object as a labelled section: a header row\n// (the field label + required/badge) above its fields, which fill the full\n// width below. It replaces the inline label + bordered box so nested objects\n// read as flat, headed groups rather than indented sub-forms.\nfunction ObjectSection({\n label,\n required,\n badge,\n helper,\n labelIcon,\n children,\n}: {\n label: string;\n required: boolean;\n badge?: string;\n helper?: string;\n labelIcon?: LabelIconSpec;\n children: ReactNode;\n}) {\n return (\n <div className=\"space-y-1.5\">\n <div className=\"flex items-center gap-2 border-b border-border pb-1 text-sm font-semibold\">\n <LabelIcon icon={labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{label}</span>\n {required && <span className=\"text-destructive\">*</span>}\n {badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {children}\n </div>\n );\n}\n\n// 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 entries = ctx.requiredFirst\n ? orderRequiredFirst(Object.entries(properties), required)\n : Object.entries(properties);\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 return row ? [<div key={key}>{row}</div>] : [];\n });\n}\n\n// orderRequiredFirst stably partitions property entries so the keys named in\n// `required` come first (in their original order), then the rest (in theirs).\n// A stable two-pass partition, so it never reshuffles within either group.\nexport function orderRequiredFirst<T>(\n entries: [string, T][],\n required: string[],\n): [string, T][] {\n const isRequired = new Set(required);\n const head = entries.filter(([key]) => isRequired.has(key));\n const tail = entries.filter(([key]) => !isRequired.has(key));\n return [...head, ...tail];\n}\n\n// softError computes a display-only validation hint. It never blocks onChange.\n// Consumers suppress the unknown-enum hint by setting allowCustomValue.\nexport function softError(field: FieldControl): string | undefined {\n const v = field.value;\n const isEmpty = v === undefined || v === null || v === \"\";\n if (field.required && isEmpty) return \"Required\";\n\n if (field.kind === \"number\" && typeof field.minimum === \"number\" && typeof v === \"number\") {\n if (v < field.minimum) return `Must be ≥ ${field.minimum}`;\n }\n\n if (field.kind === \"enum\" && !field.allowCustomValue && !isEmpty) {\n const known = (field.options ?? []).some((o) => o.value === String(v));\n if (!known) return \"Unknown value (allowed)\";\n }\n return undefined;\n}\n\n// Immutable array helpers used by the array control.\nexport function setIndex<T>(arr: T[], i: number, v: T): T[] {\n return arr.map((x, idx) => (idx === i ? v : x));\n}\n\nexport function removeIndex<T>(arr: T[], i: number): T[] {\n return arr.filter((_, idx) => idx !== i);\n}\n\nexport function moveItem<T>(arr: T[], from: number, to: number): T[] {\n if (to < 0 || to >= arr.length) return arr;\n const next = [...arr];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved as T);\n return next;\n}\n\n// seedFromSchema produces the initial value for a freshly-added array item or\n// object field, honouring an explicit default.\nexport function seedFromSchema(schema: JsonSchemaProperty): unknown {\n if (schema.default !== undefined) return schema.default;\n const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;\n if (type === \"array\") return [];\n if (type === \"object\") return {};\n if (type === \"boolean\") return false;\n // Numbers seed as \"\" so the soft Required hint can show without coercion\n // surprises; the number control coerces on first real input.\n return \"\";\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, type LabelIconSpec } from \"../data/Icon\";\nimport {\n FieldLabel,\n FieldWrapper,\n fieldInputId,\n renderValueControl,\n} from \"./json-schema-form-fields\";\nimport { effectiveProperties, resolveControl } from \"./json-schema-form-resolve\";\nimport type {\n FieldControl,\n FormLayout,\n JsonSchemaObject,\n JsonSchemaProperty,\n PostExtension,\n PreExtension,\n} from \"./json-schema-form-types\";\nimport { fieldInnerGapClass, labelSizeClass, type FormSize } from \"./json-schema-form-size\";\n\n// RenderContext carries everything the recursive renderer needs to descend into\n// array items and object/map values: readOnly/inline layout, the consumer's\n// pre/post extension stacks (so they apply at EVERY depth, not just the top\n// level), and the current depth (for keys/labels).\nexport interface RenderContext {\n readOnly: boolean;\n // Drop fields whose resolved control is read-only (schema `readOnly: true`)\n // instead of rendering them as value displays. Applies at every depth.\n hideReadOnlyFields: boolean;\n // Resolved form layout (mode + inline width caps); see FormLayout.\n layout: FormLayout;\n // Form-wide size token scaling inputs and labels; see FormSize.\n size: FormSize;\n // Optional namespace for generated input ids, so multiple forms on one page\n // don't collide on duplicate ids (which would break label/input focus).\n idPrefix?: string;\n // requiredFirst stably reorders each object level so required fields render\n // before optional ones (see JsonSchemaFormProps.requiredFirst).\n requiredFirst: boolean;\n pre: PreExtension[];\n post: PostExtension[];\n depth: number;\n}\n\n// runExtensions 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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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: { key: string; prop: JsonSchemaProperty; required: boolean; value: unknown; onChange: (next: unknown) => void },\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// ObjectSection renders a nested object as a labelled section: a header row\n// (the field label + required/badge) above its fields, which fill the full\n// width below. It replaces the inline label + bordered box so nested objects\n// read as flat, headed groups rather than indented sub-forms.\nfunction ObjectSection({\n label,\n required,\n size,\n badge,\n helper,\n labelIcon,\n children,\n}: {\n label: string;\n required: boolean;\n size: FormSize;\n badge?: string;\n helper?: string;\n labelIcon?: LabelIconSpec;\n children: ReactNode;\n}) {\n return (\n <div className={cn(\"flex flex-col\", fieldInnerGapClass[size])}>\n <div className={cn(\"flex items-center gap-2 border-b border-border pb-1 font-semibold\", labelSizeClass[size])}>\n <LabelIcon icon={labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span>{label}</span>\n {required && <span className=\"text-destructive\">*</span>}\n {badge && (\n <span className=\"rounded bg-muted px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">\n {badge}\n </span>\n )}\n </div>\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {children}\n </div>\n );\n}\n\n// 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 entries = ctx.requiredFirst\n ? orderRequiredFirst(Object.entries(properties), required)\n : Object.entries(properties);\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 return row ? [<div key={key}>{row}</div>] : [];\n });\n}\n\n// orderRequiredFirst stably partitions property entries so the keys named in\n// `required` come first (in their original order), then the rest (in theirs).\n// A stable two-pass partition, so it never reshuffles within either group.\nexport function orderRequiredFirst<T>(\n entries: [string, T][],\n required: string[],\n): [string, T][] {\n const isRequired = new Set(required);\n const head = entries.filter(([key]) => isRequired.has(key));\n const tail = entries.filter(([key]) => !isRequired.has(key));\n return [...head, ...tail];\n}\n\n// softError computes a display-only validation hint. It never blocks onChange.\n// Consumers suppress the unknown-enum hint by setting allowCustomValue.\nexport function softError(field: FieldControl): string | undefined {\n const v = field.value;\n const isEmpty = v === undefined || v === null || v === \"\";\n if (field.required && isEmpty) return \"Required\";\n\n if (field.kind === \"number\" && typeof field.minimum === \"number\" && typeof v === \"number\") {\n if (v < field.minimum) return `Must be ≥ ${field.minimum}`;\n }\n\n if (field.kind === \"enum\" && !field.allowCustomValue && !isEmpty) {\n const known = (field.options ?? []).some((o) => o.value === String(v));\n if (!known) return \"Unknown value (allowed)\";\n }\n return undefined;\n}\n\n// Immutable array helpers used by the array control.\nexport function setIndex<T>(arr: T[], i: number, v: T): T[] {\n return arr.map((x, idx) => (idx === i ? v : x));\n}\n\nexport function removeIndex<T>(arr: T[], i: number): T[] {\n return arr.filter((_, idx) => idx !== i);\n}\n\nexport function moveItem<T>(arr: T[], from: number, to: number): T[] {\n if (to < 0 || to >= arr.length) return arr;\n const next = [...arr];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved as T);\n return next;\n}\n\n// seedFromSchema produces the initial value for a freshly-added array item or\n// object field, honouring an explicit default.\nexport function seedFromSchema(schema: JsonSchemaProperty): unknown {\n if (schema.default !== undefined) return schema.default;\n const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;\n if (type === \"array\") return [];\n if (type === \"object\") return {};\n if (type === \"boolean\") return false;\n // Numbers seed as \"\" so the soft Required hint can show without coercion\n // surprises; the number control coerces on first real input.\n return \"\";\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
function isOpenStringMap(prop) {
|
|
4
|
-
|
|
4
|
+
if (!schemaHasType(prop, "object")) return false;
|
|
5
|
+
if (typeof prop.additionalProperties === "object" && prop.additionalProperties !== null) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
return !!prop.patternProperties && Object.keys(prop.patternProperties).length > 0;
|
|
9
|
+
}
|
|
10
|
+
function patternSchemasOf(prop) {
|
|
11
|
+
const pp = prop.patternProperties;
|
|
12
|
+
if (!pp || Object.keys(pp).length === 0) return void 0;
|
|
13
|
+
return Object.entries(pp).map(([pattern, schema]) => ({ pattern, schema }));
|
|
5
14
|
}
|
|
6
15
|
function schemaHasType(prop, type) {
|
|
7
16
|
if (Array.isArray(prop.type)) return prop.type.includes(type);
|
|
@@ -19,6 +28,9 @@ function enumBranch(prop) {
|
|
|
19
28
|
function resolveControl(args) {
|
|
20
29
|
const { key, prop, required, value, onChange } = args;
|
|
21
30
|
const labelIcon = prop["x-icon"];
|
|
31
|
+
const xLayout = prop["x-layout"];
|
|
32
|
+
const layout = xLayout === "inline" || xLayout === "stack" || xLayout === "table" ? xLayout : void 0;
|
|
33
|
+
const keyOptions = keyOptionsFor(prop);
|
|
22
34
|
const base = {
|
|
23
35
|
key,
|
|
24
36
|
kind: "string",
|
|
@@ -53,15 +65,26 @@ function resolveControl(args) {
|
|
|
53
65
|
};
|
|
54
66
|
}
|
|
55
67
|
if (schemaHasType(prop, "array")) {
|
|
56
|
-
return {
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
kind: "array",
|
|
71
|
+
...prop.items ? { itemSchema: prop.items } : {},
|
|
72
|
+
...layout ? { layout } : {}
|
|
73
|
+
};
|
|
57
74
|
}
|
|
58
75
|
if (isOpenStringMap(prop)) {
|
|
76
|
+
const addl = typeof prop.additionalProperties === "object" && prop.additionalProperties !== null ? prop.additionalProperties : void 0;
|
|
77
|
+
const patterns = patternSchemasOf(prop);
|
|
78
|
+
const allowExtraKeys = keyOptions || patterns ? true : prop.additionalProperties !== false;
|
|
59
79
|
return {
|
|
60
80
|
...base,
|
|
61
81
|
kind: "string-map",
|
|
62
|
-
valueSchema:
|
|
82
|
+
...addl ? { valueSchema: addl } : {},
|
|
83
|
+
...patterns ? { valuePatternSchemas: patterns } : {},
|
|
63
84
|
...prop.properties ? { knownProperties: prop.properties } : {},
|
|
64
|
-
allowExtraKeys
|
|
85
|
+
allowExtraKeys,
|
|
86
|
+
...keyOptions ? { keyOptions } : {},
|
|
87
|
+
...layout ? { layout } : {}
|
|
65
88
|
};
|
|
66
89
|
}
|
|
67
90
|
if (schemaHasType(prop, "object") && prop.properties) {
|
|
@@ -69,14 +92,26 @@ function resolveControl(args) {
|
|
|
69
92
|
...base,
|
|
70
93
|
kind: "object",
|
|
71
94
|
objectProperties: prop.properties,
|
|
72
|
-
...prop.required ? { objectRequired: prop.required } : {}
|
|
95
|
+
...prop.required ? { objectRequired: prop.required } : {},
|
|
96
|
+
...layout ? { layout } : {}
|
|
73
97
|
};
|
|
74
98
|
}
|
|
75
99
|
if (schemaHasType(prop, "object")) {
|
|
76
|
-
return {
|
|
100
|
+
return {
|
|
101
|
+
...base,
|
|
102
|
+
kind: "string-map",
|
|
103
|
+
allowExtraKeys: prop.additionalProperties !== false,
|
|
104
|
+
...keyOptions ? { keyOptions } : {},
|
|
105
|
+
...layout ? { layout } : {}
|
|
106
|
+
};
|
|
77
107
|
}
|
|
78
108
|
return base;
|
|
79
109
|
}
|
|
110
|
+
function keyOptionsFor(prop) {
|
|
111
|
+
const pn = prop.propertyNames;
|
|
112
|
+
if (!pn || !Array.isArray(pn.enum) || pn.enum.length === 0) return void 0;
|
|
113
|
+
return enumOptions(pn);
|
|
114
|
+
}
|
|
80
115
|
function isScalarStringItems(items) {
|
|
81
116
|
if (!items) return true;
|
|
82
117
|
if (items.type !== void 0 && !schemaHasType(items, "string")) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-resolve.cjs","sources":["../../src/components/json-schema-form-resolve.ts"],"sourcesContent":["import type {\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// isOpenStringMap reports whether a property is an object whose entries are\n// described by a sub-schema in `additionalProperties` (a typed key/value map).\nexport function isOpenStringMap(prop: JsonSchemaProperty): boolean {\n return (\n schemaHasType(prop, \"object\") &&\n typeof prop.additionalProperties === \"object\" &&\n prop.additionalProperties !== null\n );\n}\n\nfunction schemaHasType(prop: JsonSchemaProperty, type: string): boolean {\n if (Array.isArray(prop.type)) return prop.type.includes(type as never);\n return prop.type === type;\n}\n\nfunction enumOptions(prop: JsonSchemaProperty): FieldOption[] {\n return (prop.enum ?? []).map((v) => ({ value: String(v), label: String(v) }));\n}\n\n// enumBranch returns the first anyOf/oneOf member carrying a non-empty `enum`,\n// for a union of \"an enum value OR a free-form string\" (e.g. a value-or-token\n// field). It lets such a union render as a dropdown. Returns undefined when no\n// branch enumerates values.\nexport function enumBranch(prop: JsonSchemaProperty): JsonSchemaProperty | undefined {\n for (const branch of [...(prop.anyOf ?? []), ...(prop.oneOf ?? [])]) {\n if (Array.isArray(branch.enum) && branch.enum.length > 0) return branch;\n }\n return undefined;\n}\n\nexport interface ResolveControlArgs {\n key: string;\n prop: JsonSchemaProperty;\n required: boolean;\n value: unknown;\n onChange: (next: unknown) => void;\n}\n\n// resolveControl infers a base, render-ready FieldControl from a property\n// schema. It keys off schema keywords only — never the field name: ascode/token\n// heuristics are layered on by consumer pre-extensions. The one exception is the\n// standard `format: date`/`date-time` keyword, which is a schema-declared signal\n// (not a name guess) and so drives a date control directly. First match wins.\nexport function resolveControl(args: ResolveControlArgs): FieldControl {\n const { key, prop, required, value, onChange } = args;\n const labelIcon = prop[\"x-icon\"];\n const base: FieldControl = {\n key,\n kind: \"string\",\n label: typeof prop.title === \"string\" && prop.title ? prop.title : key,\n required,\n schema: prop,\n value,\n onChange,\n ...(prop.readOnly === true ? { readOnly: true } : {}),\n ...(typeof prop.description === \"string\" ? { description: prop.description } : {}),\n ...(labelIcon != null && labelIcon !== \"\" ? { labelIcon: labelIcon as FieldControl[\"labelIcon\"] } : {}),\n };\n\n if (Array.isArray(prop.enum) && prop.enum.length > 0) {\n return { ...base, kind: \"enum\", options: enumOptions(prop) };\n }\n // A value-or-template union: the enum lives in an anyOf/oneOf branch alongside\n // free-form branches. Render it as a dropdown using that branch's enum; the\n // free-form branches are honoured via a consumer's allowCustomValue pre-ext.\n const branch = enumBranch(prop);\n if (branch) {\n return { ...base, kind: \"enum\", options: enumOptions(branch) };\n }\n // A schema-declared date/date-time string renders as a date control.\n if (prop.format === \"date\" || prop.format === \"date-time\") {\n return { ...base, kind: \"date\", dateFormat: prop.format };\n }\n if (schemaHasType(prop, \"boolean\")) {\n return { ...base, kind: \"boolean\" };\n }\n if (schemaHasType(prop, \"integer\") || schemaHasType(prop, \"number\")) {\n return {\n ...base,\n kind: \"number\",\n coerceNumber: true,\n ...(typeof prop.minimum === \"number\" ? { minimum: prop.minimum } : {}),\n };\n }\n if (schemaHasType(prop, \"array\")) {\n return { ...base, kind: \"array\", ...(prop.items ? { itemSchema: prop.items } : {}) };\n }\n // An open map: object whose entries are described by an additionalProperties\n // sub-schema. Renders as editable key/value rows (+ any known properties).\n if (isOpenStringMap(prop)) {\n return {\n ...base,\n kind: \"string-map\",\n valueSchema: prop.additionalProperties as JsonSchemaProperty,\n ...(prop.properties ? { knownProperties: prop.properties } : {}),\n allowExtraKeys: true,\n };\n }\n // A structured object: fixed `properties`, not an open map. Renders as a\n // nested sub-form (labels, required, if/then) — recursed into by the renderer.\n if (schemaHasType(prop, \"object\") && prop.properties) {\n return {\n ...base,\n kind: \"object\",\n objectProperties: prop.properties,\n ...(prop.required ? { objectRequired: prop.required } : {}),\n };\n }\n // A bare object with neither properties nor an additionalProperties schema:\n // treat as an open string map unless explicitly closed.\n if (schemaHasType(prop, \"object\")) {\n return { ...base, kind: \"string-map\", allowExtraKeys: prop.additionalProperties !== false };\n }\n return base;\n}\n\n// isScalarStringItems reports whether an array's item schema is a plain string\n// with no richer shape — the case the array control renders as compact tags.\n// Anything with an enum/const/properties/items/additionalProperties/allOf needs\n// a real per-item control instead.\nexport function isScalarStringItems(items: JsonSchemaProperty | undefined): boolean {\n if (!items) return true; // untyped items default to string tags\n if (items.type !== undefined && !schemaHasType(items, \"string\")) return false;\n return (\n items.enum === undefined &&\n items.const === undefined &&\n items.properties === undefined &&\n items.items === undefined &&\n items.additionalProperties === undefined &&\n items.allOf === undefined\n );\n}\n\n// matchesIf reports whether the `if` sub-schema holds for the current value:\n// every `if.required` key is present AND every `if.properties[k].const` equals\n// value[k].\nexport function matchesIf(\n ifSchema: JsonSchemaProperty | undefined,\n value: Record<string, unknown>,\n): boolean {\n if (!ifSchema) return false;\n for (const k of ifSchema.required ?? []) {\n if (!(k in value)) return false;\n }\n for (const [k, sub] of Object.entries(ifSchema.properties ?? {})) {\n if (\"const\" in sub && value[k] !== sub.const) return false;\n }\n return true;\n}\n\nexport interface EffectiveProperties {\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n// effectiveProperties merges the schema's base `properties` with each `allOf`\n// member's contribution. An `if`/`then` member contributes `then.properties`\n// only when its `if` matches the current value; an unconditional member (e.g.\n// an inlined `$ref` composition, which carries its own `properties` and no\n// `if`) always contributes. Later members win on key collision; required is the\n// union. Pure and idempotent.\nexport function effectiveProperties(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n): EffectiveProperties {\n const properties: Record<string, JsonSchemaProperty> = { ...(schema.properties ?? {}) };\n const required = new Set(schema.required ?? []);\n for (const clause of schema.allOf ?? []) {\n // Unconditional composition member: merge its own properties/required.\n if (clause.if === undefined && clause.then === undefined) {\n for (const [k, sub] of Object.entries(clause.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of clause.required ?? []) required.add(k);\n continue;\n }\n if (!matchesIf(clause.if, value)) continue;\n const then = clause.then ?? {};\n for (const [k, sub] of Object.entries(then.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of then.required ?? []) required.add(k);\n }\n return { properties, required: [...required] };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-resolve.cjs","sources":["../../src/components/json-schema-form-resolve.ts"],"sourcesContent":["import type {\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// isOpenStringMap reports whether a property is an object whose entries are\n// described by a sub-schema in `additionalProperties` (a typed key/value map) or\n// by `patternProperties` (a per-key-pattern value map). Either makes it an\n// editable key/value control rather than a fixed-property sub-form.\nexport function isOpenStringMap(prop: JsonSchemaProperty): boolean {\n if (!schemaHasType(prop, \"object\")) return false;\n if (typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null) {\n return true;\n }\n return !!prop.patternProperties && Object.keys(prop.patternProperties).length > 0;\n}\n\n// patternSchemasOf compiles a schema's `patternProperties` into the ordered\n// {pattern, schema} list the string-map control matches keys against.\nfunction patternSchemasOf(prop: JsonSchemaProperty): { pattern: string; schema: JsonSchemaProperty }[] | undefined {\n const pp = prop.patternProperties;\n if (!pp || Object.keys(pp).length === 0) return undefined;\n return Object.entries(pp).map(([pattern, schema]) => ({ pattern, schema }));\n}\n\nfunction schemaHasType(prop: JsonSchemaProperty, type: string): boolean {\n if (Array.isArray(prop.type)) return prop.type.includes(type as never);\n return prop.type === type;\n}\n\nfunction enumOptions(prop: JsonSchemaProperty): FieldOption[] {\n return (prop.enum ?? []).map((v) => ({ value: String(v), label: String(v) }));\n}\n\n// enumBranch returns the first anyOf/oneOf member carrying a non-empty `enum`,\n// for a union of \"an enum value OR a free-form string\" (e.g. a value-or-token\n// field). It lets such a union render as a dropdown. Returns undefined when no\n// branch enumerates values.\nexport function enumBranch(prop: JsonSchemaProperty): JsonSchemaProperty | undefined {\n for (const branch of [...(prop.anyOf ?? []), ...(prop.oneOf ?? [])]) {\n if (Array.isArray(branch.enum) && branch.enum.length > 0) return branch;\n }\n return undefined;\n}\n\nexport interface ResolveControlArgs {\n key: string;\n prop: JsonSchemaProperty;\n required: boolean;\n value: unknown;\n onChange: (next: unknown) => void;\n}\n\n// resolveControl infers a base, render-ready FieldControl from a property\n// schema. It keys off schema keywords only — never the field name: ascode/token\n// heuristics are layered on by consumer pre-extensions. The one exception is the\n// standard `format: date`/`date-time` keyword, which is a schema-declared signal\n// (not a name guess) and so drives a date control directly. First match wins.\nexport function resolveControl(args: ResolveControlArgs): FieldControl {\n const { key, prop, required, value, onChange } = args;\n const labelIcon = prop[\"x-icon\"];\n const xLayout = prop[\"x-layout\"];\n const layout =\n xLayout === \"inline\" || xLayout === \"stack\" || xLayout === \"table\" ? xLayout : undefined;\n const keyOptions = keyOptionsFor(prop);\n const base: FieldControl = {\n key,\n kind: \"string\",\n label: typeof prop.title === \"string\" && prop.title ? prop.title : key,\n required,\n schema: prop,\n value,\n onChange,\n ...(prop.readOnly === true ? { readOnly: true } : {}),\n ...(typeof prop.description === \"string\" ? { description: prop.description } : {}),\n ...(labelIcon != null && labelIcon !== \"\" ? { labelIcon: labelIcon as FieldControl[\"labelIcon\"] } : {}),\n };\n\n if (Array.isArray(prop.enum) && prop.enum.length > 0) {\n return { ...base, kind: \"enum\", options: enumOptions(prop) };\n }\n // A value-or-template union: the enum lives in an anyOf/oneOf branch alongside\n // free-form branches. Render it as a dropdown using that branch's enum; the\n // free-form branches are honoured via a consumer's allowCustomValue pre-ext.\n const branch = enumBranch(prop);\n if (branch) {\n return { ...base, kind: \"enum\", options: enumOptions(branch) };\n }\n // A schema-declared date/date-time string renders as a date control.\n if (prop.format === \"date\" || prop.format === \"date-time\") {\n return { ...base, kind: \"date\", dateFormat: prop.format };\n }\n if (schemaHasType(prop, \"boolean\")) {\n return { ...base, kind: \"boolean\" };\n }\n if (schemaHasType(prop, \"integer\") || schemaHasType(prop, \"number\")) {\n return {\n ...base,\n kind: \"number\",\n coerceNumber: true,\n ...(typeof prop.minimum === \"number\" ? { minimum: prop.minimum } : {}),\n };\n }\n if (schemaHasType(prop, \"array\")) {\n return {\n ...base,\n kind: \"array\",\n ...(prop.items ? { itemSchema: prop.items } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // An open map: object whose entries are described by an additionalProperties\n // sub-schema and/or per-key patternProperties. Renders as editable key/value\n // rows (+ any known properties), with the value form resolved per key.\n if (isOpenStringMap(prop)) {\n const addl =\n typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null\n ? (prop.additionalProperties as JsonSchemaProperty)\n : undefined;\n const patterns = patternSchemasOf(prop);\n // A constrained picker (propertyNames enum) or patternProperties still lets\n // the author ADD keys — the additions are limited to the allowed set, not\n // free-form — so `additionalProperties: false` doesn't disable \"Add field\"\n // in that case. It only closes a plain open map with no key constraints.\n const allowExtraKeys = keyOptions || patterns ? true : prop.additionalProperties !== false;\n return {\n ...base,\n kind: \"string-map\",\n ...(addl ? { valueSchema: addl } : {}),\n ...(patterns ? { valuePatternSchemas: patterns } : {}),\n ...(prop.properties ? { knownProperties: prop.properties } : {}),\n allowExtraKeys,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A structured object: fixed `properties`, not an open map. Renders as a\n // nested sub-form (labels, required, if/then) — recursed into by the renderer.\n if (schemaHasType(prop, \"object\") && prop.properties) {\n return {\n ...base,\n kind: \"object\",\n objectProperties: prop.properties,\n ...(prop.required ? { objectRequired: prop.required } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A bare object with neither properties nor an additionalProperties schema:\n // treat as an open string map unless explicitly closed.\n if (schemaHasType(prop, \"object\")) {\n return {\n ...base,\n kind: \"string-map\",\n allowExtraKeys: prop.additionalProperties !== false,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n return base;\n}\n\n// keyOptionsFor resolves the strict map-key picker options from a map schema's\n// `propertyNames.enum` (e.g. an AsCode-constrained key set). Returns undefined\n// when the keys are unconstrained, so the key stays free-text.\nfunction keyOptionsFor(prop: JsonSchemaProperty): FieldOption[] | undefined {\n const pn = prop.propertyNames as JsonSchemaProperty | undefined;\n if (!pn || !Array.isArray(pn.enum) || pn.enum.length === 0) return undefined;\n return enumOptions(pn);\n}\n\n// isScalarStringItems reports whether an array's item schema is a plain string\n// with no richer shape — the case the array control renders as compact tags.\n// Anything with an enum/const/properties/items/additionalProperties/allOf needs\n// a real per-item control instead.\nexport function isScalarStringItems(items: JsonSchemaProperty | undefined): boolean {\n if (!items) return true; // untyped items default to string tags\n if (items.type !== undefined && !schemaHasType(items, \"string\")) return false;\n return (\n items.enum === undefined &&\n items.const === undefined &&\n items.properties === undefined &&\n items.items === undefined &&\n items.additionalProperties === undefined &&\n items.allOf === undefined\n );\n}\n\n// matchesIf reports whether the `if` sub-schema holds for the current value:\n// every `if.required` key is present AND every `if.properties[k].const` equals\n// value[k].\nexport function matchesIf(\n ifSchema: JsonSchemaProperty | undefined,\n value: Record<string, unknown>,\n): boolean {\n if (!ifSchema) return false;\n for (const k of ifSchema.required ?? []) {\n if (!(k in value)) return false;\n }\n for (const [k, sub] of Object.entries(ifSchema.properties ?? {})) {\n if (\"const\" in sub && value[k] !== sub.const) return false;\n }\n return true;\n}\n\nexport interface EffectiveProperties {\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n// effectiveProperties merges the schema's base `properties` with each `allOf`\n// member's contribution. An `if`/`then` member contributes `then.properties`\n// only when its `if` matches the current value; an unconditional member (e.g.\n// an inlined `$ref` composition, which carries its own `properties` and no\n// `if`) always contributes. Later members win on key collision; required is the\n// union. Pure and idempotent.\nexport function effectiveProperties(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n): EffectiveProperties {\n const properties: Record<string, JsonSchemaProperty> = { ...(schema.properties ?? {}) };\n const required = new Set(schema.required ?? []);\n for (const clause of schema.allOf ?? []) {\n // Unconditional composition member: merge its own properties/required.\n if (clause.if === undefined && clause.then === undefined) {\n for (const [k, sub] of Object.entries(clause.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of clause.required ?? []) required.add(k);\n continue;\n }\n if (!matchesIf(clause.if, value)) continue;\n const then = clause.then ?? {};\n for (const [k, sub] of Object.entries(then.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of then.required ?? []) required.add(k);\n }\n return { properties, required: [...required] };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-resolve.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"json-schema-form-resolve.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAMlC,wBAAgB,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAMjE;AAuBD,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,SAAS,CAKnF;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAOD,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,YAAY,CAqGrE;AAeD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAWlF;AAKD,wBAAgB,SAAS,CACvB,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAST;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC/C,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAQD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,mBAAmB,CAoBrB"}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
function isOpenStringMap(prop) {
|
|
2
|
-
|
|
2
|
+
if (!schemaHasType(prop, "object")) return false;
|
|
3
|
+
if (typeof prop.additionalProperties === "object" && prop.additionalProperties !== null) {
|
|
4
|
+
return true;
|
|
5
|
+
}
|
|
6
|
+
return !!prop.patternProperties && Object.keys(prop.patternProperties).length > 0;
|
|
7
|
+
}
|
|
8
|
+
function patternSchemasOf(prop) {
|
|
9
|
+
const pp = prop.patternProperties;
|
|
10
|
+
if (!pp || Object.keys(pp).length === 0) return void 0;
|
|
11
|
+
return Object.entries(pp).map(([pattern, schema]) => ({ pattern, schema }));
|
|
3
12
|
}
|
|
4
13
|
function schemaHasType(prop, type) {
|
|
5
14
|
if (Array.isArray(prop.type)) return prop.type.includes(type);
|
|
@@ -17,6 +26,9 @@ function enumBranch(prop) {
|
|
|
17
26
|
function resolveControl(args) {
|
|
18
27
|
const { key, prop, required, value, onChange } = args;
|
|
19
28
|
const labelIcon = prop["x-icon"];
|
|
29
|
+
const xLayout = prop["x-layout"];
|
|
30
|
+
const layout = xLayout === "inline" || xLayout === "stack" || xLayout === "table" ? xLayout : void 0;
|
|
31
|
+
const keyOptions = keyOptionsFor(prop);
|
|
20
32
|
const base = {
|
|
21
33
|
key,
|
|
22
34
|
kind: "string",
|
|
@@ -51,15 +63,26 @@ function resolveControl(args) {
|
|
|
51
63
|
};
|
|
52
64
|
}
|
|
53
65
|
if (schemaHasType(prop, "array")) {
|
|
54
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
...base,
|
|
68
|
+
kind: "array",
|
|
69
|
+
...prop.items ? { itemSchema: prop.items } : {},
|
|
70
|
+
...layout ? { layout } : {}
|
|
71
|
+
};
|
|
55
72
|
}
|
|
56
73
|
if (isOpenStringMap(prop)) {
|
|
74
|
+
const addl = typeof prop.additionalProperties === "object" && prop.additionalProperties !== null ? prop.additionalProperties : void 0;
|
|
75
|
+
const patterns = patternSchemasOf(prop);
|
|
76
|
+
const allowExtraKeys = keyOptions || patterns ? true : prop.additionalProperties !== false;
|
|
57
77
|
return {
|
|
58
78
|
...base,
|
|
59
79
|
kind: "string-map",
|
|
60
|
-
valueSchema:
|
|
80
|
+
...addl ? { valueSchema: addl } : {},
|
|
81
|
+
...patterns ? { valuePatternSchemas: patterns } : {},
|
|
61
82
|
...prop.properties ? { knownProperties: prop.properties } : {},
|
|
62
|
-
allowExtraKeys
|
|
83
|
+
allowExtraKeys,
|
|
84
|
+
...keyOptions ? { keyOptions } : {},
|
|
85
|
+
...layout ? { layout } : {}
|
|
63
86
|
};
|
|
64
87
|
}
|
|
65
88
|
if (schemaHasType(prop, "object") && prop.properties) {
|
|
@@ -67,14 +90,26 @@ function resolveControl(args) {
|
|
|
67
90
|
...base,
|
|
68
91
|
kind: "object",
|
|
69
92
|
objectProperties: prop.properties,
|
|
70
|
-
...prop.required ? { objectRequired: prop.required } : {}
|
|
93
|
+
...prop.required ? { objectRequired: prop.required } : {},
|
|
94
|
+
...layout ? { layout } : {}
|
|
71
95
|
};
|
|
72
96
|
}
|
|
73
97
|
if (schemaHasType(prop, "object")) {
|
|
74
|
-
return {
|
|
98
|
+
return {
|
|
99
|
+
...base,
|
|
100
|
+
kind: "string-map",
|
|
101
|
+
allowExtraKeys: prop.additionalProperties !== false,
|
|
102
|
+
...keyOptions ? { keyOptions } : {},
|
|
103
|
+
...layout ? { layout } : {}
|
|
104
|
+
};
|
|
75
105
|
}
|
|
76
106
|
return base;
|
|
77
107
|
}
|
|
108
|
+
function keyOptionsFor(prop) {
|
|
109
|
+
const pn = prop.propertyNames;
|
|
110
|
+
if (!pn || !Array.isArray(pn.enum) || pn.enum.length === 0) return void 0;
|
|
111
|
+
return enumOptions(pn);
|
|
112
|
+
}
|
|
78
113
|
function isScalarStringItems(items) {
|
|
79
114
|
if (!items) return true;
|
|
80
115
|
if (items.type !== void 0 && !schemaHasType(items, "string")) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-resolve.js","sources":["../../src/components/json-schema-form-resolve.ts"],"sourcesContent":["import type {\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// isOpenStringMap reports whether a property is an object whose entries are\n// described by a sub-schema in `additionalProperties` (a typed key/value map).\nexport function isOpenStringMap(prop: JsonSchemaProperty): boolean {\n return (\n schemaHasType(prop, \"object\") &&\n typeof prop.additionalProperties === \"object\" &&\n prop.additionalProperties !== null\n );\n}\n\nfunction schemaHasType(prop: JsonSchemaProperty, type: string): boolean {\n if (Array.isArray(prop.type)) return prop.type.includes(type as never);\n return prop.type === type;\n}\n\nfunction enumOptions(prop: JsonSchemaProperty): FieldOption[] {\n return (prop.enum ?? []).map((v) => ({ value: String(v), label: String(v) }));\n}\n\n// enumBranch returns the first anyOf/oneOf member carrying a non-empty `enum`,\n// for a union of \"an enum value OR a free-form string\" (e.g. a value-or-token\n// field). It lets such a union render as a dropdown. Returns undefined when no\n// branch enumerates values.\nexport function enumBranch(prop: JsonSchemaProperty): JsonSchemaProperty | undefined {\n for (const branch of [...(prop.anyOf ?? []), ...(prop.oneOf ?? [])]) {\n if (Array.isArray(branch.enum) && branch.enum.length > 0) return branch;\n }\n return undefined;\n}\n\nexport interface ResolveControlArgs {\n key: string;\n prop: JsonSchemaProperty;\n required: boolean;\n value: unknown;\n onChange: (next: unknown) => void;\n}\n\n// resolveControl infers a base, render-ready FieldControl from a property\n// schema. It keys off schema keywords only — never the field name: ascode/token\n// heuristics are layered on by consumer pre-extensions. The one exception is the\n// standard `format: date`/`date-time` keyword, which is a schema-declared signal\n// (not a name guess) and so drives a date control directly. First match wins.\nexport function resolveControl(args: ResolveControlArgs): FieldControl {\n const { key, prop, required, value, onChange } = args;\n const labelIcon = prop[\"x-icon\"];\n const base: FieldControl = {\n key,\n kind: \"string\",\n label: typeof prop.title === \"string\" && prop.title ? prop.title : key,\n required,\n schema: prop,\n value,\n onChange,\n ...(prop.readOnly === true ? { readOnly: true } : {}),\n ...(typeof prop.description === \"string\" ? { description: prop.description } : {}),\n ...(labelIcon != null && labelIcon !== \"\" ? { labelIcon: labelIcon as FieldControl[\"labelIcon\"] } : {}),\n };\n\n if (Array.isArray(prop.enum) && prop.enum.length > 0) {\n return { ...base, kind: \"enum\", options: enumOptions(prop) };\n }\n // A value-or-template union: the enum lives in an anyOf/oneOf branch alongside\n // free-form branches. Render it as a dropdown using that branch's enum; the\n // free-form branches are honoured via a consumer's allowCustomValue pre-ext.\n const branch = enumBranch(prop);\n if (branch) {\n return { ...base, kind: \"enum\", options: enumOptions(branch) };\n }\n // A schema-declared date/date-time string renders as a date control.\n if (prop.format === \"date\" || prop.format === \"date-time\") {\n return { ...base, kind: \"date\", dateFormat: prop.format };\n }\n if (schemaHasType(prop, \"boolean\")) {\n return { ...base, kind: \"boolean\" };\n }\n if (schemaHasType(prop, \"integer\") || schemaHasType(prop, \"number\")) {\n return {\n ...base,\n kind: \"number\",\n coerceNumber: true,\n ...(typeof prop.minimum === \"number\" ? { minimum: prop.minimum } : {}),\n };\n }\n if (schemaHasType(prop, \"array\")) {\n return { ...base, kind: \"array\", ...(prop.items ? { itemSchema: prop.items } : {}) };\n }\n // An open map: object whose entries are described by an additionalProperties\n // sub-schema. Renders as editable key/value rows (+ any known properties).\n if (isOpenStringMap(prop)) {\n return {\n ...base,\n kind: \"string-map\",\n valueSchema: prop.additionalProperties as JsonSchemaProperty,\n ...(prop.properties ? { knownProperties: prop.properties } : {}),\n allowExtraKeys: true,\n };\n }\n // A structured object: fixed `properties`, not an open map. Renders as a\n // nested sub-form (labels, required, if/then) — recursed into by the renderer.\n if (schemaHasType(prop, \"object\") && prop.properties) {\n return {\n ...base,\n kind: \"object\",\n objectProperties: prop.properties,\n ...(prop.required ? { objectRequired: prop.required } : {}),\n };\n }\n // A bare object with neither properties nor an additionalProperties schema:\n // treat as an open string map unless explicitly closed.\n if (schemaHasType(prop, \"object\")) {\n return { ...base, kind: \"string-map\", allowExtraKeys: prop.additionalProperties !== false };\n }\n return base;\n}\n\n// isScalarStringItems reports whether an array's item schema is a plain string\n// with no richer shape — the case the array control renders as compact tags.\n// Anything with an enum/const/properties/items/additionalProperties/allOf needs\n// a real per-item control instead.\nexport function isScalarStringItems(items: JsonSchemaProperty | undefined): boolean {\n if (!items) return true; // untyped items default to string tags\n if (items.type !== undefined && !schemaHasType(items, \"string\")) return false;\n return (\n items.enum === undefined &&\n items.const === undefined &&\n items.properties === undefined &&\n items.items === undefined &&\n items.additionalProperties === undefined &&\n items.allOf === undefined\n );\n}\n\n// matchesIf reports whether the `if` sub-schema holds for the current value:\n// every `if.required` key is present AND every `if.properties[k].const` equals\n// value[k].\nexport function matchesIf(\n ifSchema: JsonSchemaProperty | undefined,\n value: Record<string, unknown>,\n): boolean {\n if (!ifSchema) return false;\n for (const k of ifSchema.required ?? []) {\n if (!(k in value)) return false;\n }\n for (const [k, sub] of Object.entries(ifSchema.properties ?? {})) {\n if (\"const\" in sub && value[k] !== sub.const) return false;\n }\n return true;\n}\n\nexport interface EffectiveProperties {\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n// effectiveProperties merges the schema's base `properties` with each `allOf`\n// member's contribution. An `if`/`then` member contributes `then.properties`\n// only when its `if` matches the current value; an unconditional member (e.g.\n// an inlined `$ref` composition, which carries its own `properties` and no\n// `if`) always contributes. Later members win on key collision; required is the\n// union. Pure and idempotent.\nexport function effectiveProperties(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n): EffectiveProperties {\n const properties: Record<string, JsonSchemaProperty> = { ...(schema.properties ?? {}) };\n const required = new Set(schema.required ?? []);\n for (const clause of schema.allOf ?? []) {\n // Unconditional composition member: merge its own properties/required.\n if (clause.if === undefined && clause.then === undefined) {\n for (const [k, sub] of Object.entries(clause.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of clause.required ?? []) required.add(k);\n continue;\n }\n if (!matchesIf(clause.if, value)) continue;\n const then = clause.then ?? {};\n for (const [k, sub] of Object.entries(then.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of then.required ?? []) required.add(k);\n }\n return { properties, required: [...required] };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-resolve.js","sources":["../../src/components/json-schema-form-resolve.ts"],"sourcesContent":["import type {\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// isOpenStringMap reports whether a property is an object whose entries are\n// described by a sub-schema in `additionalProperties` (a typed key/value map) or\n// by `patternProperties` (a per-key-pattern value map). Either makes it an\n// editable key/value control rather than a fixed-property sub-form.\nexport function isOpenStringMap(prop: JsonSchemaProperty): boolean {\n if (!schemaHasType(prop, \"object\")) return false;\n if (typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null) {\n return true;\n }\n return !!prop.patternProperties && Object.keys(prop.patternProperties).length > 0;\n}\n\n// patternSchemasOf compiles a schema's `patternProperties` into the ordered\n// {pattern, schema} list the string-map control matches keys against.\nfunction patternSchemasOf(prop: JsonSchemaProperty): { pattern: string; schema: JsonSchemaProperty }[] | undefined {\n const pp = prop.patternProperties;\n if (!pp || Object.keys(pp).length === 0) return undefined;\n return Object.entries(pp).map(([pattern, schema]) => ({ pattern, schema }));\n}\n\nfunction schemaHasType(prop: JsonSchemaProperty, type: string): boolean {\n if (Array.isArray(prop.type)) return prop.type.includes(type as never);\n return prop.type === type;\n}\n\nfunction enumOptions(prop: JsonSchemaProperty): FieldOption[] {\n return (prop.enum ?? []).map((v) => ({ value: String(v), label: String(v) }));\n}\n\n// enumBranch returns the first anyOf/oneOf member carrying a non-empty `enum`,\n// for a union of \"an enum value OR a free-form string\" (e.g. a value-or-token\n// field). It lets such a union render as a dropdown. Returns undefined when no\n// branch enumerates values.\nexport function enumBranch(prop: JsonSchemaProperty): JsonSchemaProperty | undefined {\n for (const branch of [...(prop.anyOf ?? []), ...(prop.oneOf ?? [])]) {\n if (Array.isArray(branch.enum) && branch.enum.length > 0) return branch;\n }\n return undefined;\n}\n\nexport interface ResolveControlArgs {\n key: string;\n prop: JsonSchemaProperty;\n required: boolean;\n value: unknown;\n onChange: (next: unknown) => void;\n}\n\n// resolveControl infers a base, render-ready FieldControl from a property\n// schema. It keys off schema keywords only — never the field name: ascode/token\n// heuristics are layered on by consumer pre-extensions. The one exception is the\n// standard `format: date`/`date-time` keyword, which is a schema-declared signal\n// (not a name guess) and so drives a date control directly. First match wins.\nexport function resolveControl(args: ResolveControlArgs): FieldControl {\n const { key, prop, required, value, onChange } = args;\n const labelIcon = prop[\"x-icon\"];\n const xLayout = prop[\"x-layout\"];\n const layout =\n xLayout === \"inline\" || xLayout === \"stack\" || xLayout === \"table\" ? xLayout : undefined;\n const keyOptions = keyOptionsFor(prop);\n const base: FieldControl = {\n key,\n kind: \"string\",\n label: typeof prop.title === \"string\" && prop.title ? prop.title : key,\n required,\n schema: prop,\n value,\n onChange,\n ...(prop.readOnly === true ? { readOnly: true } : {}),\n ...(typeof prop.description === \"string\" ? { description: prop.description } : {}),\n ...(labelIcon != null && labelIcon !== \"\" ? { labelIcon: labelIcon as FieldControl[\"labelIcon\"] } : {}),\n };\n\n if (Array.isArray(prop.enum) && prop.enum.length > 0) {\n return { ...base, kind: \"enum\", options: enumOptions(prop) };\n }\n // A value-or-template union: the enum lives in an anyOf/oneOf branch alongside\n // free-form branches. Render it as a dropdown using that branch's enum; the\n // free-form branches are honoured via a consumer's allowCustomValue pre-ext.\n const branch = enumBranch(prop);\n if (branch) {\n return { ...base, kind: \"enum\", options: enumOptions(branch) };\n }\n // A schema-declared date/date-time string renders as a date control.\n if (prop.format === \"date\" || prop.format === \"date-time\") {\n return { ...base, kind: \"date\", dateFormat: prop.format };\n }\n if (schemaHasType(prop, \"boolean\")) {\n return { ...base, kind: \"boolean\" };\n }\n if (schemaHasType(prop, \"integer\") || schemaHasType(prop, \"number\")) {\n return {\n ...base,\n kind: \"number\",\n coerceNumber: true,\n ...(typeof prop.minimum === \"number\" ? { minimum: prop.minimum } : {}),\n };\n }\n if (schemaHasType(prop, \"array\")) {\n return {\n ...base,\n kind: \"array\",\n ...(prop.items ? { itemSchema: prop.items } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // An open map: object whose entries are described by an additionalProperties\n // sub-schema and/or per-key patternProperties. Renders as editable key/value\n // rows (+ any known properties), with the value form resolved per key.\n if (isOpenStringMap(prop)) {\n const addl =\n typeof prop.additionalProperties === \"object\" && prop.additionalProperties !== null\n ? (prop.additionalProperties as JsonSchemaProperty)\n : undefined;\n const patterns = patternSchemasOf(prop);\n // A constrained picker (propertyNames enum) or patternProperties still lets\n // the author ADD keys — the additions are limited to the allowed set, not\n // free-form — so `additionalProperties: false` doesn't disable \"Add field\"\n // in that case. It only closes a plain open map with no key constraints.\n const allowExtraKeys = keyOptions || patterns ? true : prop.additionalProperties !== false;\n return {\n ...base,\n kind: \"string-map\",\n ...(addl ? { valueSchema: addl } : {}),\n ...(patterns ? { valuePatternSchemas: patterns } : {}),\n ...(prop.properties ? { knownProperties: prop.properties } : {}),\n allowExtraKeys,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A structured object: fixed `properties`, not an open map. Renders as a\n // nested sub-form (labels, required, if/then) — recursed into by the renderer.\n if (schemaHasType(prop, \"object\") && prop.properties) {\n return {\n ...base,\n kind: \"object\",\n objectProperties: prop.properties,\n ...(prop.required ? { objectRequired: prop.required } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n // A bare object with neither properties nor an additionalProperties schema:\n // treat as an open string map unless explicitly closed.\n if (schemaHasType(prop, \"object\")) {\n return {\n ...base,\n kind: \"string-map\",\n allowExtraKeys: prop.additionalProperties !== false,\n ...(keyOptions ? { keyOptions } : {}),\n ...(layout ? { layout } : {}),\n };\n }\n return base;\n}\n\n// keyOptionsFor resolves the strict map-key picker options from a map schema's\n// `propertyNames.enum` (e.g. an AsCode-constrained key set). Returns undefined\n// when the keys are unconstrained, so the key stays free-text.\nfunction keyOptionsFor(prop: JsonSchemaProperty): FieldOption[] | undefined {\n const pn = prop.propertyNames as JsonSchemaProperty | undefined;\n if (!pn || !Array.isArray(pn.enum) || pn.enum.length === 0) return undefined;\n return enumOptions(pn);\n}\n\n// isScalarStringItems reports whether an array's item schema is a plain string\n// with no richer shape — the case the array control renders as compact tags.\n// Anything with an enum/const/properties/items/additionalProperties/allOf needs\n// a real per-item control instead.\nexport function isScalarStringItems(items: JsonSchemaProperty | undefined): boolean {\n if (!items) return true; // untyped items default to string tags\n if (items.type !== undefined && !schemaHasType(items, \"string\")) return false;\n return (\n items.enum === undefined &&\n items.const === undefined &&\n items.properties === undefined &&\n items.items === undefined &&\n items.additionalProperties === undefined &&\n items.allOf === undefined\n );\n}\n\n// matchesIf reports whether the `if` sub-schema holds for the current value:\n// every `if.required` key is present AND every `if.properties[k].const` equals\n// value[k].\nexport function matchesIf(\n ifSchema: JsonSchemaProperty | undefined,\n value: Record<string, unknown>,\n): boolean {\n if (!ifSchema) return false;\n for (const k of ifSchema.required ?? []) {\n if (!(k in value)) return false;\n }\n for (const [k, sub] of Object.entries(ifSchema.properties ?? {})) {\n if (\"const\" in sub && value[k] !== sub.const) return false;\n }\n return true;\n}\n\nexport interface EffectiveProperties {\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n// effectiveProperties merges the schema's base `properties` with each `allOf`\n// member's contribution. An `if`/`then` member contributes `then.properties`\n// only when its `if` matches the current value; an unconditional member (e.g.\n// an inlined `$ref` composition, which carries its own `properties` and no\n// `if`) always contributes. Later members win on key collision; required is the\n// union. Pure and idempotent.\nexport function effectiveProperties(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n): EffectiveProperties {\n const properties: Record<string, JsonSchemaProperty> = { ...(schema.properties ?? {}) };\n const required = new Set(schema.required ?? []);\n for (const clause of schema.allOf ?? []) {\n // Unconditional composition member: merge its own properties/required.\n if (clause.if === undefined && clause.then === undefined) {\n for (const [k, sub] of Object.entries(clause.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of clause.required ?? []) required.add(k);\n continue;\n }\n if (!matchesIf(clause.if, value)) continue;\n const then = clause.then ?? {};\n for (const [k, sub] of Object.entries(then.properties ?? {})) {\n properties[k] = sub;\n }\n for (const k of then.required ?? []) required.add(k);\n }\n return { properties, required: [...required] };\n}\n"],"names":[],"mappings":"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"}
|