@keboola/design 11.0.1 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/AGENTS.md +16 -1
  2. package/CHANGELOG.md +2138 -0
  3. package/COMPONENT-API.md +40 -1
  4. package/dist/{AIKit-Dre37SJr.js → AIKit-DiS0CVOW.js} +6 -6
  5. package/dist/{AIKit-Dre37SJr.js.map → AIKit-DiS0CVOW.js.map} +1 -1
  6. package/dist/{AlertModal-BUC4Es8o.js → AlertModal-Dp_XuJBW.js} +3 -6
  7. package/dist/{AlertModal-BUC4Es8o.js.map → AlertModal-Dp_XuJBW.js.map} +1 -1
  8. package/dist/{BrandEditor-B8o9zdZO.js → BrandEditor-DyzgfVkl.js} +6 -6
  9. package/dist/{BrandEditor-B8o9zdZO.js.map → BrandEditor-DyzgfVkl.js.map} +1 -1
  10. package/dist/{Breadcrumb-DJp7WwSv.js → Breadcrumb-Frst8MTA.js} +3 -3
  11. package/dist/{Breadcrumb-DJp7WwSv.js.map → Breadcrumb-Frst8MTA.js.map} +1 -1
  12. package/dist/{Button-nzmDNS2q.js → Button-6xBX0nNl.js} +15 -15
  13. package/dist/Button-6xBX0nNl.js.map +1 -0
  14. package/dist/{ClipboardButton-ez5V3fkk.js → ClipboardButton-ClcluT0C.js} +2 -2
  15. package/dist/{ClipboardButton-ez5V3fkk.js.map → ClipboardButton-ClcluT0C.js.map} +1 -1
  16. package/dist/{CodeEditor-BfQJfbhL.js → CodeEditor-DyaN-Ij2.js} +58 -10
  17. package/dist/CodeEditor-DyaN-Ij2.js.map +1 -0
  18. package/dist/{ColorInput-Dx8Dsv7Y.js → ColorInput-B8z4j4Y_.js} +2 -2
  19. package/dist/{ColorInput-Dx8Dsv7Y.js.map → ColorInput-B8z4j4Y_.js.map} +1 -1
  20. package/dist/{ColorModeSwitch-CCqj7tjE.js → ColorModeSwitch-dZFZyqy1.js} +3 -3
  21. package/dist/{ColorModeSwitch-CCqj7tjE.js.map → ColorModeSwitch-dZFZyqy1.js.map} +1 -1
  22. package/dist/{Combobox-c_xBjf0P.js → Combobox-Dgm6Z4ib.js} +9 -5
  23. package/dist/Combobox-Dgm6Z4ib.js.map +1 -0
  24. package/dist/{Command-CQ_bQsJp.js → Command-C0aZfVTq.js} +2 -2
  25. package/dist/{Command-CQ_bQsJp.js.map → Command-C0aZfVTq.js.map} +1 -1
  26. package/dist/{DateInput-CMD3dY-T.js → DateInput-B3UdzRfW.js} +3 -3
  27. package/dist/{DateInput-CMD3dY-T.js.map → DateInput-B3UdzRfW.js.map} +1 -1
  28. package/dist/{DatePicker-BbFbmsGl.js → DatePicker-Dw3DpbUh.js} +2 -2
  29. package/dist/{DatePicker-BbFbmsGl.js.map → DatePicker-Dw3DpbUh.js.map} +1 -1
  30. package/dist/{DateRangeInput-D3BhiKyk.js → DateRangeInput-DTuySEiq.js} +3 -3
  31. package/dist/{DateRangeInput-D3BhiKyk.js.map → DateRangeInput-DTuySEiq.js.map} +1 -1
  32. package/dist/{DateRangePicker-BiUgtt_M.js → DateRangePicker-DCmMHg4s.js} +4 -4
  33. package/dist/{DateRangePicker-BiUgtt_M.js.map → DateRangePicker-DCmMHg4s.js.map} +1 -1
  34. package/dist/{DropdownMenu-B6ZbYvaM.js → DropdownMenu-t90tVw6l.js} +8 -8
  35. package/dist/DropdownMenu-t90tVw6l.js.map +1 -0
  36. package/dist/FieldItem-CAPj9lj3.d.ts +111 -0
  37. package/dist/FieldItem-D-h1NeBo.js +108 -0
  38. package/dist/FieldItem-D-h1NeBo.js.map +1 -0
  39. package/dist/{FileUpload-sXRv7JiY.js → FileUpload-BRv0TaZk.js} +2 -2
  40. package/dist/{FileUpload-sXRv7JiY.js.map → FileUpload-BRv0TaZk.js.map} +1 -1
  41. package/dist/{Form-BDCef6O9.js → Form-DHvcFoEi.js} +18 -78
  42. package/dist/{Form-BDCef6O9.js.map → Form-DHvcFoEi.js.map} +1 -1
  43. package/dist/{FormGroup-S9mPNHKH.js → FormGroup-C41n65cE.js} +7 -7
  44. package/dist/FormGroup-C41n65cE.js.map +1 -0
  45. package/dist/{FullScreenModal-CJa2VkJ2.js → FullScreenModal-Cb3PGgh4.js} +2 -2
  46. package/dist/{FullScreenModal-CJa2VkJ2.js.map → FullScreenModal-Cb3PGgh4.js.map} +1 -1
  47. package/dist/{InputGroup-BJWsI35s.js → InputGroup-CdTq8H7c.js} +2 -2
  48. package/dist/{InputGroup-BJWsI35s.js.map → InputGroup-CdTq8H7c.js.map} +1 -1
  49. package/dist/{MermaidDiagram-BB06gymm.js → MermaidDiagram-ChL3WIQT.js} +2 -2
  50. package/dist/{MermaidDiagram-BB06gymm.js.map → MermaidDiagram-ChL3WIQT.js.map} +1 -1
  51. package/dist/{Modal-BA5Wc3sx.js → Modal-wqG8nJiK.js} +2 -2
  52. package/dist/{Modal-BA5Wc3sx.js.map → Modal-wqG8nJiK.js.map} +1 -1
  53. package/dist/{MultiActionButtonGroup-CiBHxsSk.js → MultiActionButtonGroup-BiIIubiL.js} +2 -2
  54. package/dist/{MultiActionButtonGroup-CiBHxsSk.js.map → MultiActionButtonGroup-BiIIubiL.js.map} +1 -1
  55. package/dist/{Navbar-t16usFZQ.js → Navbar-BfaPeLUL.js} +5 -2
  56. package/dist/Navbar-BfaPeLUL.js.map +1 -0
  57. package/dist/{PageToolbar-0_1OBzaZ.js → PageToolbar-OQg3mPF-.js} +4 -4
  58. package/dist/PageToolbar-OQg3mPF-.js.map +1 -0
  59. package/dist/{Pagination-CM_Rszz-.js → Pagination-Cjfda8KG.js} +2 -2
  60. package/dist/{Pagination-CM_Rszz-.js.map → Pagination-Cjfda8KG.js.map} +1 -1
  61. package/dist/{Popconfirm-BGe1jLov.js → Popconfirm-D7_vfxFd.js} +4 -7
  62. package/dist/{Popconfirm-BGe1jLov.js.map → Popconfirm-D7_vfxFd.js.map} +1 -1
  63. package/dist/{Popover-Ca0V6AD1.js → Popover-CzeHjvrB.js} +6 -13
  64. package/dist/Popover-CzeHjvrB.js.map +1 -0
  65. package/dist/{SearchInput-D2fcOv7E.js → SearchInput-C7dF_Ir-.js} +2 -2
  66. package/dist/{SearchInput-D2fcOv7E.js.map → SearchInput-C7dF_Ir-.js.map} +1 -1
  67. package/dist/{SectionNav--7bw2b6u.js → SectionNav-8NoTOKO8.js} +3 -3
  68. package/dist/{SectionNav--7bw2b6u.js.map → SectionNav-8NoTOKO8.js.map} +1 -1
  69. package/dist/{Select-4YX38G5h.js → Select-Is0VkePH.js} +2 -2
  70. package/dist/{Select-4YX38G5h.js.map → Select-Is0VkePH.js.map} +1 -1
  71. package/dist/{Sheet-BQrX8-h5.js → Sheet-Dw9BDvjI.js} +2 -2
  72. package/dist/{Sheet-BQrX8-h5.js.map → Sheet-Dw9BDvjI.js.map} +1 -1
  73. package/dist/{Sidebar-ROaR_AqC.js → Sidebar-Dcb4rinA.js} +2 -2
  74. package/dist/{Sidebar-ROaR_AqC.js.map → Sidebar-Dcb4rinA.js.map} +1 -1
  75. package/dist/{Slider-Da_3mS5v.js → Slider-BOPfMOMm.js} +2 -2
  76. package/dist/{Slider-Da_3mS5v.js.map → Slider-BOPfMOMm.js.map} +1 -1
  77. package/dist/{Tabs-EAihyqCt.js → Tabs-UMQuDoW8.js} +2 -2
  78. package/dist/{Tabs-EAihyqCt.js.map → Tabs-UMQuDoW8.js.map} +1 -1
  79. package/dist/{TextInput-BGed-V13.js → TextInput-CMuN1WfY.js} +2 -2
  80. package/dist/{TextInput-BGed-V13.js.map → TextInput-CMuN1WfY.js.map} +1 -1
  81. package/dist/{TimePicker-B_NegL-7.js → TimePicker-D9zktB8A.js} +2 -2
  82. package/dist/{TimePicker-B_NegL-7.js.map → TimePicker-D9zktB8A.js.map} +1 -1
  83. package/dist/{ZoomableSvg-DG9PnAm8.js → ZoomableSvg-CZEu6sAq.js} +3 -3
  84. package/dist/{ZoomableSvg-DG9PnAm8.js.map → ZoomableSvg-CZEu6sAq.js.map} +1 -1
  85. package/dist/editors.d.ts +71 -9
  86. package/dist/editors.js +58 -3
  87. package/dist/editors.js.map +1 -1
  88. package/dist/index.d.ts +314 -312
  89. package/dist/index.js +41 -40
  90. package/dist/internal/blocks/AIKit.js +1 -1
  91. package/dist/internal/blocks/BrandEditor.js +1 -1
  92. package/dist/internal/blocks/ClipboardButton.js +1 -1
  93. package/dist/internal/blocks/ColorInput.js +1 -1
  94. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  95. package/dist/internal/blocks/Command.js +1 -1
  96. package/dist/internal/blocks/DateInput.js +1 -1
  97. package/dist/internal/blocks/DateRangeInput.js +1 -1
  98. package/dist/internal/blocks/ExportMenu.js +2 -2
  99. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +56 -0
  100. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js.map +1 -0
  101. package/dist/internal/blocks/Form.js +1 -1
  102. package/dist/internal/blocks/FormGroup.js +1 -1
  103. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  104. package/dist/internal/blocks/MultiCombobox.js +8 -3
  105. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  106. package/dist/internal/blocks/NumberInput.js +1 -1
  107. package/dist/internal/blocks/PageToolbar.js +1 -1
  108. package/dist/internal/blocks/PasswordInput.js +1 -1
  109. package/dist/internal/blocks/SearchInput.js +1 -1
  110. package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
  111. package/dist/internal/blocks/SectionNav.js +1 -1
  112. package/dist/internal/blocks/SplitButton.js +2 -2
  113. package/dist/internal/blocks/TextInput.js +1 -1
  114. package/dist/internal/blocks/Textarea.js +1 -1
  115. package/dist/internal/blocks/TimeInput.js +2 -2
  116. package/dist/internal/components/AlertModal.js +1 -1
  117. package/dist/internal/components/Breadcrumb.js +1 -1
  118. package/dist/internal/components/Button.js +1 -1
  119. package/dist/internal/components/Combobox.js +1 -1
  120. package/dist/internal/components/DatePicker.js +1 -1
  121. package/dist/internal/components/DateRangePicker.js +1 -1
  122. package/dist/internal/components/DropdownMenu.js +1 -1
  123. package/dist/internal/components/FileUpload.js +1 -1
  124. package/dist/internal/components/FullScreenModal.js +1 -1
  125. package/dist/internal/components/InputGroup.js +1 -1
  126. package/dist/internal/components/Modal.js +1 -1
  127. package/dist/internal/components/Navbar.js +1 -1
  128. package/dist/internal/components/Pagination.js +1 -1
  129. package/dist/internal/components/Popconfirm.js +1 -1
  130. package/dist/internal/components/Popover.js +1 -1
  131. package/dist/internal/components/Select.js +1 -1
  132. package/dist/internal/components/Sheet.js +1 -1
  133. package/dist/internal/components/Sidebar.js +1 -1
  134. package/dist/internal/components/Slider.js +1 -1
  135. package/dist/internal/components/Tabs.js +1 -1
  136. package/dist/internal/components/TimePicker.js +1 -1
  137. package/dist/internal/components/ZoomableSvg.js +1 -1
  138. package/dist/markdown-editor.js +5 -5
  139. package/dist/mermaid.js +1 -1
  140. package/dist/rjsf.d.ts +13 -1
  141. package/dist/rjsf.js +233 -173
  142. package/dist/rjsf.js.map +1 -1
  143. package/dist/styles.css +1 -1
  144. package/package.json +7 -6
  145. package/dist/Button-nzmDNS2q.js.map +0 -1
  146. package/dist/CodeEditor-BfQJfbhL.js.map +0 -1
  147. package/dist/Combobox-c_xBjf0P.js.map +0 -1
  148. package/dist/DropdownMenu-B6ZbYvaM.js.map +0 -1
  149. package/dist/FormGroup-S9mPNHKH.js.map +0 -1
  150. package/dist/Navbar-t16usFZQ.js.map +0 -1
  151. package/dist/PageToolbar-0_1OBzaZ.js.map +0 -1
  152. package/dist/Popover-Ca0V6AD1.js.map +0 -1
  153. package/dist/constants-D6JcsD4_.d.ts +0 -41
