@flanksource/clicky-ui 0.2.9 → 0.2.10

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.
@@ -3,12 +3,24 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const utils = require("../lib/utils.cjs");
5
5
  const jsonSchemaFormRender = require("./json-schema-form-render.cjs");
6
+ const DEFAULT_LABEL_MAX_WIDTH = "40ch";
7
+ const DEFAULT_VALUE_MAX_WIDTH = "400px";
8
+ function resolveFormLayout(layout, inline) {
9
+ const base = layout ?? { mode: inline ? "inline" : "stacked" };
10
+ if (base.mode !== "inline") return { mode: "stacked" };
11
+ return {
12
+ mode: "inline",
13
+ labelMaxWidth: base.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,
14
+ valueMaxWidth: base.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH
15
+ };
16
+ }
6
17
  function JsonSchemaForm({
7
18
  schema,
8
19
  value,
9
20
  onChange,
10
21
  readOnly = false,
11
22
  inline = false,
23
+ layout,
12
24
  hideReadOnlyFields = false,
13
25
  hiddenKeys,
14
26
  requiredFirst = false,
@@ -16,10 +28,11 @@ function JsonSchemaForm({
16
28
  pre,
17
29
  post
18
30
  }) {
31
+ const resolvedLayout = resolveFormLayout(layout, inline);
19
32
  const ctx = {
20
33
  readOnly,
21
34
  hideReadOnlyFields,
22
- inline,
35
+ layout: resolvedLayout,
23
36
  requiredFirst,
24
37
  pre: pre ?? [],
25
38
  post: post ?? [],
@@ -28,7 +41,7 @@ function JsonSchemaForm({
28
41
  const rows = jsonSchemaFormRender.renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : void 0);
29
42
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
30
43
  title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold", children: title }),
31
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn(inline ? "grid gap-2" : "grid gap-4"), children: rows })
44
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn(resolvedLayout.mode === "inline" ? "grid gap-2" : "grid gap-4"), children: rows })
32
45
  ] });
33
46
  }
34
47
  exports.JsonSchemaForm = JsonSchemaForm;
@@ -1 +1 @@
1
- {"version":3,"file":"JsonSchemaForm.cjs","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\nimport { renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type { JsonSchemaFormProps } from \"./json-schema-form-types\";\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n}: JsonSchemaFormProps) {\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n inline,\n requiredFirst,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className=\"space-y-3\">\n {title && <h3 className=\"text-sm font-semibold\">{title}</h3>}\n <div className={cn(inline ? \"grid gap-2\" : \"grid gap-4\")}>{rows}</div>\n </div>\n );\n}\n"],"names":["renderObjectFields","jsxs","jsx","cn"],"mappings":";;;;;AASO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,MAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,OAAO,CAAA;AAAA,IACZ,MAAM,QAAQ,CAAA;AAAA,IACd,OAAO;AAAA,EAAA;AAET,QAAM,OAAOA,qBAAAA,mBAAmB,QAAQ,OAAO,UAAU,KAAK,aAAa,EAAE,WAAA,IAAe,MAAS;AAErG,SACEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,aACZ,UAAA;AAAA,IAAA,SAASC,2BAAAA,IAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IACvDA,+BAAC,SAAI,WAAWC,MAAAA,GAAG,SAAS,eAAe,YAAY,GAAI,UAAA,KAAA,CAAK;AAAA,EAAA,GAClE;AAEJ;;"}
1
+ {"version":3,"file":"JsonSchemaForm.cjs","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\nimport { renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type { FormLayout, JsonSchemaFormProps } from \"./json-schema-form-types\";\n\nconst DEFAULT_LABEL_MAX_WIDTH = \"40ch\";\nconst DEFAULT_VALUE_MAX_WIDTH = \"400px\";\n\n// resolveFormLayout maps the `layout`/`inline` props to a single resolved\n// FormLayout. An explicit `layout` wins; otherwise `inline` selects the inline\n// preset. Width caps are only filled for inline mode.\nfunction resolveFormLayout(layout: FormLayout | undefined, inline: boolean): FormLayout {\n const base = layout ?? { mode: inline ? \"inline\" : \"stacked\" };\n if (base.mode !== \"inline\") return { mode: \"stacked\" };\n return {\n mode: \"inline\",\n labelMaxWidth: base.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,\n valueMaxWidth: base.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH,\n };\n}\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n layout,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n}: JsonSchemaFormProps) {\n const resolvedLayout = resolveFormLayout(layout, inline);\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n layout: resolvedLayout,\n requiredFirst,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className=\"space-y-3\">\n {title && <h3 className=\"text-sm font-semibold\">{title}</h3>}\n <div className={cn(resolvedLayout.mode === \"inline\" ? \"grid gap-2\" : \"grid gap-4\")}>{rows}</div>\n </div>\n );\n}\n"],"names":["renderObjectFields","jsxs","jsx","cn"],"mappings":";;;;;AAIA,MAAM,0BAA0B;AAChC,MAAM,0BAA0B;AAKhC,SAAS,kBAAkB,QAAgC,QAA6B;AACtF,QAAM,OAAO,UAAU,EAAE,MAAM,SAAS,WAAW,UAAA;AACnD,MAAI,KAAK,SAAS,SAAU,QAAO,EAAE,MAAM,UAAA;AAC3C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,KAAK,iBAAiB;AAAA,IACrC,eAAe,KAAK,iBAAiB;AAAA,EAAA;AAEzC;AAOO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT;AAAA,EACA,qBAAqB;AAAA,EACrB;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,iBAAiB,kBAAkB,QAAQ,MAAM;AACvD,QAAM,MAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,KAAK,OAAO,CAAA;AAAA,IACZ,MAAM,QAAQ,CAAA;AAAA,IACd,OAAO;AAAA,EAAA;AAET,QAAM,OAAOA,qBAAAA,mBAAmB,QAAQ,OAAO,UAAU,KAAK,aAAa,EAAE,WAAA,IAAe,MAAS;AAErG,SACEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,aACZ,UAAA;AAAA,IAAA,SAASC,2BAAAA,IAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IACvDA,2BAAAA,IAAC,OAAA,EAAI,WAAWC,MAAAA,GAAG,eAAe,SAAS,WAAW,eAAe,YAAY,GAAI,UAAA,KAAA,CAAK;AAAA,EAAA,GAC5F;AAEJ;;"}
@@ -1,3 +1,3 @@
1
1
  import { JsonSchemaFormProps } from './json-schema-form-types';