package/dist/rjsf.js CHANGED
@@ -1,111 +1,26 @@
1
1
  import { Tooltip, debounce } from "./utils-D0c5VAyF.js";
2
2
  import { BookOpen, Info, Trash2 } from "./icons-Cek151jC.js";
3
- import { Button } from "./Button-nzmDNS2q.js";
3
+ import { Button } from "./Button-6xBX0nNl.js";
4
4
  import { Label } from "./internal/components/Label.js";
5
5
  import { Link } from "./internal/components/Link.js";
6
- import { TextInput } from "./TextInput-BGed-V13.js";
6
+ import { TextInput } from "./TextInput-CMuN1WfY.js";
7
7
  import { RadioGroup } from "./RadioGroup-sIveSsNa.js";
8
8
  import { Checkbox } from "./Checkbox-GJ8-srt4.js";
9
- import { Combobox } from "./Combobox-c_xBjf0P.js";
10
- import { Textarea } from "./internal/blocks/Textarea.js";
11
- import { DateInput } from "./DateInput-CMD3dY-T.js";
9
+ import { Combobox } from "./Combobox-Dgm6Z4ib.js";
10
+ import { FormGroup } from "./FormGroup-C41n65cE.js";
12
11
  import { NumberInput } from "./internal/blocks/NumberInput.js";
12
+ import { Textarea } from "./internal/blocks/Textarea.js";
13
+ import { DateInput } from "./DateInput-B3UdzRfW.js";
13
14
  import { PasswordInput } from "./internal/blocks/PasswordInput.js";
14
- import { FormGroup } from "./FormGroup-S9mPNHKH.js";
15
15
  import { Alert } from "./Alert-DfZq9kGe.js";
16
16
  import { CollapsiblePanel } from "./internal/components/CollapsiblePanel.js";
17
- import { Tabs, TabsContent } from "./Tabs-EAihyqCt.js";
18
- import { CodeEditor, isLanguageMode } from "./CodeEditor-BfQJfbhL.js";
17
+ import { Tabs, TabsContent } from "./Tabs-UMQuDoW8.js";
18
+ import { CodeEditor, isLanguageMode } from "./CodeEditor-DyaN-Ij2.js";
19
19
  import { createContext, isValidElement, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
20
20
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
21
21
  import DOMPurify from "dompurify";
22
22
  import Form from "@rjsf/core";
23
23
  import validator from "@rjsf/validator-ajv8";
24
- //#region src/blocks/RjsfSchemaEditor/markdownContext.ts
25
- /** Falls back to plain text when the host app doesn't provide a markdown renderer. */
26
- const RenderMarkdownContext = createContext((source) => source);
27
- const RenderMarkdownProvider = RenderMarkdownContext;
28
- const useRenderMarkdown = () => use(RenderMarkdownContext);
29
- //#endregion
30
- //#region src/blocks/RjsfSchemaEditor/widgets/CodeEditorWidget.tsx
31
- const isValidJson = (raw) => {
32
- try {
33
- const parsed = JSON.parse(raw);
34
- return Boolean(parsed && typeof parsed === "object");
35
- } catch {
36
- return false;
37
- }
38
- };
39
- const sanitize = (val) => {
40
- if (typeof val === "object" && val !== null) return JSON.stringify(val, null, " ");
41
- return String(val ?? "");
42
- };
43
- const CodeEditorWidget = ({ id, value, onChange, disabled, readonly, options }) => {
44
- const editorOptions = options.editor ?? {};
45
- const rawMode = editorOptions.mode ?? "application/json";
46
- const mode = isLanguageMode(rawMode) ? rawMode : "application/json";
47
- const isJsonMode = mode === "application/json";
48
- const isReadOnly = disabled || readonly || !!editorOptions.readOnly;
49
- const [text, setText] = useState(() => sanitize(value));
50
- useEffect(() => {
51
- setText((currentText) => {
52
- const sanitized = sanitize(value);
53
- if (currentText === sanitized) return currentText;
54
- if (isJsonMode && isValidJson(currentText)) try {
55
- if (JSON.stringify(JSON.parse(currentText)) === JSON.stringify(typeof value === "object" ? value : JSON.parse(sanitized))) return currentText;
56
- } catch {}
57
- return sanitized;
58
- });
59
- }, [value, isJsonMode]);
60
- const handleChange = (raw) => {
61
- setText(raw);
62
- if (isJsonMode && isValidJson(raw)) onChange(JSON.parse(raw));
63
- else onChange(raw);
64
- };
65
- const help = isJsonMode && !isReadOnly && options.encryptionHint !== false ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
66
- "Properties prefixed with ",
67
- /* @__PURE__ */ jsx("code", { children: "#" }),
68
- " sign will be encrypted on save. Already encrypted strings will persist."
69
- ] }) : null;
70
- return /* @__PURE__ */ jsx("div", {
71
- id,
72
- children: isReadOnly ? /* @__PURE__ */ jsx(CodeEditor, {
73
- variant: "field",
74
- value: text,
75
- mode,
76
- readOnly: true,
77
- withCopyButton: true,
78
- withLineNumbers: editorOptions.lineNumbers !== false
79
- }) : /* @__PURE__ */ jsx(CodeEditor, {
80
- variant: "field",
81
- value: text,
82
- mode,
83
- onChange: handleChange,
84
- withCopyButton: true,
85
- withLineNumbers: editorOptions.lineNumbers !== false,
86
- help
87
- })
88
- });
89
- };
90
- //#endregion
91
- //#region src/blocks/RjsfSchemaEditor/fields/CodeEditorField.tsx
92
- /**
93
- * Field wrapper for CodeEditorWidget when used with type: "object".
94
- * RJSF only applies ui:widget to primitive types, so object-typed
95
- * code editors need a custom field that delegates to the widget.
96
- */
97
- const CodeEditorField = ({ fieldPathId, formData, onChange, disabled, readonly, uiSchema }) => {
98
- const uiOptions = uiSchema?.["ui:options"];
99
- return /* @__PURE__ */ jsx(CodeEditorWidget, {
100
- id: fieldPathId.$id,
101
- value: formData,
102
- onChange: (val) => onChange(val, fieldPathId.path),
103
- disabled: !!disabled,
104
- readonly: !!readonly,
105
- options: uiOptions ?? {}
106
- });
107
- };
108
- //#endregion
109
24
  //#region src/blocks/RjsfSchemaEditor/fieldHelpers.ts