2
- export declare function JsonSchemaForm({ schema, value, onChange, readOnly, inline, hideReadOnlyFields, hiddenKeys, requiredFirst, title, pre, post, }: JsonSchemaFormProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function JsonSchemaForm({ schema, value, onChange, readOnly, inline, layout, hideReadOnlyFields, hiddenKeys, requiredFirst, title, pre, post, }: JsonSchemaFormProps): import("react/jsx-runtime").JSX.Element;
3
3
  //# sourceMappingURL=JsonSchemaForm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JsonSchemaForm.d.ts","sourceRoot":"","sources":["../../src/components/JsonSchemaForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAOpE,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,MAAc,EACd,kBAA0B,EAC1B,UAAU,EACV,aAAqB,EACrB,KAAK,EACL,GAAG,EACH,IAAI,GACL,EAAE,mBAAmB,2CAkBrB"}
1
+ {"version":3,"file":"JsonSchemaForm.d.ts","sourceRoot":"","sources":["../../src/components/JsonSchemaForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAuBhF,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAgB,EAChB,MAAc,EACd,MAAM,EACN,kBAA0B,EAC1B,UAAU,EACV,aAAqB,EACrB,KAAK,EACL,GAAG,EACH,IAAI,GACL,EAAE,mBAAmB,2CAmBrB"}
@@ -1,12 +1,24 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { cn } from "../lib/utils.js";
3
3
  import { renderObjectFields } from "./json-schema-form-render.js";
4
+ const DEFAULT_LABEL_MAX_WIDTH = "40ch";
5
+ const DEFAULT_VALUE_MAX_WIDTH = "400px";
6
+ function resolveFormLayout(layout, inline) {
7
+ const base = layout ?? { mode: inline ? "inline" : "stacked" };
8
+ if (base.mode !== "inline") return { mode: "stacked" };
9
+ return {
10
+ mode: "inline",
11
+ labelMaxWidth: base.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,
12
+ valueMaxWidth: base.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH
13
+ };
14
+ }
4
15
  function JsonSchemaForm({
5
16
  schema,
6
17
  value,
7
18
  onChange,
8
19
  readOnly = false,
9
20
  inline = false,
21
+ layout,
10
22
  hideReadOnlyFields = false,
11
23
  hiddenKeys,
12
24
  requiredFirst = false,
@@ -14,10 +26,11 @@ function JsonSchemaForm({
14
26
  pre,
15
27
  post
16
28
  }) {
29
+ const resolvedLayout = resolveFormLayout(layout, inline);
17
30
  const ctx = {
18
31
  readOnly,
19
32
  hideReadOnlyFields,
20
- inline,
33
+ layout: resolvedLayout,
21
34
  requiredFirst,
22
35
  pre: pre ?? [],
23
36
  post: post ?? [],
@@ -26,7 +39,7 @@ function JsonSchemaForm({
26
39
  const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : void 0);
27
40
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
28
41
  title && /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: title }),
29
- /* @__PURE__ */ jsx("div", { className: cn(inline ? "grid gap-2" : "grid gap-4"), children: rows })
42
+ /* @__PURE__ */ jsx("div", { className: cn(resolvedLayout.mode === "inline" ? "grid gap-2" : "grid gap-4"), children: rows })
30
43
  ] });
31
44
  }
32
45
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"JsonSchemaForm.js","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\nimport { renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type { JsonSchemaFormProps } from \"./json-schema-form-types\";\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n}: JsonSchemaFormProps) {\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n inline,\n requiredFirst,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className=\"space-y-3\">\n {title && <h3 className=\"text-sm font-semibold\">{title}</h3>}\n <div className={cn(inline ? \"grid gap-2\" : \"grid gap-4\")}>{rows}</div>\n </div>\n );\n}\n"],"names":[],"mappings":";;;AASO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,MAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,OAAO,CAAA;AAAA,IACZ,MAAM,QAAQ,CAAA;AAAA,IACd,OAAO;AAAA,EAAA;AAET,QAAM,OAAO,mBAAmB,QAAQ,OAAO,UAAU,KAAK,aAAa,EAAE,WAAA,IAAe,MAAS;AAErG,SACE,qBAAC,OAAA,EAAI,WAAU,aACZ,UAAA;AAAA,IAAA,SAAS,oBAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IACvD,oBAAC,SAAI,WAAW,GAAG,SAAS,eAAe,YAAY,GAAI,UAAA,KAAA,CAAK;AAAA,EAAA,GAClE;AAEJ;"}
1
+ {"version":3,"file":"JsonSchemaForm.js","sources":["../../src/components/JsonSchemaForm.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\nimport { renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type { FormLayout, JsonSchemaFormProps } from \"./json-schema-form-types\";\n\nconst DEFAULT_LABEL_MAX_WIDTH = \"40ch\";\nconst DEFAULT_VALUE_MAX_WIDTH = \"400px\";\n\n// resolveFormLayout maps the `layout`/`inline` props to a single resolved\n// FormLayout. An explicit `layout` wins; otherwise `inline` selects the inline\n// preset. Width caps are only filled for inline mode.\nfunction resolveFormLayout(layout: FormLayout | undefined, inline: boolean): FormLayout {\n const base = layout ?? { mode: inline ? \"inline\" : \"stacked\" };\n if (base.mode !== \"inline\") return { mode: \"stacked\" };\n return {\n mode: \"inline\",\n labelMaxWidth: base.labelMaxWidth ?? DEFAULT_LABEL_MAX_WIDTH,\n valueMaxWidth: base.valueMaxWidth ?? DEFAULT_VALUE_MAX_WIDTH,\n };\n}\n\n// JsonSchemaForm renders an object subschema as a form: one control per\n// (effective) property. It resolves if/then conditionals internally and recurses\n// through array items and object/map values; every other behaviour is layered on\n// by the pre/post extension functions the consumer supplies. The component holds\n// no domain knowledge.\nexport function JsonSchemaForm({\n schema,\n value,\n onChange,\n readOnly = false,\n inline = false,\n layout,\n hideReadOnlyFields = false,\n hiddenKeys,\n requiredFirst = false,\n title,\n pre,\n post,\n}: JsonSchemaFormProps) {\n const resolvedLayout = resolveFormLayout(layout, inline);\n const ctx: RenderContext = {\n readOnly,\n hideReadOnlyFields,\n layout: resolvedLayout,\n requiredFirst,\n pre: pre ?? [],\n post: post ?? [],\n depth: 0,\n };\n const rows = renderObjectFields(schema, value, onChange, ctx, hiddenKeys ? { hiddenKeys } : undefined);\n\n return (\n <div className=\"space-y-3\">\n {title && <h3 className=\"text-sm font-semibold\">{title}</h3>}\n <div className={cn(resolvedLayout.mode === \"inline\" ? \"grid gap-2\" : \"grid gap-4\")}>{rows}</div>\n </div>\n );\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,0BAA0B;AAChC,MAAM,0BAA0B;AAKhC,SAAS,kBAAkB,QAAgC,QAA6B;AACtF,QAAM,OAAO,UAAU,EAAE,MAAM,SAAS,WAAW,UAAA;AACnD,MAAI,KAAK,SAAS,SAAU,QAAO,EAAE,MAAM,UAAA;AAC3C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,KAAK,iBAAiB;AAAA,IACrC,eAAe,KAAK,iBAAiB;AAAA,EAAA;AAEzC;AAOO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,SAAS;AAAA,EACT;AAAA,EACA,qBAAqB;AAAA,EACrB;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,iBAAiB,kBAAkB,QAAQ,MAAM;AACvD,QAAM,MAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA,KAAK,OAAO,CAAA;AAAA,IACZ,MAAM,QAAQ,CAAA;AAAA,IACd,OAAO;AAAA,EAAA;AAET,QAAM,OAAO,mBAAmB,QAAQ,OAAO,UAAU,KAAK,aAAa,EAAE,WAAA,IAAe,MAAS;AAErG,SACE,qBAAC,OAAA,EAAI,WAAU,aACZ,UAAA;AAAA,IAAA,SAAS,oBAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IACvD,oBAAC,OAAA,EAAI,WAAW,GAAG,eAAe,SAAS,WAAW,eAAe,YAAY,GAAI,UAAA,KAAA,CAAK;AAAA,EAAA,GAC5F;AAEJ;"}
@@ -18,15 +18,24 @@ function FieldWrapper({
18
18
  value,
19
19
  helper,
20
20
  error,
21
- inline
21
+ layout
22
22
  }) {
23
- if (inline) {
24
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5", children: [
25
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-9 items-center", children: label }),
26
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children: value }),
27
- helper && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "col-start-2 text-xs text-muted-foreground", children: helper }),
28
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "col-start-2 text-xs text-destructive", children: error })
29
- ] });
23
+ if (layout.mode === "inline") {
24
+ const labelMaxWidth = layout.labelMaxWidth ?? "40ch";
25
+ const valueMaxWidth = layout.valueMaxWidth ?? "400px";
26
+ return /* @__PURE__ */ jsxRuntime.jsxs(
27
+ "div",
28
+ {
29
+ className: "grid items-start gap-x-3 gap-y-0.5",
30
+ style: { gridTemplateColumns: `minmax(0, ${labelMaxWidth}) minmax(0, ${valueMaxWidth})` },
31
+ children: [
32
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-9 min-w-0 items-center", children: label }),
33
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children: value }),
34
+ helper && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "col-start-2 text-xs text-muted-foreground", children: helper }),
35
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "col-start-2 text-xs text-destructive", children: error })
36
+ ]
37
+ }
38
+ );
30
39
  }