110
25
  /** No-op function reused as onBlur/onFocus stub in custom fields. */
111
26
  const noop = () => {};
@@ -118,6 +33,8 @@ const SCHEMA_FIELD_STUBS = {
118
33
  onFocus: noop,
119
34
  errorSchema: {}
120
35
  };
36
+ /** Whether a value is a keyed namespace — an object that is neither `null` nor an array. */
37
+ const isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
121
38
  /**
122
39
  * Resolves a dot-path against an object (e.g. "_metadata_.table.columns").
123
40
  *
@@ -143,17 +60,6 @@ const resolveByPath = (path, data) => {
143
60
  return result;
144
61
  };
145
62
  /**
146
- * Whether a `template-watch` field is the invisible computed-helper variant.
147
- *
148
- * - `template-watch` replaces `ui:widget: 'hidden'`, so `ui:options.hidden` carries the schema's
149
- * `options.hidden` instead.
150
- * - The field stays mounted either way; only its wrapper is hidden.
151
- */
152
- const isHiddenTemplateWatch = (uiSchema) => {
153
- if (uiSchema?.["ui:widget"] !== "template-watch") return false;
154
- return !!uiSchema["ui:options"]?.hidden;
155
- };
156
- /**
157
63
  * Extracts a property name from a simple Mustache-like template.
158
64
  * e.g. "{{item.field_name}}" → "field_name"
159
65
  */
@@ -210,6 +116,122 @@ const childFieldPathId = (parentFieldPathId, ...segments) => ({
210
116
  * for properties without an explicit order.
211
117
  */
212
118
  const sortByPropertyOrder = (properties) => Object.entries(properties).sort(([, a], [, b]) => (a.propertyOrder ?? Number.MAX_SAFE_INTEGER) - (b.propertyOrder ?? Number.MAX_SAFE_INTEGER)).map(([key]) => key);
119
+ /**
120
+ * Whether the schema asked for this field to be hidden.
121
+ *
122
+ * - `ui:widget: 'hidden'` is what RJSF itself reads, but any widget branch in
123
+ * `generateUiSchema` that runs later claims the slot and erases it.
124
+ * - `ui:options.hidden` is the copy written last, so it survives all of them.
125
+ */
126
+ const isHiddenField = (fieldUiSchema) => fieldUiSchema?.["ui:widget"] === "hidden" || !!fieldUiSchema?.["ui:options"]?.hidden;
127
+ /**
128
+ * Whether a schema node holds children.
129
+ *
130
+ * - `properties`, `additionalProperties`, `patternProperties` or `items` alone qualify —
131
+ * json-editor infers the container type from them and omits `type`.
132
+ * - `type` may be a union (`['object', 'null']`).
133
+ */
134
+ const isContainerSchema = (schema) => {
135
+ if (!schema) return false;
136
+ if (schema.properties || schema.additionalProperties || schema.patternProperties) return true;
137
+ if (schema.items) return true;
138
+ if (Array.isArray(schema.type)) return schema.type.includes("object") || schema.type.includes("array");
139
+ return schema.type === "object" || schema.type === "array";
140
+ };
141
+ /**
142
+ * Whether a hidden field's whole subtree should leave the form.
143
+ *
144
+ * - Hidden containers mount nothing. RJSF recurses into objects and arrays regardless of
145
+ * hiddenness, so a `_metadata_` subtree costs hundreds of fields for no visible output.
146
+ * - Hidden leaves are kept, wrapped in `tw:hidden`: their mount-phase onChange writes the
147
+ * schema default that sibling `options.dependencies` resolve against.
148
+ */
149
+ const isHiddenContainer = (fieldUiSchema, schema) => isHiddenField(fieldUiSchema) && isContainerSchema(schema);
150
+ //#endregion
151
+ //#region src/blocks/RjsfSchemaEditor/markdownContext.ts
152
+ /** Falls back to plain text when the host app doesn't provide a markdown renderer. */
153
+ const RenderMarkdownContext = createContext((source) => source);
154
+ const RenderMarkdownProvider = RenderMarkdownContext;
155
+ const useRenderMarkdown = () => use(RenderMarkdownContext);
156
+ //#endregion
157
+ //#region src/blocks/RjsfSchemaEditor/widgets/CodeEditorWidget.tsx
158
+ const isValidJson = (raw) => {
159
+ try {
160
+ const parsed = JSON.parse(raw);
161
+ return Boolean(parsed && typeof parsed === "object");
162
+ } catch {
163
+ return false;
164
+ }
165
+ };
166
+ const sanitize = (val) => {
167
+ if (typeof val === "object" && val !== null) return JSON.stringify(val, null, " ");
168
+ return String(val ?? "");
169
+ };
170
+ const CodeEditorWidget = ({ id, value, onChange, disabled, readonly, options }) => {
171
+ const editorOptions = options.editor ?? {};
172
+ const rawMode = editorOptions.mode ?? "application/json";
173
+ const mode = isLanguageMode(rawMode) ? rawMode : "application/json";
174
+ const isJsonMode = mode === "application/json";
175
+ const isReadOnly = disabled || readonly || !!editorOptions.readOnly;
176
+ const [text, setText] = useState(() => sanitize(value));
177
+ useEffect(() => {
178
+ setText((currentText) => {
179
+ const sanitized = sanitize(value);
180
+ if (currentText === sanitized) return currentText;
181
+ if (isJsonMode && isValidJson(currentText)) try {
182
+ if (JSON.stringify(JSON.parse(currentText)) === JSON.stringify(typeof value === "object" ? value : JSON.parse(sanitized))) return currentText;
183
+ } catch {}
184
+ return sanitized;
185
+ });
186
+ }, [value, isJsonMode]);
187
+ const handleChange = (raw) => {
188
+ setText(raw);
189
+ if (isJsonMode && isValidJson(raw)) onChange(JSON.parse(raw));
190
+ else onChange(raw);
191
+ };
192
+ const help = isJsonMode && !isReadOnly && options.encryptionHint !== false ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
193
+ "Properties prefixed with ",
194
+ /* @__PURE__ */ jsx("code", { children: "#" }),
195
+ " sign will be encrypted on save. Already encrypted strings will persist."
196
+ ] }) : null;
197
+ return /* @__PURE__ */ jsx("div", {
198
+ id,
199
+ children: isReadOnly ? /* @__PURE__ */ jsx(CodeEditor, {
200
+ variant: "field",
201
+ value: text,
202
+ mode,
203
+ readOnly: true,
204
+ withCopyButton: true,
205
+ withLineNumbers: editorOptions.lineNumbers !== false
206
+ }) : /* @__PURE__ */ jsx(CodeEditor, {
207
+ variant: "field",
208
+ value: text,
209
+ mode,
210
+ onChange: handleChange,
211
+ withCopyButton: true,
212
+ withLineNumbers: editorOptions.lineNumbers !== false,
213
+ help
214
+ })
215
+ });
216
+ };
217
+ //#endregion
218
+ //#region src/blocks/RjsfSchemaEditor/fields/CodeEditorField.tsx
219
+ /**
220
+ * Field wrapper for CodeEditorWidget when used with type: "object".
221
+ * RJSF only applies ui:widget to primitive types, so object-typed
222
+ * code editors need a custom field that delegates to the widget.
223
+ */
224
+ const CodeEditorField = ({ fieldPathId, formData, onChange, disabled, readonly, uiSchema }) => {
225
+ const uiOptions = uiSchema?.["ui:options"];
226
+ return /* @__PURE__ */ jsx(CodeEditorWidget, {
227
+ id: fieldPathId.$id,
228
+ value: formData,
229
+ onChange: (val) => onChange(val, fieldPathId.path),
230
+ disabled: !!disabled,
231
+ readonly: !!readonly,
232
+ options: uiOptions ?? {}
233
+ });
234
+ };
213
235
  //#endregion
214
236
  //#region src/blocks/RjsfSchemaEditor/SchemaDescription.tsx
215
237
  /** Renders a schema description with sanitized HTML support (links, formatting, etc.). */