31
40
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
32
41
  label,
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema-form-fields.cjs","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, LabelIcon } from \"../data/Icon\";\nimport { formatDateTimeRelative } from \"../data/cells/Timestamp\";\nimport { UiAdd, UiTrash } from \"../icons\";\nimport { Button } from \"./button\";\nimport { Combobox } from \"./Combobox\";\nimport { DateTimePicker } from \"./DateTimePicker\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { renderFieldNodes, renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type {\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\nexport const inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n\n// FieldWrapper lays out a label + value (+ helper/error) either inline (2-col)\n// or stacked, mirroring the convention used elsewhere in the library.\nexport function FieldWrapper({\n label,\n value,\n helper,\n error,\n inline,\n}: {\n label: ReactNode;\n value: ReactNode;\n helper?: ReactNode;\n error?: ReactNode;\n inline?: boolean;\n}) {\n if (inline) {\n return (\n <div className=\"grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5\">\n <div className=\"flex min-h-9 items-center\">{label}</div>\n <div className=\"min-w-0\">{value}</div>\n {helper && <p className=\"col-start-2 text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"col-start-2 text-xs text-destructive\">{error}</p>}\n </div>\n );\n }\n return (\n <div className=\"space-y-1.5\">\n {label}\n {value}\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\nexport function FieldLabel({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n return (\n <label htmlFor={fieldId} className=\"flex items-center gap-2 text-sm font-medium\">\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span title={field.label !== field.key ? field.key : undefined}>{field.label}</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 </label>\n );\n}\n\nexport function fieldInputId(key: string): string {\n return `jsf-${key.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} />;\n }\n const readOnly = ctx.readOnly;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n }\n}\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nfunction ReadOnlyValue({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n const text = toText(field.value);\n const display = field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\nfunction StringControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n return (\n <input\n id={fieldId}\n type=\"text\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n}\n\nfunction NumberControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // type=\"text\" (not number) so non-numeric values a consumer permits — e.g.\n // template tokens — are not silently dropped by the browser.\n return (\n <input\n id={fieldId}\n type=\"text\"\n inputMode=\"decimal\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n const coerce = field.coerceNumber !== false;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n />\n );\n}\n\n// DateControl edits a `format: date`/`date-time` string. Read-only, it shows the\n// human-readable absolute + relative form (e.g. \"Apr 15, 2026, 12:00 PM (2h\n// ago)\"); editable, a DateTimePicker. The raw string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nfunction DateControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateTimePicker\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n inputClassName={cn(inputClassName, \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n />\n );\n}\n\nfunction BooleanControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className=\"flex h-9 items-center\">\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n}\n\nfunction EnumControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"radio\") {\n return <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} />;\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className=\"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\"\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1 text-sm\",\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// ObjectControl renders a nested structured object as a sub-form: its own\n// properties, required markers, if/then, soft errors — all via the shared\n// recursive renderer, so pre/post extensions apply at this depth too.\nfunction ObjectControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n const obj = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const subSchema: JsonSchemaObject = {\n type: \"object\",\n properties: field.objectProperties ?? {},\n ...(field.objectRequired ? { required: field.objectRequired } : {}),\n ...(Array.isArray(field.schema.allOf) ? { allOf: field.schema.allOf } : {}),\n };\n // No border/box: nested objects render as flat headed sections (see\n // ObjectSection in renderFieldRow) rather than progressively indented\n // sub-forms, so deep schemas stay readable as a single column.\n // A read-only object marks its whole subtree non-editable: recurse with\n // form-level readOnly on so child inputs are disabled (and any child the\n // schema marks readOnly still renders as a value span).\n return (\n <div className=\"space-y-2\">\n {renderObjectFields(subSchema, obj, (next) => field.onChange(next), {\n ...ctx,\n readOnly: ctx.readOnly || field.readOnly === true,\n depth: ctx.depth + 1,\n })}\n </div>\n );\n}\n\n// StringMapControl edits an object as key/value rows. Known properties (from the\n// schema) render first with derived value controls; unknown keys render as\n// editable key/value pairs. \"Add field\" appears when extra keys are allowed.\n// Values recurse through the shared pipeline, so a value that is itself an object\n// or array renders structurally and pre/post extensions apply to it.\nfunction StringMapControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n // A read-only map marks its whole subtree non-editable: no rename/remove/add\n // and value inputs disabled.\n const readOnly = ctx.readOnly || field.readOnly === true;\n const map = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const known = field.knownProperties ?? {};\n const knownKeys = Object.keys(known);\n const extraKeys = Object.keys(map).filter((k) => !(k in known));\n const childCtx: RenderContext = { ...ctx, readOnly, depth: ctx.depth + 1 };\n\n function setEntry(key: string, next: unknown) {\n field.onChange({ ...map, [key]: next });\n }\n function renameEntry(oldKey: string, newKey: string) {\n if (newKey === oldKey) return;\n const next: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(map)) next[k === oldKey ? newKey : k] = v;\n field.onChange(next);\n }\n function removeEntry(key: string) {\n const next = { ...map };\n delete next[key];\n field.onChange(next);\n }\n function addEntry() {\n if (\"\" in map) return;\n field.onChange({ ...map, \"\": \"\" });\n }\n\n function valueControlFor(key: string, valueSchema: JsonSchemaProperty): ReactNode {\n const nodes = renderFieldNodes(\n {\n key,\n prop: valueSchema,\n required: false,\n value: map[key] ?? \"\",\n onChange: (next) => setEntry(key, next),\n },\n childCtx,\n );\n return nodes?.value ?? null;\n }\n\n return (\n <div className=\"space-y-2 rounded-md border border-input p-2\">\n {knownKeys.map((key) => (\n <div key={`known-${key}`} className=\"grid grid-cols-[10rem_1fr] items-center gap-2\">\n <label htmlFor={fieldInputId(key)} className=\"truncate text-xs text-muted-foreground\" title={key}>\n {key}\n </label>\n <div className=\"min-w-0\">{valueControlFor(key, known[key] ?? { type: \"string\" })}</div>\n </div>\n ))}\n {extraKeys.map((key) => (\n <div key={`extra-${key}`} className=\"grid grid-cols-[10rem_1fr_auto] items-center gap-2\">\n <input\n type=\"text\"\n aria-label=\"Field name\"\n className={cn(inputClassName, \"h-8 font-mono text-xs\")}\n value={key}\n disabled={readOnly}\n onChange={(e) => renameEntry(key, e.target.value)}\n />\n <div className=\"min-w-0\">\n {valueControlFor(key, field.valueSchema ?? { type: \"string\" })}\n </div>\n {!readOnly && (\n <button\n type=\"button\"\n aria-label={`Remove ${key}`}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={() => removeEntry(key)}\n >\n <Icon icon={UiTrash} className=\"text-sm\" />\n </button>\n )}\n </div>\n ))}\n {!readOnly && field.allowExtraKeys !== false && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addEntry} className=\"gap-1.5\">\n <Icon icon={UiAdd} className=\"text-sm\" />\n Add field\n </Button>\n )}\n </div>\n );\n}\n\nfunction withSyntheticValue(\n options: { value: string; label: string }[],\n value: string,\n): { value: string; label: string }[] {\n if (!value || options.some((o) => o.value === value)) return options;\n return [{ value, label: value }, ...options];\n}\n\nfunction toText(value: unknown): string {\n if (value === undefined || value === null) return \"\";\n if (typeof value === \"object\") return \"\";\n return String(value);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function defaultPlaceholder(schema: JsonSchemaProperty): string {\n if (schema.default != null && typeof schema.default !== \"object\") return String(schema.default);\n return \"\";\n}\n"],"names":["jsxs","jsx","LabelIcon","ArrayControl","formatDateTimeRelative","DateTimePicker","cn","Combobox","renderObjectFields","renderFieldNodes","Icon","UiTrash","Button","UiAdd"],"mappings":"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"}
1
+ {"version":3,"file":"json-schema-form-fields.cjs","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, LabelIcon } from \"../data/Icon\";\nimport { formatDateTimeRelative } from \"../data/cells/Timestamp\";\nimport { UiAdd, UiTrash } from \"../icons\";\nimport { Button } from \"./button\";\nimport { Combobox } from \"./Combobox\";\nimport { DateTimePicker } from \"./DateTimePicker\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { renderFieldNodes, renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type {\n FieldControl,\n FieldOption,\n FormLayout,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\nexport const inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n\n// FieldWrapper lays out a label + value (+ helper/error) either inline (2-col)\n// or stacked, mirroring the convention used elsewhere in the library. In inline\n// mode the label and value columns are capped (see FormLayout); the grid\n// template is set inline because Tailwind can't interpolate runtime widths.\nexport function FieldWrapper({\n label,\n value,\n helper,\n error,\n layout,\n}: {\n label: ReactNode;\n value: ReactNode;\n helper?: ReactNode;\n error?: ReactNode;\n layout: FormLayout;\n}) {\n if (layout.mode === \"inline\") {\n const labelMaxWidth = layout.labelMaxWidth ?? \"40ch\";\n const valueMaxWidth = layout.valueMaxWidth ?? \"400px\";\n return (\n <div\n className=\"grid items-start gap-x-3 gap-y-0.5\"\n style={{ gridTemplateColumns: `minmax(0, ${labelMaxWidth}) minmax(0, ${valueMaxWidth})` }}\n >\n <div className=\"flex min-h-9 min-w-0 items-center\">{label}</div>\n <div className=\"min-w-0\">{value}</div>\n {helper && <p className=\"col-start-2 text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"col-start-2 text-xs text-destructive\">{error}</p>}\n </div>\n );\n }\n return (\n <div className=\"space-y-1.5\">\n {label}\n {value}\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\nexport function FieldLabel({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n return (\n <label htmlFor={fieldId} className=\"flex items-center gap-2 text-sm font-medium\">\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span title={field.label !== field.key ? field.key : undefined}>{field.label}</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 </label>\n );\n}\n\nexport function fieldInputId(key: string): string {\n return `jsf-${key.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} />;\n }\n const readOnly = ctx.readOnly;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n }\n}\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nfunction ReadOnlyValue({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n const text = toText(field.value);\n const display = field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\nfunction StringControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n return (\n <input\n id={fieldId}\n type=\"text\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n}\n\nfunction NumberControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // type=\"text\" (not number) so non-numeric values a consumer permits — e.g.\n // template tokens — are not silently dropped by the browser.\n return (\n <input\n id={fieldId}\n type=\"text\"\n inputMode=\"decimal\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n const coerce = field.coerceNumber !== false;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n />\n );\n}\n\n// DateControl edits a `format: date`/`date-time` string. Read-only, it shows the\n// human-readable absolute + relative form (e.g. \"Apr 15, 2026, 12:00 PM (2h\n// ago)\"); editable, a DateTimePicker. The raw string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nfunction DateControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateTimePicker\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n inputClassName={cn(inputClassName, \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n />\n );\n}\n\nfunction BooleanControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className=\"flex h-9 items-center\">\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n}\n\nfunction EnumControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"radio\") {\n return <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} />;\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className=\"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\"\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1 text-sm\",\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// ObjectControl renders a nested structured object as a sub-form: its own\n// properties, required markers, if/then, soft errors — all via the shared\n// recursive renderer, so pre/post extensions apply at this depth too.\nfunction ObjectControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n const obj = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const subSchema: JsonSchemaObject = {\n type: \"object\",\n properties: field.objectProperties ?? {},\n ...(field.objectRequired ? { required: field.objectRequired } : {}),\n ...(Array.isArray(field.schema.allOf) ? { allOf: field.schema.allOf } : {}),\n };\n // No border/box: nested objects render as flat headed sections (see\n // ObjectSection in renderFieldRow) rather than progressively indented\n // sub-forms, so deep schemas stay readable as a single column.\n // A read-only object marks its whole subtree non-editable: recurse with\n // form-level readOnly on so child inputs are disabled (and any child the\n // schema marks readOnly still renders as a value span).\n return (\n <div className=\"space-y-2\">\n {renderObjectFields(subSchema, obj, (next) => field.onChange(next), {\n ...ctx,\n readOnly: ctx.readOnly || field.readOnly === true,\n depth: ctx.depth + 1,\n })}\n </div>\n );\n}\n\n// StringMapControl edits an object as key/value rows. Known properties (from the\n// schema) render first with derived value controls; unknown keys render as\n// editable key/value pairs. \"Add field\" appears when extra keys are allowed.\n// Values recurse through the shared pipeline, so a value that is itself an object\n// or array renders structurally and pre/post extensions apply to it.\nfunction StringMapControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n // A read-only map marks its whole subtree non-editable: no rename/remove/add\n // and value inputs disabled.\n const readOnly = ctx.readOnly || field.readOnly === true;\n const map = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const known = field.knownProperties ?? {};\n const knownKeys = Object.keys(known);\n const extraKeys = Object.keys(map).filter((k) => !(k in known));\n const childCtx: RenderContext = { ...ctx, readOnly, depth: ctx.depth + 1 };\n\n function setEntry(key: string, next: unknown) {\n field.onChange({ ...map, [key]: next });\n }\n function renameEntry(oldKey: string, newKey: string) {\n if (newKey === oldKey) return;\n const next: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(map)) next[k === oldKey ? newKey : k] = v;\n field.onChange(next);\n }\n function removeEntry(key: string) {\n const next = { ...map };\n delete next[key];\n field.onChange(next);\n }\n function addEntry() {\n if (\"\" in map) return;\n field.onChange({ ...map, \"\": \"\" });\n }\n\n function valueControlFor(key: string, valueSchema: JsonSchemaProperty): ReactNode {\n const nodes = renderFieldNodes(\n {\n key,\n prop: valueSchema,\n required: false,\n value: map[key] ?? \"\",\n onChange: (next) => setEntry(key, next),\n },\n childCtx,\n );\n return nodes?.value ?? null;\n }\n\n return (\n <div className=\"space-y-2 rounded-md border border-input p-2\">\n {knownKeys.map((key) => (\n <div key={`known-${key}`} className=\"grid grid-cols-[10rem_1fr] items-center gap-2\">\n <label htmlFor={fieldInputId(key)} className=\"truncate text-xs text-muted-foreground\" title={key}>\n {key}\n </label>\n <div className=\"min-w-0\">{valueControlFor(key, known[key] ?? { type: \"string\" })}</div>\n </div>\n ))}\n {extraKeys.map((key) => (\n <div key={`extra-${key}`} className=\"grid grid-cols-[10rem_1fr_auto] items-center gap-2\">\n <input\n type=\"text\"\n aria-label=\"Field name\"\n className={cn(inputClassName, \"h-8 font-mono text-xs\")}\n value={key}\n disabled={readOnly}\n onChange={(e) => renameEntry(key, e.target.value)}\n />\n <div className=\"min-w-0\">\n {valueControlFor(key, field.valueSchema ?? { type: \"string\" })}\n </div>\n {!readOnly && (\n <button\n type=\"button\"\n aria-label={`Remove ${key}`}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={() => removeEntry(key)}\n >\n <Icon icon={UiTrash} className=\"text-sm\" />\n </button>\n )}\n </div>\n ))}\n {!readOnly && field.allowExtraKeys !== false && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addEntry} className=\"gap-1.5\">\n <Icon icon={UiAdd} className=\"text-sm\" />\n Add field\n </Button>\n )}\n </div>\n );\n}\n\nfunction withSyntheticValue(\n options: { value: string; label: string }[],\n value: string,\n): { value: string; label: string }[] {\n if (!value || options.some((o) => o.value === value)) return options;\n return [{ value, label: value }, ...options];\n}\n\nfunction toText(value: unknown): string {\n if (value === undefined || value === null) return \"\";\n if (typeof value === \"object\") return \"\";\n return String(value);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function defaultPlaceholder(schema: JsonSchemaProperty): string {\n if (schema.default != null && typeof schema.default !== \"object\") return String(schema.default);\n return \"\";\n}\n"],"names":["jsxs","jsx","LabelIcon","ArrayControl","formatDateTimeRelative","DateTimePicker","cn","Combobox","renderObjectFields","renderFieldNodes","Icon","UiTrash","Button","UiAdd"],"mappings":"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"}
@@ -1,13 +1,13 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { RenderContext } from './json-schema-form-render';
3
- import { FieldControl, JsonSchemaProperty } from './json-schema-form-types';
3
+ import { FieldControl, FormLayout, JsonSchemaProperty } from './json-schema-form-types';
4
4
  export declare const inputClassName = "h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring";