@@ -245,14 +267,15 @@ const GridObjectField = ({ schema, uiSchema = {}, formData, onChange, disabled,
245
267
  const hasCollapsed = uiOptions?.collapsed !== void 0;
246
268
  const collapsed = !!uiOptions?.collapsed;
247
269
  const disableCollapse = !!uiOptions?.disableCollapse;
248
- const sortedKeys = sortByPropertyOrder(properties);
249
- if (sortedKeys.length === 0) return null;
270
+ const mountedKeys = sortByPropertyOrder(properties).filter((key) => !isHiddenContainer(uiSchema[key], properties[key]));
271
+ if (mountedKeys.length === 0) return null;
250
272
  const gridContent = /* @__PURE__ */ jsx("div", {
251
273
  className: "tw:grid tw:grid-cols-12 tw:gap-4 tw:[&>div:empty]:hidden",
252
- children: sortedKeys.map((key) => {
274
+ children: mountedKeys.map((key) => {
253
275
  const gridCols = properties[key]?.options?.grid_columns ?? 12;
254
276
  const gridBreak = !!properties[key]?.options?.grid_break;
255
277
  return /* @__PURE__ */ jsx("div", {
278
+ className: isHiddenField(uiSchema[key]) ? "tw:hidden" : void 0,
256
279
  style: { gridColumn: gridBreak ? "1 / -1" : `span ${Math.min(gridCols, 12)}` },
257
280
  children: /* @__PURE__ */ jsx(SchemaField, {
258
281
  name: key,
@@ -364,8 +387,9 @@ const TableArrayField = ({ schema, uiSchema = {}, formData, onChange, disabled,
364
387
  const properties = itemSchema?.properties ?? {};
365
388
  const itemUiSchema = uiSchema.items ?? {};
366
389
  const SchemaField = getSchemaField(registry);
367
- const sortedKeys = sortByPropertyOrder(properties);
368
- const isPrimitiveItems = sortedKeys.length === 0 && itemSchema != null;
390
+ const allKeys = sortByPropertyOrder(properties);
391
+ const columnKeys = allKeys.filter((key) => !isHiddenField(itemUiSchema[key]));
392
+ const isPrimitiveItems = allKeys.length === 0 && itemSchema != null;
369
393
  const isReadOnly = disabled || readonly;
370
394
  const fieldPath = fieldPathId?.path ?? [];
371
395
  const itemsRef = useRef(items);
@@ -395,7 +419,7 @@ const TableArrayField = ({ schema, uiSchema = {}, formData, onChange, disabled,
395
419
  return;
396
420
  }
397
421
  const newItem = {};
398
- for (const key of sortedKeys) newItem[key] = defaultValueFor(properties[key] ?? {});
422
+ for (const key of allKeys) newItem[key] = defaultValueFor(properties[key] ?? {});
399
423
  onChange([...itemsRef.current, newItem], fieldPath);
400
424
  };
401
425
  const withHiddenLabel = (base) => ({
@@ -411,7 +435,7 @@ const TableArrayField = ({ schema, uiSchema = {}, formData, onChange, disabled,
411
435
  children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [isPrimitiveItems ? /* @__PURE__ */ jsx("th", {
412
436
  className: "tw:border-b tw:border-neutral-200 tw:p-2 tw:text-left tw:text-xs tw:font-medium tw:text-neutral-600",
413
437
  children: itemSchema?.title ?? ""
414
- }) : sortedKeys.map((key) => /* @__PURE__ */ jsx("th", {
438
+ }) : columnKeys.map((key) => /* @__PURE__ */ jsx("th", {
415
439
  className: "tw:border-b tw:border-neutral-200 tw:p-2 tw:text-left tw:text-xs tw:font-medium tw:text-neutral-600",
416
440
  children: properties[key]?.title ?? key
417
441
  }, key)), !isReadOnly && /* @__PURE__ */ jsx("th", { className: "tw:w-20" })] }) }), /* @__PURE__ */ jsx("tbody", { children: items.map((item, rowIndex) => /* @__PURE__ */ jsxs("tr", {
@@ -430,7 +454,7 @@ const TableArrayField = ({ schema, uiSchema = {}, formData, onChange, disabled,
430
454
  disabled: !!disabled,
431
455
  readonly: !!readonly
432
456
  })
433
- }) : sortedKeys.map((key) => /* @__PURE__ */ jsx("td", {
457
+ }) : columnKeys.map((key) => /* @__PURE__ */ jsx("td", {
434
458
  className: "tw:px-2 tw:py-1.5 tw:[&>div]:mb-0",
435
459
  children: /* @__PURE__ */ jsx(SchemaField, {
436
460
  name: key,
@@ -507,13 +531,27 @@ const TabsObjectField = ({ schema, uiSchema = {}, formData, onChange, disabled,
507
531
  [key]: value
508
532
  }, path, errorSchema, id);
509
533
  }, [onChange]);
510
- const sortedKeys = sortByPropertyOrder(properties);
511
- const [activeTab, setActiveTab] = useState(sortedKeys[0] ?? "");
512
- if (sortedKeys.length === 0) return null;
513
- const triggers = sortedKeys.map((key) => ({
534
+ const mountedKeys = sortByPropertyOrder(properties).filter((key) => !isHiddenContainer(uiSchema[key], properties[key]));
535
+ const tabKeys = mountedKeys.filter((key) => !isHiddenField(uiSchema[key]));
536
+ const hiddenLeafKeys = mountedKeys.filter((key) => isHiddenField(uiSchema[key]));
537
+ const [activeTab, setActiveTab] = useState(tabKeys[0] ?? "");
538
+ if (mountedKeys.length === 0) return null;
539
+ const triggers = tabKeys.map((key) => ({
514
540
  value: key,
515
541
  title: properties[key]?.title ?? key
516
542
  }));
543
+ const renderField = (key) => /* @__PURE__ */ jsx(SchemaField, {
544
+ name: key,
545
+ schema: schema.properties[key],
546
+ uiSchema: uiSchema[key] ?? {},
547
+ formData: data[key],
548
+ ...SCHEMA_FIELD_STUBS,
549
+ fieldPathId: childFieldPathId(fieldPathId, key),
550
+ registry,
551
+ onChange: onPropertyChange(key),
552
+ disabled: !!disabled,
553
+ readonly: !!readonly
554
+ }, key);
517
555
  return /* @__PURE__ */ jsxs("div", {
518
556
  className: "tw:flex tw:flex-col tw:gap-4",
519
557
  children: [
@@ -522,27 +560,17 @@ const TabsObjectField = ({ schema, uiSchema = {}, formData, onChange, disabled,
522
560
  children: schema.title
523
561
  }),
524
562
  /* @__PURE__ */ jsx(SchemaDescription, { description: schema.description }),
525
- /* @__PURE__ */ jsx(Tabs, {
563
+ tabKeys.length > 0 && /* @__PURE__ */ jsx(Tabs, {
526
564
  triggers,
527
565
  value: activeTab,
528
566
  onValueChange: setActiveTab,
529
567
  compact: true,
530
- children: sortedKeys.map((key) => /* @__PURE__ */ jsx(TabsContent, {
568
+ children: tabKeys.map((key) => /* @__PURE__ */ jsx(TabsContent, {
531
569
  value: key,
532
- children: /* @__PURE__ */ jsx(SchemaField, {
533
- name: key,
534
- schema: schema.properties[key],
535
- uiSchema: uiSchema[key] ?? {},
536
- formData: data[key],
537
- ...SCHEMA_FIELD_STUBS,
538
- fieldPathId: childFieldPathId(fieldPathId, key),
539
- registry,
540
- onChange: onPropertyChange(key),
541
- disabled: !!disabled,
542
- readonly: !!readonly
543
- })
570
+ children: renderField(key)
544
571
  }, key))
545
- })
572
+ }),
573
+ hiddenLeafKeys.map(renderField)
546
574
  ]
547
575
  });
548
576
  };
@@ -654,9 +682,13 @@ const ErrorListTemplate = ({ errors }) => {
654
682
  };
655
683
  //#endregion
656
684
  //#region src/blocks/RjsfSchemaEditor/RootFormDataContext.ts
657
- const RootFormDataContext = createContext({});
685
+ const RootFormDataContext = createContext({
686
+ data: {},
687
+ context: {}
688
+ });
658
689
  const RootFormDataProvider = RootFormDataContext;
659
- const useRootFormData = () => use(RootFormDataContext);
690
+ const useRootFormData = () => use(RootFormDataContext).data;
691
+ const useRootContext = () => use(RootFormDataContext).context;
660
692
  //#endregion
661
693
  //#region src/blocks/RjsfSchemaEditor/templates/FieldTemplate.tsx
662
694
  /**
@@ -776,16 +808,11 @@ const FieldTemplateWithDependencies = ({ dependencies, keepMounted, ...props })
776
808
  return /* @__PURE__ */ jsx(FieldTemplateBody, { ...props });
777
809
  };
778
810
  const FieldTemplate = (props) => {
779
- if (props.hidden) return /* @__PURE__ */ jsx("div", {
811
+ if (isHiddenField(props.uiSchema)) return /* @__PURE__ */ jsx("div", {
780
812
  className: "tw:hidden",
781
813
  children: props.children
782
814
  });
783
- const uiOptions = props.uiSchema?.["ui:options"];
784
- if (isHiddenTemplateWatch(props.uiSchema)) return /* @__PURE__ */ jsx("div", {
785
- className: "tw:hidden",
786
- children: props.children
787
- });
788
- const dependencies = uiOptions?.dependencies;
815
+ const dependencies = (props.uiSchema?.["ui:options"])?.dependencies;
789
816
  if (dependencies) return /* @__PURE__ */ jsx(FieldTemplateWithDependencies, {
790
817
  dependencies,
791
818
  keepMounted: props.uiSchema?.["ui:widget"] === "template-watch",
@@ -803,22 +830,9 @@ const ObjectFieldTemplate = ({ title, description, properties, formData, uiSchem
803
830
  const disableCollapse = !!uiOptions?.disableCollapse;
804
831
  const isArrayItem = typeof fieldPathId?.path?.at(-1) === "number";
805
832
  const childSchemas = schema.properties;
806
- const isContainerSchema = (s) => {
807
- if (!s) return false;
808
- if (s.properties || s.items) return true;
809
- if (Array.isArray(s.type)) return s.type.includes("object") || s.type.includes("array");
810
- return s.type === "object" || s.type === "array";
811
- };
812
- const visibleProperties = properties.filter((prop) => {
813
- if (uiSchema?.[prop.name]?.["ui:widget"] !== "hidden") return true;
814
- return !isContainerSchema(childSchemas?.[prop.name]);
815
- });
816
- const isHiddenMount = (name) => {
817
- const childUi = uiSchema?.[name];
818
- return childUi?.["ui:widget"] === "hidden" || isHiddenTemplateWatch(childUi);
819
- };
833
+ const visibleProperties = properties.filter((prop) => !isHiddenContainer(uiSchema?.[prop.name], childSchemas?.[prop.name]));
820
834
  const renderChildren = (props) => props.map((prop) => /* @__PURE__ */ jsx("div", {
821
- className: isHiddenMount(prop.name) ? "tw:hidden" : void 0,
835
+ className: isHiddenField(uiSchema?.[prop.name]) ? "tw:hidden" : void 0,
822
836
  children: prop.content
823
837
  }, prop.name));
824
838
  if (isRoot) return /* @__PURE__ */ jsx("div", {
@@ -1029,24 +1043,62 @@ const resolveTemplate = (template, watch, rootFormData) => {
1029
1043
  });
1030
1044
  };
1031
1045
  /**
1046
+ * Whether `rootContext` declares the value a path reads.
1047
+ *
1048
+ * - A context entry shares its top-level key with the form data — a sync action writes its own
1049
+ * keys under the same key — so the entry key alone does not settle it.
1050
+ * - Both the entry and the segment under it must be own properties — plain-object lookups also
1051
+ * answer for `toString` and the rest of the prototype chain.
1052
+ * - A path naming an entry and nothing under it reads the whole namespace, context included.
1053
+ */
1054
+ const declaresPath = (segments, rootContext) => {
1055
+ const [entryKey = "", key] = segments;
1056
+ const entry = rootContext[entryKey];
1057
+ return isRecord(entry) && (key === void 0 || Object.hasOwn(entry, key));
1058
+ };
1059
+ /**
1060
+ * Whether every watched path reads a value `rootContext` declares.
1061
+ *
1062
+ * - No watched paths means nothing is derived, which is not a context view.
1063
+ */
1064
+ const readsOnlyContext = (watch, rootContext) => {
1065
+ const paths = Object.values(watch);
1066
+ return paths.length > 0 && paths.every((path) => {
1067
+ const segments = path.split(".");
1068
+ return declaresPath(segments, rootContext) || declaresPath(segments.slice(1), rootContext);
1069
+ });
1070
+ };
1071
+ /**
1032
1072
  * Widget for json-editor's `template`/`watch` pattern (without `enumSource`).
1033
- * Computes a value from watched form data paths and keeps the field in sync.
1073
+ * Computes a value from watched paths and shows it.
1034
1074
  *
1035
1075
  * - With `options.hidden` it renders nothing — a helper for cross-object dependencies.
1036
1076
  * - Without it, the value is shown in a read-only input; `FieldTemplate` supplies the label.
1077
+ * - It writes the computed value into the form data, so a component reads it back from the
1078
+ * saved configuration.
1079
+ * - It stops writing when every watched path reads `rootContext` — the configuration does not
1080
+ * own that context.
1081
+ * - `options.hidden` fields always write; they exist to feed cross-object dependencies.
1037
1082
  */
1038
1083
  const TemplateWatchWidget = ({ id, value, onChange, disabled, readonly, rawErrors, options: widgetOptions }) => {
1039
1084
  const data = useRootFormData();
1085
+ const rootContext = useRootContext();
1040
1086
  const watch = widgetOptions.watch;
1041
1087
  const template = widgetOptions.template;
1088
+ const isContextView = !widgetOptions.hidden && !!watch && readsOnlyContext(watch, rootContext);
1042
1089
  const computed = watch && template ? resolveTemplate(template, watch, data) : stringify(value);
1043
1090
  const lastSetRef = useRef(stringify(value));
1044
1091
  useEffect(() => {
1092
+ if (isContextView) return;
1045
1093
  if (computed !== lastSetRef.current) {
1046
1094
  lastSetRef.current = computed;
1047
1095
  onChange(computed);
1048
1096
  }
1049
- }, [computed, onChange]);
1097
+ }, [
1098
+ computed,
1099
+ onChange,
1100
+ isContextView
1101
+ ]);
1050
1102
  if (widgetOptions.hidden) return null;
1051
1103
  return /* @__PURE__ */ jsx(TextInput, {
1052
1104
  id,
@@ -1167,7 +1219,8 @@ const generateUiSchema = (schema, readOnly = false, definitions, globalConfig, h
1167
1219
  const type = propSchema.type ?? (propSchema.properties ? "object" : void 0);
1168
1220
  const options = propSchema.options;
1169
1221
  const fieldUi = {};
1170
- if (options?.hidden) fieldUi["ui:widget"] = "hidden";
1222
+ const isHidden = !!options?.hidden;
1223
+ if (isHidden) fieldUi["ui:widget"] = "hidden";
1171
1224
  if (type === "array" && format === "table") fieldUi["ui:field"] = "tableArray";
1172
1225
  if (type === "array" && format === "checkbox") fieldUi["ui:widget"] = "checkboxes";
1173
1226
  if (format === "radio" && propSchema.enum) fieldUi["ui:widget"] = "radio";
@@ -1241,7 +1294,7 @@ const generateUiSchema = (schema, readOnly = false, definitions, globalConfig, h
1241
1294
  ...fieldUi["ui:options"],
1242
1295
  watch: propSchema.watch,
1243
1296
  template: propSchema.template,
1244
- hidden: !!options?.hidden || isContainerType(propSchema)
1297
+ ...isContainerSchema(propSchema) && { hidden: true }
1245
1298
  };
1246
1299
  }
1247
1300
  if (type === "boolean" && options?.enum_titles) fieldUi["ui:widget"] = "select";
@@ -1297,6 +1350,10 @@ const generateUiSchema = (schema, readOnly = false, definitions, globalConfig, h
1297
1350
  if (Object.keys(itemsUi).length > 0) fieldUi.items = itemsUi;
1298
1351
  }
1299
1352
  if ((propSchema.enumSource || propSchema.watch) && !fieldUi["ui:widget"]) console.warn(`[RJSF] Property "${key}" uses enumSource/watch which is not yet supported. It will render as a plain input.`);
1353
+ if (isHidden) fieldUi["ui:options"] = {
1354
+ ...fieldUi["ui:options"],
1355
+ hidden: true
1356
+ };
1300
1357
  if (Object.keys(fieldUi).length > 0) uiSchema[key] = fieldUi;
1301
1358
  }
1302
1359
  const orderedEntries = Object.entries(properties).filter(([, prop]) => prop.propertyOrder !== void 0).sort(([, a], [, b]) => (a.propertyOrder ?? Number.MAX_SAFE_INTEGER) - (b.propertyOrder ?? Number.MAX_SAFE_INTEGER));
@@ -1332,18 +1389,6 @@ const isDynamicSelectSchema = (schema) => {
1332
1389
  const isTemplateWatchSchema = (schema) => {
1333
1390
  return !!(schema.template && schema.watch && !schema.enumSource);
1334
1391
  };
1335
- /**
1336
- * Whether a schema describes an object or an array.
1337
- *
1338
- * - `properties` or `items` imply the type even when json-editor omits it.
1339
- * - `type` may be a union, e.g. `['object', 'null']`.
1340
- */
1341
- const isContainerType = (schema) => {
1342
- if (schema.properties || schema.items) return true;
1343
- const { type } = schema;
1344
- if (Array.isArray(type)) return type.includes("object") || type.includes("array");
1345
- return type === "object" || type === "array";
1346
- };
1347
1392
  const isAsyncSelectSchema = (schema) => {
1348
1393
  return !!(schema.options?.async || schema.options?.creatable);
1349
1394
  };
@@ -1468,7 +1513,7 @@ const stableStringify = (obj) => JSON.stringify(obj, (_key, val) => {
1468
1513
  }
1469
1514
  return val;
1470
1515
  });
1471
- const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalConfig, onRegisterValidate, widgets, fields, renderMarkdown, hasProtectedDefaultBranch = false }) => {
1516
+ const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalConfig, rootContext, onRegisterValidate, widgets, fields, renderMarkdown, hasProtectedDefaultBranch = false }) => {
1472
1517
  const schemaJs = useMemo(() => sanitizeSchema(schema), [schema]);
1473
1518
  const uiSchema = useMemo(() => generateUiSchema(schema, readOnly, void 0, globalConfig ?? void 0, hasProtectedDefaultBranch), [
1474
1519
  schema,
@@ -1564,12 +1609,27 @@ const RjsfSchemaEditor = ({ schema, value, onChange, readOnly, inForm, globalCon
1564
1609
  return formRef.current?.validateForm() ?? true;
1565
1610
  });
1566
1611
  }, [onRegisterValidate, formKey]);
1612
+ const rootFormDataValue = useMemo(() => {
1613
+ const context = rootContext ?? {};
1614
+ const merged = { ...rootFormData };
1615
+ for (const [key, entry] of Object.entries(context)) {
1616
+ const existing = merged[key];
1617
+ merged[key] = isRecord(existing) ? {
1618
+ ...existing,
1619
+ ...entry
1620
+ } : entry;
1621
+ }
1622
+ return {
1623
+ data: merged,
1624
+ context
1625
+ };
1626
+ }, [rootFormData, rootContext]);
1567
1627
  return /* @__PURE__ */ jsx("div", {
1568
1628
  className: "json-editor",
1569
1629
  children: /* @__PURE__ */ jsx(RenderMarkdownProvider, {
1570
1630
  value: renderMarkdown ?? defaultRenderMarkdown,
1571
1631
  children: /* @__PURE__ */ jsx(RootFormDataProvider, {
1572
- value: rootFormData,
1632
+ value: rootFormDataValue,
1573
1633
  children: /* @__PURE__ */ jsx(Form, {
1574
1634
  ref: formRef,
1575
1635
  schema: schemaJs,