5
- export declare function FieldWrapper({ label, value, helper, error, inline, }: {
5
+ export declare function FieldWrapper({ label, value, helper, error, layout, }: {
6
6
  label: ReactNode;
7
7
  value: ReactNode;
8
8
  helper?: ReactNode;
9
9
  error?: ReactNode;
10
- inline?: boolean;
10
+ layout: FormLayout;
11
11
  }): import("react/jsx-runtime").JSX.Element;
12
12
  export declare function FieldLabel({ field, fieldId }: {
13
13
  field: FieldControl;
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema-form-fields.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACrG,OAAO,KAAK,EACV,YAAY,EAGZ,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,cAAc,8OACkN,CAAC;AAI9O,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAM,EACN,KAAK,EACL,MAAM,GACP,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,2CAmBA;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,2CAatF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAKD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,SAAS,CA6BrF;AAgXD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAGrE"}
1
+ {"version":3,"file":"json-schema-form-fields.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-fields.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACrG,OAAO,KAAK,EACV,YAAY,EAEZ,UAAU,EAEV,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,cAAc,8OACkN,CAAC;AAM9O,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAM,EACN,KAAK,EACL,MAAM,GACP,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;CACpB,2CAwBA;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,2CAatF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAKD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,GAAG,SAAS,CA6BrF;AAgXD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAGrE"}
@@ -16,15 +16,24 @@ function FieldWrapper({
16
16
  value,
17
17
  helper,
18
18
  error,
19
- inline
19
+ layout
20
20
  }) {
21
- if (inline) {
22
- return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5", children: [
23
- /* @__PURE__ */ jsx("div", { className: "flex min-h-9 items-center", children: label }),
24
- /* @__PURE__ */ jsx("div", { className: "min-w-0", children: value }),
25
- helper && /* @__PURE__ */ jsx("p", { className: "col-start-2 text-xs text-muted-foreground", children: helper }),
26
- error && /* @__PURE__ */ jsx("p", { className: "col-start-2 text-xs text-destructive", children: error })
27
- ] });
21
+ if (layout.mode === "inline") {
22
+ const labelMaxWidth = layout.labelMaxWidth ?? "40ch";
23
+ const valueMaxWidth = layout.valueMaxWidth ?? "400px";
24
+ return /* @__PURE__ */ jsxs(
25
+ "div",
26
+ {
27
+ className: "grid items-start gap-x-3 gap-y-0.5",
28
+ style: { gridTemplateColumns: `minmax(0, ${labelMaxWidth}) minmax(0, ${valueMaxWidth})` },
29
+ children: [
30
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-9 min-w-0 items-center", children: label }),
31
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: value }),
32
+ helper && /* @__PURE__ */ jsx("p", { className: "col-start-2 text-xs text-muted-foreground", children: helper }),
33
+ error && /* @__PURE__ */ jsx("p", { className: "col-start-2 text-xs text-destructive", children: error })
34
+ ]
35
+ }
36
+ );
28
37
  }
29
38
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
30
39
  label,
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema-form-fields.js","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, LabelIcon } from \"../data/Icon\";\nimport { formatDateTimeRelative } from \"../data/cells/Timestamp\";\nimport { UiAdd, UiTrash } from \"../icons\";\nimport { Button } from \"./button\";\nimport { Combobox } from \"./Combobox\";\nimport { DateTimePicker } from \"./DateTimePicker\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { renderFieldNodes, renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type {\n FieldControl,\n FieldOption,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\nexport const inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n\n// FieldWrapper lays out a label + value (+ helper/error) either inline (2-col)\n// or stacked, mirroring the convention used elsewhere in the library.\nexport function FieldWrapper({\n label,\n value,\n helper,\n error,\n inline,\n}: {\n label: ReactNode;\n value: ReactNode;\n helper?: ReactNode;\n error?: ReactNode;\n inline?: boolean;\n}) {\n if (inline) {\n return (\n <div className=\"grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5\">\n <div className=\"flex min-h-9 items-center\">{label}</div>\n <div className=\"min-w-0\">{value}</div>\n {helper && <p className=\"col-start-2 text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"col-start-2 text-xs text-destructive\">{error}</p>}\n </div>\n );\n }\n return (\n <div className=\"space-y-1.5\">\n {label}\n {value}\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\nexport function FieldLabel({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n return (\n <label htmlFor={fieldId} className=\"flex items-center gap-2 text-sm font-medium\">\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span title={field.label !== field.key ? field.key : undefined}>{field.label}</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 </label>\n );\n}\n\nexport function fieldInputId(key: string): string {\n return `jsf-${key.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} />;\n }\n const readOnly = ctx.readOnly;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n }\n}\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nfunction ReadOnlyValue({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n const text = toText(field.value);\n const display = field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\nfunction StringControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n return (\n <input\n id={fieldId}\n type=\"text\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n}\n\nfunction NumberControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // type=\"text\" (not number) so non-numeric values a consumer permits — e.g.\n // template tokens — are not silently dropped by the browser.\n return (\n <input\n id={fieldId}\n type=\"text\"\n inputMode=\"decimal\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n const coerce = field.coerceNumber !== false;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n />\n );\n}\n\n// DateControl edits a `format: date`/`date-time` string. Read-only, it shows the\n// human-readable absolute + relative form (e.g. \"Apr 15, 2026, 12:00 PM (2h\n// ago)\"); editable, a DateTimePicker. The raw string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nfunction DateControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateTimePicker\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n inputClassName={cn(inputClassName, \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n />\n );\n}\n\nfunction BooleanControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className=\"flex h-9 items-center\">\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n}\n\nfunction EnumControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"radio\") {\n return <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} />;\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className=\"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\"\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1 text-sm\",\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// ObjectControl renders a nested structured object as a sub-form: its own\n// properties, required markers, if/then, soft errors — all via the shared\n// recursive renderer, so pre/post extensions apply at this depth too.\nfunction ObjectControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n const obj = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const subSchema: JsonSchemaObject = {\n type: \"object\",\n properties: field.objectProperties ?? {},\n ...(field.objectRequired ? { required: field.objectRequired } : {}),\n ...(Array.isArray(field.schema.allOf) ? { allOf: field.schema.allOf } : {}),\n };\n // No border/box: nested objects render as flat headed sections (see\n // ObjectSection in renderFieldRow) rather than progressively indented\n // sub-forms, so deep schemas stay readable as a single column.\n // A read-only object marks its whole subtree non-editable: recurse with\n // form-level readOnly on so child inputs are disabled (and any child the\n // schema marks readOnly still renders as a value span).\n return (\n <div className=\"space-y-2\">\n {renderObjectFields(subSchema, obj, (next) => field.onChange(next), {\n ...ctx,\n readOnly: ctx.readOnly || field.readOnly === true,\n depth: ctx.depth + 1,\n })}\n </div>\n );\n}\n\n// StringMapControl edits an object as key/value rows. Known properties (from the\n// schema) render first with derived value controls; unknown keys render as\n// editable key/value pairs. \"Add field\" appears when extra keys are allowed.\n// Values recurse through the shared pipeline, so a value that is itself an object\n// or array renders structurally and pre/post extensions apply to it.\nfunction StringMapControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n // A read-only map marks its whole subtree non-editable: no rename/remove/add\n // and value inputs disabled.\n const readOnly = ctx.readOnly || field.readOnly === true;\n const map = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const known = field.knownProperties ?? {};\n const knownKeys = Object.keys(known);\n const extraKeys = Object.keys(map).filter((k) => !(k in known));\n const childCtx: RenderContext = { ...ctx, readOnly, depth: ctx.depth + 1 };\n\n function setEntry(key: string, next: unknown) {\n field.onChange({ ...map, [key]: next });\n }\n function renameEntry(oldKey: string, newKey: string) {\n if (newKey === oldKey) return;\n const next: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(map)) next[k === oldKey ? newKey : k] = v;\n field.onChange(next);\n }\n function removeEntry(key: string) {\n const next = { ...map };\n delete next[key];\n field.onChange(next);\n }\n function addEntry() {\n if (\"\" in map) return;\n field.onChange({ ...map, \"\": \"\" });\n }\n\n function valueControlFor(key: string, valueSchema: JsonSchemaProperty): ReactNode {\n const nodes = renderFieldNodes(\n {\n key,\n prop: valueSchema,\n required: false,\n value: map[key] ?? \"\",\n onChange: (next) => setEntry(key, next),\n },\n childCtx,\n );\n return nodes?.value ?? null;\n }\n\n return (\n <div className=\"space-y-2 rounded-md border border-input p-2\">\n {knownKeys.map((key) => (\n <div key={`known-${key}`} className=\"grid grid-cols-[10rem_1fr] items-center gap-2\">\n <label htmlFor={fieldInputId(key)} className=\"truncate text-xs text-muted-foreground\" title={key}>\n {key}\n </label>\n <div className=\"min-w-0\">{valueControlFor(key, known[key] ?? { type: \"string\" })}</div>\n </div>\n ))}\n {extraKeys.map((key) => (\n <div key={`extra-${key}`} className=\"grid grid-cols-[10rem_1fr_auto] items-center gap-2\">\n <input\n type=\"text\"\n aria-label=\"Field name\"\n className={cn(inputClassName, \"h-8 font-mono text-xs\")}\n value={key}\n disabled={readOnly}\n onChange={(e) => renameEntry(key, e.target.value)}\n />\n <div className=\"min-w-0\">\n {valueControlFor(key, field.valueSchema ?? { type: \"string\" })}\n </div>\n {!readOnly && (\n <button\n type=\"button\"\n aria-label={`Remove ${key}`}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={() => removeEntry(key)}\n >\n <Icon icon={UiTrash} className=\"text-sm\" />\n </button>\n )}\n </div>\n ))}\n {!readOnly && field.allowExtraKeys !== false && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addEntry} className=\"gap-1.5\">\n <Icon icon={UiAdd} className=\"text-sm\" />\n Add field\n </Button>\n )}\n </div>\n );\n}\n\nfunction withSyntheticValue(\n options: { value: string; label: string }[],\n value: string,\n): { value: string; label: string }[] {\n if (!value || options.some((o) => o.value === value)) return options;\n return [{ value, label: value }, ...options];\n}\n\nfunction toText(value: unknown): string {\n if (value === undefined || value === null) return \"\";\n if (typeof value === \"object\") return \"\";\n return String(value);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function defaultPlaceholder(schema: JsonSchemaProperty): string {\n if (schema.default != null && typeof schema.default !== \"object\") return String(schema.default);\n return \"\";\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"json-schema-form-fields.js","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, LabelIcon } from \"../data/Icon\";\nimport { formatDateTimeRelative } from \"../data/cells/Timestamp\";\nimport { UiAdd, UiTrash } from \"../icons\";\nimport { Button } from \"./button\";\nimport { Combobox } from \"./Combobox\";\nimport { DateTimePicker } from \"./DateTimePicker\";\nimport { ArrayControl } from \"./json-schema-form-array\";\nimport { renderFieldNodes, renderObjectFields, type RenderContext } from \"./json-schema-form-render\";\nimport type {\n FieldControl,\n FieldOption,\n FormLayout,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\nexport const inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n\n// FieldWrapper lays out a label + value (+ helper/error) either inline (2-col)\n// or stacked, mirroring the convention used elsewhere in the library. In inline\n// mode the label and value columns are capped (see FormLayout); the grid\n// template is set inline because Tailwind can't interpolate runtime widths.\nexport function FieldWrapper({\n label,\n value,\n helper,\n error,\n layout,\n}: {\n label: ReactNode;\n value: ReactNode;\n helper?: ReactNode;\n error?: ReactNode;\n layout: FormLayout;\n}) {\n if (layout.mode === \"inline\") {\n const labelMaxWidth = layout.labelMaxWidth ?? \"40ch\";\n const valueMaxWidth = layout.valueMaxWidth ?? \"400px\";\n return (\n <div\n className=\"grid items-start gap-x-3 gap-y-0.5\"\n style={{ gridTemplateColumns: `minmax(0, ${labelMaxWidth}) minmax(0, ${valueMaxWidth})` }}\n >\n <div className=\"flex min-h-9 min-w-0 items-center\">{label}</div>\n <div className=\"min-w-0\">{value}</div>\n {helper && <p className=\"col-start-2 text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"col-start-2 text-xs text-destructive\">{error}</p>}\n </div>\n );\n }\n return (\n <div className=\"space-y-1.5\">\n {label}\n {value}\n {helper && <p className=\"text-xs text-muted-foreground\">{helper}</p>}\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n );\n}\n\nexport function FieldLabel({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n return (\n <label htmlFor={fieldId} className=\"flex items-center gap-2 text-sm font-medium\">\n <LabelIcon icon={field.labelIcon} className=\"text-[15px] text-muted-foreground\" />\n <span title={field.label !== field.key ? field.key : undefined}>{field.label}</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 </label>\n );\n}\n\nexport function fieldInputId(key: string): string {\n return `jsf-${key.replace(/[^a-zA-Z0-9_-]/g, \"_\")}`;\n}\n\n// renderValueControl produces just the value node for a field, dispatching on\n// its resolved kind. The RenderContext carries readOnly + the pre/post stacks so\n// container controls (array/object/map) can recurse with full context.\nexport function renderValueControl(field: FieldControl, ctx: RenderContext): ReactNode {\n const fieldId = fieldInputId(field.key);\n // A field the schema marks `readOnly` is never editable: it shows its current\n // value as plain text, not a disabled input. (The form-level ctx.readOnly,\n // below, instead disables the real controls so the structure stays visible.)\n // Containers (array/object/map) still render structurally so nested read-only\n // values surface; their own children resolve their own readOnly.\n if (field.readOnly && field.kind !== \"array\" && field.kind !== \"object\" && field.kind !== \"string-map\") {\n return <ReadOnlyValue field={field} fieldId={fieldId} />;\n }\n const readOnly = ctx.readOnly;\n switch (field.kind) {\n case \"enum\":\n return <EnumControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"boolean\":\n return <BooleanControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"number\":\n return <NumberControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"date\":\n return <DateControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n case \"array\":\n return <ArrayControl field={field} fieldId={fieldId} ctx={ctx} />;\n case \"object\":\n return <ObjectControl field={field} ctx={ctx} />;\n case \"string-map\":\n return <StringMapControl field={field} ctx={ctx} />;\n default:\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n }\n}\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nfunction ReadOnlyValue({ field, fieldId }: { field: FieldControl; fieldId: string }) {\n const text = toText(field.value);\n const display = field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\nfunction StringControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n return (\n <input\n id={fieldId}\n type=\"text\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n}\n\nfunction NumberControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // type=\"text\" (not number) so non-numeric values a consumer permits — e.g.\n // template tokens — are not silently dropped by the browser.\n return (\n <input\n id={fieldId}\n type=\"text\"\n inputMode=\"decimal\"\n data-jsf-input\n className={inputClassName}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n const coerce = field.coerceNumber !== false;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n />\n );\n}\n\n// DateControl edits a `format: date`/`date-time` string. Read-only, it shows the\n// human-readable absolute + relative form (e.g. \"Apr 15, 2026, 12:00 PM (2h\n// ago)\"); editable, a DateTimePicker. The raw string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nfunction DateControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className=\"flex h-9 items-center text-sm text-foreground\"\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateTimePicker\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n inputClassName={cn(inputClassName, \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n />\n );\n}\n\nfunction BooleanControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className=\"flex h-9 items-center\">\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} />;\n}\n\nfunction EnumControl({\n field,\n fieldId,\n readOnly,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"radio\") {\n return <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} />;\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className=\"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\"\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1 text-sm\",\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// ObjectControl renders a nested structured object as a sub-form: its own\n// properties, required markers, if/then, soft errors — all via the shared\n// recursive renderer, so pre/post extensions apply at this depth too.\nfunction ObjectControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n const obj = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const subSchema: JsonSchemaObject = {\n type: \"object\",\n properties: field.objectProperties ?? {},\n ...(field.objectRequired ? { required: field.objectRequired } : {}),\n ...(Array.isArray(field.schema.allOf) ? { allOf: field.schema.allOf } : {}),\n };\n // No border/box: nested objects render as flat headed sections (see\n // ObjectSection in renderFieldRow) rather than progressively indented\n // sub-forms, so deep schemas stay readable as a single column.\n // A read-only object marks its whole subtree non-editable: recurse with\n // form-level readOnly on so child inputs are disabled (and any child the\n // schema marks readOnly still renders as a value span).\n return (\n <div className=\"space-y-2\">\n {renderObjectFields(subSchema, obj, (next) => field.onChange(next), {\n ...ctx,\n readOnly: ctx.readOnly || field.readOnly === true,\n depth: ctx.depth + 1,\n })}\n </div>\n );\n}\n\n// StringMapControl edits an object as key/value rows. Known properties (from the\n// schema) render first with derived value controls; unknown keys render as\n// editable key/value pairs. \"Add field\" appears when extra keys are allowed.\n// Values recurse through the shared pipeline, so a value that is itself an object\n// or array renders structurally and pre/post extensions apply to it.\nfunction StringMapControl({ field, ctx }: { field: FieldControl; ctx: RenderContext }) {\n // A read-only map marks its whole subtree non-editable: no rename/remove/add\n // and value inputs disabled.\n const readOnly = ctx.readOnly || field.readOnly === true;\n const map = isPlainObject(field.value) ? (field.value as Record<string, unknown>) : {};\n const known = field.knownProperties ?? {};\n const knownKeys = Object.keys(known);\n const extraKeys = Object.keys(map).filter((k) => !(k in known));\n const childCtx: RenderContext = { ...ctx, readOnly, depth: ctx.depth + 1 };\n\n function setEntry(key: string, next: unknown) {\n field.onChange({ ...map, [key]: next });\n }\n function renameEntry(oldKey: string, newKey: string) {\n if (newKey === oldKey) return;\n const next: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(map)) next[k === oldKey ? newKey : k] = v;\n field.onChange(next);\n }\n function removeEntry(key: string) {\n const next = { ...map };\n delete next[key];\n field.onChange(next);\n }\n function addEntry() {\n if (\"\" in map) return;\n field.onChange({ ...map, \"\": \"\" });\n }\n\n function valueControlFor(key: string, valueSchema: JsonSchemaProperty): ReactNode {\n const nodes = renderFieldNodes(\n {\n key,\n prop: valueSchema,\n required: false,\n value: map[key] ?? \"\",\n onChange: (next) => setEntry(key, next),\n },\n childCtx,\n );\n return nodes?.value ?? null;\n }\n\n return (\n <div className=\"space-y-2 rounded-md border border-input p-2\">\n {knownKeys.map((key) => (\n <div key={`known-${key}`} className=\"grid grid-cols-[10rem_1fr] items-center gap-2\">\n <label htmlFor={fieldInputId(key)} className=\"truncate text-xs text-muted-foreground\" title={key}>\n {key}\n </label>\n <div className=\"min-w-0\">{valueControlFor(key, known[key] ?? { type: \"string\" })}</div>\n </div>\n ))}\n {extraKeys.map((key) => (\n <div key={`extra-${key}`} className=\"grid grid-cols-[10rem_1fr_auto] items-center gap-2\">\n <input\n type=\"text\"\n aria-label=\"Field name\"\n className={cn(inputClassName, \"h-8 font-mono text-xs\")}\n value={key}\n disabled={readOnly}\n onChange={(e) => renameEntry(key, e.target.value)}\n />\n <div className=\"min-w-0\">\n {valueControlFor(key, field.valueSchema ?? { type: \"string\" })}\n </div>\n {!readOnly && (\n <button\n type=\"button\"\n aria-label={`Remove ${key}`}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\"\n onClick={() => removeEntry(key)}\n >\n <Icon icon={UiTrash} className=\"text-sm\" />\n </button>\n )}\n </div>\n ))}\n {!readOnly && field.allowExtraKeys !== false && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addEntry} className=\"gap-1.5\">\n <Icon icon={UiAdd} className=\"text-sm\" />\n Add field\n </Button>\n )}\n </div>\n );\n}\n\nfunction withSyntheticValue(\n options: { value: string; label: string }[],\n value: string,\n): { value: string; label: string }[] {\n if (!value || options.some((o) => o.value === value)) return options;\n return [{ value, label: value }, ...options];\n}\n\nfunction toText(value: unknown): string {\n if (value === undefined || value === null) return \"\";\n if (typeof value === \"object\") return \"\";\n return String(value);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function defaultPlaceholder(schema: JsonSchemaProperty): string {\n if (schema.default != null && typeof schema.default !== \"object\") return String(schema.default);\n return \"\";\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAkBO,MAAM,iBACX;AAMK,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,gBAAgB,OAAO,iBAAiB;AAC9C,UAAM,gBAAgB,OAAO,iBAAiB;AAC9C,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,EAAE,qBAAqB,aAAa,aAAa,eAAe,aAAa,IAAA;AAAA,QAEpF,UAAA;AAAA,UAAA,oBAAC,OAAA,EAAI,WAAU,qCAAqC,UAAA,OAAM;AAAA,UAC1D,oBAAC,OAAA,EAAI,WAAU,WAAW,UAAA,OAAM;AAAA,UAC/B,UAAU,oBAAC,KAAA,EAAE,WAAU,6CAA6C,UAAA,QAAO;AAAA,UAC3E,SAAS,oBAAC,KAAA,EAAE,WAAU,wCAAwC,UAAA,MAAA,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAG3E;AACA,SACE,qBAAC,OAAA,EAAI,WAAU,eACZ,UAAA;AAAA,IAAA;AAAA,IACA;AAAA,IACA,UAAU,oBAAC,KAAA,EAAE,WAAU,iCAAiC,UAAA,QAAO;AAAA,IAC/D,SAAS,oBAAC,KAAA,EAAE,WAAU,4BAA4B,UAAA,MAAA,CAAM;AAAA,EAAA,GAC3D;AAEJ;AAEO,SAAS,WAAW,EAAE,OAAO,WAAqD;AACvF,SACE,qBAAC,SAAA,EAAM,SAAS,SAAS,WAAU,+CACjC,UAAA;AAAA,IAAA,oBAAC,WAAA,EAAU,MAAM,MAAM,WAAW,WAAU,qCAAoC;AAAA,IAChF,oBAAC,QAAA,EAAK,OAAO,MAAM,UAAU,MAAM,MAAM,MAAM,MAAM,QAAY,UAAA,MAAM,MAAA,CAAM;AAAA,IAC5E,MAAM,YAAY,oBAAC,QAAA,EAAK,WAAU,oBAAmB,UAAA,KAAC;AAAA,IACtD,MAAM,SACL,oBAAC,UAAK,WAAU,wGACb,gBAAM,MAAA,CACT;AAAA,EAAA,GAEJ;AAEJ;AAEO,SAAS,aAAa,KAAqB;AAChD,SAAO,OAAO,IAAI,QAAQ,mBAAmB,GAAG,CAAC;AACnD;AAKO,SAAS,mBAAmB,OAAqB,KAA+B;AACrF,QAAM,UAAU,aAAa,MAAM,GAAG;AAMtC,MAAI,MAAM,YAAY,MAAM,SAAS,WAAW,MAAM,SAAS,YAAY,MAAM,SAAS,cAAc;AACtG,WAAO,oBAAC,eAAA,EAAc,OAAc,QAAA,CAAkB;AAAA,EACxD;AACA,QAAM,WAAW,IAAI;AACrB,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK;AACH,aAAO,oBAAC,aAAA,EAAY,OAAc,SAAkB,SAAA,CAAoB;AAAA,IAC1E,KAAK;AACH,aAAO,oBAAC,gBAAA,EAAe,OAAc,SAAkB,SAAA,CAAoB;AAAA,IAC7E,KAAK;AACH,aAAO,oBAAC,eAAA,EAAc,OAAc,SAAkB,SAAA,CAAoB;AAAA,IAC5E,KAAK;AACH,aAAO,oBAAC,aAAA,EAAY,OAAc,SAAkB,SAAA,CAAoB;AAAA,IAC1E,KAAK;AACH,aAAO,oBAAC,cAAA,EAAa,OAAc,SAAkB,IAAA,CAAU;AAAA,IACjE,KAAK;AACH,aAAO,oBAAC,eAAA,EAAc,OAAc,IAAA,CAAU;AAAA,IAChD,KAAK;AACH,aAAO,oBAAC,kBAAA,EAAiB,OAAc,IAAA,CAAU;AAAA,IACnD;AACE,aAAO,oBAAC,eAAA,EAAc,OAAc,SAAkB,SAAA,CAAoB;AAAA,EAAA;AAEhF;AAMA,SAAS,cAAc,EAAE,OAAO,WAAqD;AACnF,QAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,QAAM,UAAU,MAAM,SAAS,UAAU,OAAO,uBAAuB,IAAI,IAAI;AAC/E,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAI;AAAA,MACJ,kBAAc;AAAA,MACd,qBAAiB;AAAA,MACjB,WAAU;AAAA,MACV,OAAO,QAAQ;AAAA,MAEd,UAAA,WAAW,oBAAC,QAAA,EAAK,WAAU,yBAAwB,UAAA,IAAA,CAAC;AAAA,IAAA;AAAA,EAAA;AAG3D;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAI;AAAA,MACJ,MAAK;AAAA,MACL,kBAAc;AAAA,MACd,WAAW;AAAA,MACX,OAAO,OAAO,MAAM,KAAK;AAAA,MACzB,UAAU;AAAA,MACV,aAAa,mBAAmB,MAAM,MAAM;AAAA,MAC5C,UAAU,CAAC,MAAM,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,IAAA;AAAA,EAAA;AAGpD;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAGD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAI;AAAA,MACJ,MAAK;AAAA,MACL,WAAU;AAAA,MACV,kBAAc;AAAA,MACd,WAAW;AAAA,MACX,OAAO,OAAO,MAAM,KAAK;AAAA,MACzB,UAAU;AAAA,MACV,aAAa,mBAAmB,MAAM,MAAM;AAAA,MAC5C,UAAU,CAAC,MAAM;AACf,cAAM,MAAM,EAAE,OAAO;AACrB,cAAM,SAAS,MAAM,iBAAiB;AACtC,YAAI,UAAU,IAAI,WAAW,MAAM,OAAO,SAAS,OAAO,GAAG,CAAC,GAAG;AAC/D,gBAAM,SAAS,OAAO,GAAG,CAAC;AAAA,QAC5B,OAAO;AACL,gBAAM,SAAS,GAAG;AAAA,QACpB;AAAA,MACF;AAAA,IAAA;AAAA,EAAA;AAGN;AAMA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,OAAO,OAAO,MAAM,KAAK;AAC/B,MAAI,UAAU;AACZ,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAI;AAAA,QACJ,kBAAc;AAAA,QACd,WAAU;AAAA,QACV,OAAO,QAAQ;AAAA,QAEd,UAAA,OAAO,uBAAuB,IAAI,wBAAK,QAAA,EAAK,WAAU,yBAAwB,UAAA,IAAA,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EAGtF;AACA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAI;AAAA,MACJ,cAAY,MAAM;AAAA,MAClB,kBAAc;AAAA,MACd,gBAAgB,GAAG,gBAAgB,MAAM;AAAA,MACzC,OAAO;AAAA,MACP,UAAU,CAAC,SAAS,MAAM,SAAS,IAAI;AAAA,MACvC,aAAa,mBAAmB,MAAM,MAAM;AAAA,IAAA;AAAA,EAAA;AAGlD;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAID,MAAI,OAAO,MAAM,UAAU,aAAa,MAAM,UAAU,UAAa,MAAM,UAAU,MAAM;AACzF,WACE,oBAAC,OAAA,EAAI,WAAU,yBACb,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAI;AAAA,QACJ,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,UAAU;AAAA,QACzB,UAAU;AAAA,QACV,UAAU,CAAC,MAAM,MAAM,SAAS,EAAE,OAAO,OAAO;AAAA,MAAA;AAAA,IAAA,GAEpD;AAAA,EAEJ;AACA,SAAO,oBAAC,eAAA,EAAc,OAAc,SAAkB,SAAA,CAAoB;AAC5E;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQ,OAAO,MAAM,KAAK;AAChC,QAAM,UAAU,mBAAmB,MAAM,WAAW,CAAA,GAAI,KAAK;AAC7D,MAAI,MAAM,YAAY,SAAS;AAC7B,+BAAQ,mBAAA,EAAkB,OAAc,SAAkB,UAAoB,SAAkB,OAAc;AAAA,EAChH;AACA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,kBAAkB,MAAM,oBAAoB;AAAA,MAC5C,UAAU,CAAC,MAAM,MAAM,SAAS,CAAC;AAAA,MAChC,GAAI,mBAAmB,MAAM,MAAM,IAAI,EAAE,aAAa,mBAAmB,MAAM,MAAM,MAAM,CAAA;AAAA,IAAC;AAAA,EAAA;AAGnG;AAMA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY,MAAM;AAAA,MAClB,IAAI;AAAA,MACJ,kBAAc;AAAA,MACd,WAAU;AAAA,MAET,UAAA,QAAQ,IAAI,CAAC,QAAQ;AACpB,cAAM,UAAU,IAAI,UAAU;AAC9B,eACE;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAW;AAAA,cACT;AAAA,cACA,UACI,uCACA;AAAA,cACJ,YAAY;AAAA,YAAA;AAAA,YAGd,UAAA;AAAA,cAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,MAAM;AAAA,kBACN,WAAU;AAAA,kBACV,OAAO,IAAI;AAAA,kBACX;AAAA,kBACA,UAAU;AAAA,kBACV,UAAU,MAAM,MAAM,SAAS,IAAI,KAAK;AAAA,gBAAA;AAAA,cAAA;AAAA,cAEzC,IAAI;AAAA,YAAA;AAAA,UAAA;AAAA,UAlBA,IAAI;AAAA,QAAA;AAAA,MAqBf,CAAC;AAAA,IAAA;AAAA,EAAA;AAGP;AAKA,SAAS,cAAc,EAAE,OAAO,OAAoD;AAClF,QAAM,MAAM,cAAc,MAAM,KAAK,IAAK,MAAM,QAAoC,CAAA;AACpF,QAAM,YAA8B;AAAA,IAElC,YAAY,MAAM,oBAAoB,CAAA;AAAA,IACtC,GAAI,MAAM,iBAAiB,EAAE,UAAU,MAAM,eAAA,IAAmB,CAAA;AAAA,IAChE,GAAI,MAAM,QAAQ,MAAM,OAAO,KAAK,IAAI,EAAE,OAAO,MAAM,OAAO,MAAA,IAAU,CAAA;AAAA,EAAC;AAQ3E,SACE,oBAAC,OAAA,EAAI,WAAU,aACZ,UAAA,mBAAmB,WAAW,KAAK,CAAC,SAAS,MAAM,SAAS,IAAI,GAAG;AAAA,IAClE,GAAG;AAAA,IACH,UAAU,IAAI,YAAY,MAAM,aAAa;AAAA,IAC7C,OAAO,IAAI,QAAQ;AAAA,EAAA,CACpB,GACH;AAEJ;AAOA,SAAS,iBAAiB,EAAE,OAAO,OAAoD;AAGrF,QAAM,WAAW,IAAI,YAAY,MAAM,aAAa;AACpD,QAAM,MAAM,cAAc,MAAM,KAAK,IAAK,MAAM,QAAoC,CAAA;AACpF,QAAM,QAAQ,MAAM,mBAAmB,CAAA;AACvC,QAAM,YAAY,OAAO,KAAK,KAAK;AACnC,QAAM,YAAY,OAAO,KAAK,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,MAAM;AAC9D,QAAM,WAA0B,EAAE,GAAG,KAAK,UAAU,OAAO,IAAI,QAAQ,EAAA;AAEvE,WAAS,SAAS,KAAa,MAAe;AAC5C,UAAM,SAAS,EAAE,GAAG,KAAK,CAAC,GAAG,GAAG,MAAM;AAAA,EACxC;AACA,WAAS,YAAY,QAAgB,QAAgB;AACnD,QAAI,WAAW,OAAQ;AACvB,UAAM,OAAgC,CAAA;AACtC,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,EAAG,MAAK,MAAM,SAAS,SAAS,CAAC,IAAI;AAC5E,UAAM,SAAS,IAAI;AAAA,EACrB;AACA,WAAS,YAAY,KAAa;AAChC,UAAM,OAAO,EAAE,GAAG,IAAA;AAClB,WAAO,KAAK,GAAG;AACf,UAAM,SAAS,IAAI;AAAA,EACrB;AACA,WAAS,WAAW;AAClB,QAAI,MAAM,IAAK;AACf,UAAM,SAAS,EAAE,GAAG,KAAK,IAAI,IAAI;AAAA,EACnC;AAEA,WAAS,gBAAgB,KAAa,aAA4C;AAChF,UAAM,QAAQ;AAAA,MACZ;AAAA,QACE;AAAA,QACA,MAAM;AAAA,QACN,UAAU;AAAA,QACV,OAAO,IAAI,GAAG,KAAK;AAAA,QACnB,UAAU,CAAC,SAAS,SAAS,KAAK,IAAI;AAAA,MAAA;AAAA,MAExC;AAAA,IAAA;AAEF,YAAO,+BAAO,UAAS;AAAA,EACzB;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,gDACZ,UAAA;AAAA,IAAA,UAAU,IAAI,CAAC,QACd,qBAAC,OAAA,EAAyB,WAAU,iDAClC,UAAA;AAAA,MAAA,oBAAC,SAAA,EAAM,SAAS,aAAa,GAAG,GAAG,WAAU,0CAAyC,OAAO,KAC1F,UAAA,IAAA,CACH;AAAA,MACA,oBAAC,OAAA,EAAI,WAAU,WAAW,UAAA,gBAAgB,KAAK,MAAM,GAAG,KAAK,EAAE,MAAM,SAAA,CAAU,EAAA,CAAE;AAAA,IAAA,EAAA,GAJzE,SAAS,GAAG,EAKtB,CACD;AAAA,IACA,UAAU,IAAI,CAAC,QACd,qBAAC,OAAA,EAAyB,WAAU,sDAClC,UAAA;AAAA,MAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,WAAW,GAAG,gBAAgB,uBAAuB;AAAA,UACrD,OAAO;AAAA,UACP,UAAU;AAAA,UACV,UAAU,CAAC,MAAM,YAAY,KAAK,EAAE,OAAO,KAAK;AAAA,QAAA;AAAA,MAAA;AAAA,MAElD,oBAAC,OAAA,EAAI,WAAU,WACZ,UAAA,gBAAgB,KAAK,MAAM,eAAe,EAAE,MAAM,SAAA,CAAU,EAAA,CAC/D;AAAA,MACC,CAAC,YACA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAY,UAAU,GAAG;AAAA,UACzB,WAAU;AAAA,UACV,SAAS,MAAM,YAAY,GAAG;AAAA,UAE9B,UAAA,oBAAC,MAAA,EAAK,MAAM,SAAS,WAAU,UAAA,CAAU;AAAA,QAAA;AAAA,MAAA;AAAA,IAC3C,EAAA,GApBM,SAAS,GAAG,EAsBtB,CACD;AAAA,IACA,CAAC,YAAY,MAAM,mBAAmB,8BACpC,QAAA,EAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,SAAS,UAAU,WAAU,WAC7E,UAAA;AAAA,MAAA,oBAAC,MAAA,EAAK,MAAM,OAAO,WAAU,WAAU;AAAA,MAAE;AAAA,IAAA,EAAA,CAE3C;AAAA,EAAA,GAEJ;AAEJ;AAEA,SAAS,mBACP,SACA,OACoC;AACpC,MAAI,CAAC,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK,EAAG,QAAO;AAC7D,SAAO,CAAC,EAAE,OAAO,OAAO,MAAA,GAAS,GAAG,OAAO;AAC7C;AAEA,SAAS,OAAO,OAAwB;AACtC,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,cAAc,OAAkD;AACvE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEO,SAAS,mBAAmB,QAAoC;AACrE,MAAI,OAAO,WAAW,QAAQ,OAAO,OAAO,YAAY,SAAU,QAAO,OAAO,OAAO,OAAO;AAC9F,SAAO;AACT;"}
@@ -56,7 +56,7 @@ function renderFieldRow(args, ctx, opts) {
56
56
  return /* @__PURE__ */ jsxRuntime.jsx(
57
57
  jsonSchemaFormFields.FieldWrapper,
58
58
  {
59
- inline: ctx.inline,
59
+ layout: ctx.layout,
60
60
  label,
61
61
  value: built.value,
62
62
  ...field.helper ? { helper: field.helper } : {},
@@ -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 { 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\";\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 // 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 layout={ctx.layout}\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,9 +1,9 @@
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
3
  export interface RenderContext {
4
4
  readOnly: boolean;
5
5
  hideReadOnlyFields: boolean;
6
- inline: boolean;
6
+ layout: FormLayout;
7
7
  requiredFirst: boolean;
8
8
  pre: PreExtension[];
9
9
  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;AASvC,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACb,MAAM,0BAA0B,CAAC;AAMlC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAGlB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;IAGhB,aAAa,EAAE,OAAO,CAAC;IACvB,GAAG,EAAE,YAAY,EAAE,CAAC;IACpB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAkCD,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,CA6ClB;AA0CD,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
+ {"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;AASvC,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACb,MAAM,0BAA0B,CAAC;AAMlC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAGlB,kBAAkB,EAAE,OAAO,CAAC;IAE5B,MAAM,EAAE,UAAU,CAAC;IAGnB,aAAa,EAAE,OAAO,CAAC;IACvB,GAAG,EAAE,YAAY,EAAE,CAAC;IACpB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAkCD,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,CA6ClB;AA0CD,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"}
@@ -54,7 +54,7 @@ function renderFieldRow(args, ctx, opts) {
54
54
  return /* @__PURE__ */ jsx(
55
55
  FieldWrapper,
56
56
  {
57
- inline: ctx.inline,
57
+ layout: ctx.layout,
58
58
  label,
59
59
  value: built.value,
60
60
  ...field.helper ? { helper: field.helper } : {},
@@ -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 { 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\";\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 // 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 layout={ctx.layout}\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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"}
@@ -81,13 +81,29 @@ export type PostExtension = (field: FieldControl, nodes: {
81
81
  label: ReactNode;
82
82
  value: ReactNode;
83
83
  };
84
+ export interface FormLayout {
85
+ /** "inline" = 2-column label/value; "stacked" = label above value. */
86
+ mode: "inline" | "stacked";
87
+ /** Inline only: max width of the label column (CSS length). Default "40ch". */
88
+ labelMaxWidth?: string;
89
+ /** Inline only: max width of the value column (CSS length). Default "400px". */
90
+ valueMaxWidth?: string;
91
+ }
84
92
  export interface JsonSchemaFormProps {
85
93
  schema: JsonSchemaObject;
86
94
  value: Record<string, unknown>;
87
95
  onChange: (next: Record<string, unknown>) => void;
88
96
  readOnly?: boolean;
89
- /** Inline 2-column label/field layout; stacked when false (default). */
97
+ /**
98
+ * Shorthand for `layout: { mode: "inline" }` (2-column label/value); stacked
99
+ * when false (default). Ignored when `layout` is provided.
100
+ */
90
101
  inline?: boolean;
102
+ /**
103
+ * Form-level layout. Takes precedence over `inline`. Inline mode caps the
104
+ * label column (default 40ch) and value column (default 400px).
105
+ */
106
+ layout?: FormLayout;
91
107
  /**
92
108
  * Omit fields whose schema declares `readOnly: true` entirely, instead of
93
109
  * rendering them as read-only value displays. Applies at every depth.
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema-form-types.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"json-schema-form-types.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IACpD,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAKhC,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,EAAE,CAAC,EAAE,kBAAkB,CAAC;IACxB,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAE1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,SAAS,GACT,MAAM,CAAC;AAKX,MAAM,WAAW,qBAAqB;IACpC,EAAE,CAAC,EAAE,kBAAkB,CAAC;IACxB,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAKD,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAC;IACpD,KAAK,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,MAAM,GACN,MAAM,GACN,YAAY,GACZ,OAAO,GACP,QAAQ,CAAC;AAIb,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC;AAM/C,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAMlC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,SAAS,CAAC,EAAE,aAAa,CAAC;IAG1B,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IAGxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAG3B,OAAO,CAAC,EAAE,WAAW,CAAC;IAGtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,OAAO,CAAC,EAAE,MAAM,CAAC;IAIjB,YAAY,CAAC,EAAE,OAAO,CAAC;IAIvB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAGlC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACrD,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAGhC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAID,MAAM,MAAM,YAAY,GAAG,CACzB,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,KAC3D,YAAY,GAAG,IAAI,CAAC;AAIzB,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,KAC1C;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAK5C,MAAM,WAAW,UAAU;IACzB,sEAAsE;IACtE,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC;CACxB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flanksource/clicky-ui",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.",
5
5
  "homepage": "https://github.com/flanksource/clicky-ui#readme",
6
6
  "bugs": "https://github.com/flanksource/clicky-ui/issues",