@flanksource/clicky-ui 0.3.41 → 0.3.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.cjs +4 -0
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.js +4 -0
- package/dist/ai.js.map +1 -1
- package/dist/comments/CommentCard.cjs +3 -1
- package/dist/comments/CommentCard.cjs.map +1 -1
- package/dist/comments/CommentCard.d.ts.map +1 -1
- package/dist/comments/CommentCard.js +4 -2
- package/dist/comments/CommentCard.js.map +1 -1
- package/dist/comments/CommentCardParts.cjs +16 -0
- package/dist/comments/CommentCardParts.cjs.map +1 -1
- package/dist/comments/CommentCardParts.d.ts +4 -1
- package/dist/comments/CommentCardParts.d.ts.map +1 -1
- package/dist/comments/CommentCardParts.js +16 -0
- package/dist/comments/CommentCardParts.js.map +1 -1
- package/dist/comments/comment-types.cjs.map +1 -1
- package/dist/comments/comment-types.d.ts +4 -0
- package/dist/comments/comment-types.d.ts.map +1 -1
- package/dist/comments/comment-types.js.map +1 -1
- package/dist/components/Combobox.cjs +54 -8
- package/dist/components/Combobox.cjs.map +1 -1
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +56 -10
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/ComboboxMenu.cjs +139 -113
- package/dist/components/ComboboxMenu.cjs.map +1 -1
- package/dist/components/ComboboxMenu.d.ts +3 -1
- package/dist/components/ComboboxMenu.d.ts.map +1 -1
- package/dist/components/ComboboxMenu.js +139 -113
- package/dist/components/ComboboxMenu.js.map +1 -1
- package/dist/components/ComboboxMenuTrigger.cjs +87 -0
- package/dist/components/ComboboxMenuTrigger.cjs.map +1 -0
- package/dist/components/ComboboxMenuTrigger.d.ts +23 -0
- package/dist/components/ComboboxMenuTrigger.d.ts.map +1 -0
- package/dist/components/ComboboxMenuTrigger.js +87 -0
- package/dist/components/ComboboxMenuTrigger.js.map +1 -0
- package/dist/components/JsonSchemaForm.cjs +30 -7
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.d.ts.map +1 -1
- package/dist/components/JsonSchemaForm.js +30 -7
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/SegmentedControl.cjs +20 -3
- package/dist/components/SegmentedControl.cjs.map +1 -1
- package/dist/components/SegmentedControl.d.ts +11 -0
- package/dist/components/SegmentedControl.d.ts.map +1 -1
- package/dist/components/SegmentedControl.js +21 -4
- package/dist/components/SegmentedControl.js.map +1 -1
- package/dist/components/combobox-types.d.ts +8 -0
- package/dist/components/combobox-types.d.ts.map +1 -1
- package/dist/components/json-schema-form-debug-badge.cjs +108 -0
- package/dist/components/json-schema-form-debug-badge.cjs.map +1 -0
- package/dist/components/json-schema-form-debug-badge.d.ts +10 -0
- package/dist/components/json-schema-form-debug-badge.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug-badge.js +108 -0
- package/dist/components/json-schema-form-debug-badge.js.map +1 -0
- package/dist/components/json-schema-form-debug-glyph-map.cjs +129 -0
- package/dist/components/json-schema-form-debug-glyph-map.cjs.map +1 -0
- package/dist/components/json-schema-form-debug-glyph-map.d.ts +20 -0
- package/dist/components/json-schema-form-debug-glyph-map.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug-glyph-map.js +129 -0
- package/dist/components/json-schema-form-debug-glyph-map.js.map +1 -0
- package/dist/components/json-schema-form-debug-glyph.cjs +13 -0
- package/dist/components/json-schema-form-debug-glyph.cjs.map +1 -0
- package/dist/components/json-schema-form-debug-glyph.d.ts +6 -0
- package/dist/components/json-schema-form-debug-glyph.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug-glyph.js +13 -0
- package/dist/components/json-schema-form-debug-glyph.js.map +1 -0
- package/dist/components/json-schema-form-debug-groups.cjs +56 -0
- package/dist/components/json-schema-form-debug-groups.cjs.map +1 -0
- package/dist/components/json-schema-form-debug-groups.d.ts +8 -0
- package/dist/components/json-schema-form-debug-groups.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug-groups.js +56 -0
- package/dist/components/json-schema-form-debug-groups.js.map +1 -0
- package/dist/components/json-schema-form-debug-keywords.cjs +159 -0
- package/dist/components/json-schema-form-debug-keywords.cjs.map +1 -0
- package/dist/components/json-schema-form-debug-keywords.d.ts +6 -0
- package/dist/components/json-schema-form-debug-keywords.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug-keywords.js +159 -0
- package/dist/components/json-schema-form-debug-keywords.js.map +1 -0
- package/dist/components/json-schema-form-debug-listeners.cjs +102 -0
- package/dist/components/json-schema-form-debug-listeners.cjs.map +1 -0
- package/dist/components/json-schema-form-debug-listeners.d.ts +6 -0
- package/dist/components/json-schema-form-debug-listeners.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug-listeners.js +102 -0
- package/dist/components/json-schema-form-debug-listeners.js.map +1 -0
- package/dist/components/json-schema-form-debug.cjs +31 -0
- package/dist/components/json-schema-form-debug.cjs.map +1 -0
- package/dist/components/json-schema-form-debug.d.ts +11 -0
- package/dist/components/json-schema-form-debug.d.ts.map +1 -0
- package/dist/components/json-schema-form-debug.js +31 -0
- package/dist/components/json-schema-form-debug.js.map +1 -0
- package/dist/components/json-schema-form-enum-choice.cjs +114 -0
- package/dist/components/json-schema-form-enum-choice.cjs.map +1 -0
- package/dist/components/json-schema-form-enum-choice.d.ts +14 -0
- package/dist/components/json-schema-form-enum-choice.d.ts.map +1 -0
- package/dist/components/json-schema-form-enum-choice.js +114 -0
- package/dist/components/json-schema-form-enum-choice.js.map +1 -0
- package/dist/components/json-schema-form-fields.cjs +3 -93
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +1 -91
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-listeners.cjs +7 -1
- package/dist/components/json-schema-form-listeners.cjs.map +1 -1
- package/dist/components/json-schema-form-listeners.d.ts.map +1 -1
- package/dist/components/json-schema-form-listeners.js +7 -1
- package/dist/components/json-schema-form-listeners.js.map +1 -1
- package/dist/components/json-schema-form-preferences.cjs +1 -0
- package/dist/components/json-schema-form-preferences.cjs.map +1 -1
- package/dist/components/json-schema-form-preferences.d.ts +1 -0
- package/dist/components/json-schema-form-preferences.d.ts.map +1 -1
- package/dist/components/json-schema-form-preferences.js +1 -0
- package/dist/components/json-schema-form-preferences.js.map +1 -1
- package/dist/components/json-schema-form-render.cjs +21 -5
- package/dist/components/json-schema-form-render.cjs.map +1 -1
- package/dist/components/json-schema-form-render.d.ts.map +1 -1
- package/dist/components/json-schema-form-render.js +21 -5
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-runtime-types.d.ts +1 -0
- package/dist/components/json-schema-form-runtime-types.d.ts.map +1 -1
- package/dist/components/json-schema-form-tone.cjs +12 -0
- package/dist/components/json-schema-form-tone.cjs.map +1 -1
- package/dist/components/json-schema-form-tone.js +12 -0
- package/dist/components/json-schema-form-tone.js.map +1 -1
- package/dist/components/json-schema-form-types.d.ts +1 -0
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/data/GraphDiagram.cjs +125 -138
- package/dist/data/GraphDiagram.cjs.map +1 -1
- package/dist/data/GraphDiagram.d.ts +30 -23
- package/dist/data/GraphDiagram.d.ts.map +1 -1
- package/dist/data/GraphDiagram.js +128 -141
- package/dist/data/GraphDiagram.js.map +1 -1
- package/dist/data/GraphDiagramEdges.cjs +208 -0
- package/dist/data/GraphDiagramEdges.cjs.map +1 -0
- package/dist/data/GraphDiagramEdges.d.ts +40 -0
- package/dist/data/GraphDiagramEdges.d.ts.map +1 -0
- package/dist/data/GraphDiagramEdges.js +208 -0
- package/dist/data/GraphDiagramEdges.js.map +1 -0
- package/dist/data/GraphDiagramNodes.cjs +142 -0
- package/dist/data/GraphDiagramNodes.cjs.map +1 -0
- package/dist/data/GraphDiagramNodes.d.ts +22 -0
- package/dist/data/GraphDiagramNodes.d.ts.map +1 -0
- package/dist/data/GraphDiagramNodes.js +142 -0
- package/dist/data/GraphDiagramNodes.js.map +1 -0
- package/dist/data/ai/PromptRunEditor/RuntimeRows.cjs +8 -3
- package/dist/data/ai/PromptRunEditor/RuntimeRows.cjs.map +1 -1
- package/dist/data/ai/PromptRunEditor/RuntimeRows.d.ts.map +1 -1
- package/dist/data/ai/PromptRunEditor/RuntimeRows.js +8 -3
- package/dist/data/ai/PromptRunEditor/RuntimeRows.js.map +1 -1
- package/dist/data/ai/PromptRunEditor/index.cjs +37 -43
- package/dist/data/ai/PromptRunEditor/index.cjs.map +1 -1
- package/dist/data/ai/PromptRunEditor/index.d.ts +3 -1
- package/dist/data/ai/PromptRunEditor/index.d.ts.map +1 -1
- package/dist/data/ai/PromptRunEditor/index.js +38 -44
- package/dist/data/ai/PromptRunEditor/index.js.map +1 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.cjs +16 -5
- package/dist/data/ai/PromptRunEditor/runtimeActions.cjs.map +1 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts +4 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts.map +1 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.js +17 -6
- package/dist/data/ai/PromptRunEditor/runtimeActions.js.map +1 -1
- package/dist/data/ai/SessionInspector.approvals-model.cjs +12 -0
- package/dist/data/ai/SessionInspector.approvals-model.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.approvals-model.d.ts +11 -2
- package/dist/data/ai/SessionInspector.approvals-model.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.approvals-model.js +12 -0
- package/dist/data/ai/SessionInspector.approvals-model.js.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.cjs +25 -1
- package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.js +26 -2
- package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
- package/dist/data/ai/SessionInspector.summary.cjs +9 -3
- package/dist/data/ai/SessionInspector.summary.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.summary.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.summary.js +9 -3
- package/dist/data/ai/SessionInspector.summary.js.map +1 -1
- package/dist/data/ai/SessionInspector.transcript.cjs +4 -0
- package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.transcript.js +4 -0
- package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
- package/dist/data/ai/SessionViewer.approval-body.cjs +146 -0
- package/dist/data/ai/SessionViewer.approval-body.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.approval-body.d.ts +11 -0
- package/dist/data/ai/SessionViewer.approval-body.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.approval-body.js +146 -0
- package/dist/data/ai/SessionViewer.approval-body.js.map +1 -0
- package/dist/data/ai/SessionViewer.approval-forms.cjs +150 -0
- package/dist/data/ai/SessionViewer.approval-forms.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.approval-forms.d.ts +23 -0
- package/dist/data/ai/SessionViewer.approval-forms.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.approval-forms.js +150 -0
- package/dist/data/ai/SessionViewer.approval-forms.js.map +1 -0
- package/dist/data/ai/SessionViewer.cjs +57 -20
- package/dist/data/ai/SessionViewer.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.d.ts +13 -3
- package/dist/data/ai/SessionViewer.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.decision-controls.cjs +313 -0
- package/dist/data/ai/SessionViewer.decision-controls.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.decision-controls.d.ts +43 -0
- package/dist/data/ai/SessionViewer.decision-controls.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.decision-controls.js +313 -0
- package/dist/data/ai/SessionViewer.decision-controls.js.map +1 -0
- package/dist/data/ai/SessionViewer.decision.cjs +21 -0
- package/dist/data/ai/SessionViewer.decision.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.decision.d.ts +12 -0
- package/dist/data/ai/SessionViewer.decision.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.decision.js +21 -0
- package/dist/data/ai/SessionViewer.decision.js.map +1 -0
- package/dist/data/ai/SessionViewer.input.cjs +14 -0
- package/dist/data/ai/SessionViewer.input.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.input.d.ts +5 -0
- package/dist/data/ai/SessionViewer.input.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.input.js +14 -0
- package/dist/data/ai/SessionViewer.input.js.map +1 -1
- package/dist/data/ai/SessionViewer.js +58 -21
- package/dist/data/ai/SessionViewer.js.map +1 -1
- package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.model.d.ts +4 -0
- package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.model.js.map +1 -1
- package/dist/data/ai/SessionViewer.rows.cjs +6 -3
- package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.rows.d.ts +2 -1
- package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.rows.js +6 -3
- package/dist/data/ai/SessionViewer.rows.js.map +1 -1
- package/dist/data/ai/SessionViewer.tool-row.cjs +29 -237
- package/dist/data/ai/SessionViewer.tool-row.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.tool-row.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.tool-row.js +27 -235
- package/dist/data/ai/SessionViewer.tool-row.js.map +1 -1
- package/dist/data/ai/SessionViewer.unified.d.ts +4 -0
- package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
- package/dist/data/ai/SessionViewerMenu.cjs +8 -2
- package/dist/data/ai/SessionViewerMenu.cjs.map +1 -1
- package/dist/data/ai/SessionViewerMenu.d.ts +4 -1
- package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -1
- package/dist/data/ai/SessionViewerMenu.js +8 -2
- package/dist/data/ai/SessionViewerMenu.js.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/CommitSection.cjs +28 -17
- package/dist/data/ai/SpecRuntimeEditor/CommitSection.cjs.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/CommitSection.d.ts +10 -2
- package/dist/data/ai/SpecRuntimeEditor/CommitSection.d.ts.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/CommitSection.js +29 -18
- package/dist/data/ai/SpecRuntimeEditor/CommitSection.js.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/index.cjs +9 -1
- package/dist/data/ai/SpecRuntimeEditor/index.cjs.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/index.d.ts +9 -2
- package/dist/data/ai/SpecRuntimeEditor/index.d.ts.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/index.js +9 -1
- package/dist/data/ai/SpecRuntimeEditor/index.js.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/permission-mode-visuals.cjs +1 -1
- package/dist/data/ai/SpecRuntimeEditor/permission-mode-visuals.js +1 -1
- package/dist/data/ai/SpecRuntimeEditor/summaries.cjs.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/summaries.d.ts +8 -2
- package/dist/data/ai/SpecRuntimeEditor/summaries.d.ts.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/summaries.js.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/update.cjs +14 -6
- package/dist/data/ai/SpecRuntimeEditor/update.cjs.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/update.d.ts +1 -0
- package/dist/data/ai/SpecRuntimeEditor/update.d.ts.map +1 -1
- package/dist/data/ai/SpecRuntimeEditor/update.js +14 -6
- package/dist/data/ai/SpecRuntimeEditor/update.js.map +1 -1
- package/dist/data/ai/approval-request.cjs +75 -0
- package/dist/data/ai/approval-request.cjs.map +1 -0
- package/dist/data/ai/approval-request.d.ts +155 -0
- package/dist/data/ai/approval-request.d.ts.map +1 -0
- package/dist/data/ai/approval-request.js +75 -0
- package/dist/data/ai/approval-request.js.map +1 -0
- package/dist/data/ai/index.d.ts +3 -0
- package/dist/data/ai/index.d.ts.map +1 -1
- package/dist/data/ai/runtime-preset-menu/SavePresetDialog.cjs +125 -0
- package/dist/data/ai/runtime-preset-menu/SavePresetDialog.cjs.map +1 -0
- package/dist/data/ai/runtime-preset-menu/SavePresetDialog.d.ts +11 -0
- package/dist/data/ai/runtime-preset-menu/SavePresetDialog.d.ts.map +1 -0
- package/dist/data/ai/runtime-preset-menu/SavePresetDialog.js +125 -0
- package/dist/data/ai/runtime-preset-menu/SavePresetDialog.js.map +1 -0
- package/dist/data/ai/runtime-preset-menu/index.d.ts +3 -0
- package/dist/data/ai/runtime-preset-menu/index.d.ts.map +1 -0
- package/dist/data/ai/runtime-preset-menu/model.cjs +73 -0
- package/dist/data/ai/runtime-preset-menu/model.cjs.map +1 -0
- package/dist/data/ai/runtime-preset-menu/model.d.ts +13 -0
- package/dist/data/ai/runtime-preset-menu/model.d.ts.map +1 -0
- package/dist/data/ai/runtime-preset-menu/model.js +73 -0
- package/dist/data/ai/runtime-preset-menu/model.js.map +1 -0
- package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.cjs +149 -0
- package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.cjs.map +1 -0
- package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.d.ts +15 -0
- package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.d.ts.map +1 -0
- package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.js +149 -0
- package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.js.map +1 -0
- package/dist/data/ai/runtime-spec-fields.cjs +166 -0
- package/dist/data/ai/runtime-spec-fields.cjs.map +1 -0
- package/dist/data/ai/runtime-spec-fields.d.ts +13 -0
- package/dist/data/ai/runtime-spec-fields.d.ts.map +1 -0
- package/dist/data/ai/runtime-spec-fields.js +166 -0
- package/dist/data/ai/runtime-spec-fields.js.map +1 -0
- package/dist/data/ai/session-categories.cjs +4 -0
- package/dist/data/ai/session-categories.cjs.map +1 -1
- package/dist/data/ai/session-categories.d.ts +1 -0
- package/dist/data/ai/session-categories.d.ts.map +1 -1
- package/dist/data/ai/session-categories.js +4 -0
- package/dist/data/ai/session-categories.js.map +1 -1
- package/dist/data/ai/use-session-scroll.cjs +49 -21
- package/dist/data/ai/use-session-scroll.cjs.map +1 -1
- package/dist/data/ai/use-session-scroll.d.ts +2 -0
- package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
- package/dist/data/ai/use-session-scroll.js +49 -21
- package/dist/data/ai/use-session-scroll.js.map +1 -1
- package/dist/data/chat/Chat.runtime.cjs +1 -1
- package/dist/data/chat/Chat.runtime.cjs.map +1 -1
- package/dist/data/chat/Chat.runtime.d.ts.map +1 -1
- package/dist/data/chat/Chat.runtime.js +1 -1
- package/dist/data/chat/Chat.runtime.js.map +1 -1
- package/dist/data/graph-columns-layout.cjs +216 -0
- package/dist/data/graph-columns-layout.cjs.map +1 -0
- package/dist/data/graph-columns-layout.d.ts +56 -0
- package/dist/data/graph-columns-layout.d.ts.map +1 -0
- package/dist/data/graph-columns-layout.js +216 -0
- package/dist/data/graph-columns-layout.js.map +1 -0
- package/dist/data/graph-diagram-model.cjs +73 -0
- package/dist/data/graph-diagram-model.cjs.map +1 -0
- package/dist/data/graph-diagram-model.d.ts +90 -0
- package/dist/data/graph-diagram-model.d.ts.map +1 -0
- package/dist/data/graph-diagram-model.js +73 -0
- package/dist/data/graph-diagram-model.js.map +1 -0
- package/dist/data/graph-edge-routing.cjs +235 -0
- package/dist/data/graph-edge-routing.cjs.map +1 -0
- package/dist/data/graph-edge-routing.d.ts +73 -0
- package/dist/data/graph-edge-routing.d.ts.map +1 -0
- package/dist/data/graph-edge-routing.js +235 -0
- package/dist/data/graph-edge-routing.js.map +1 -0
- package/dist/data/graph-layout.cjs +0 -82
- package/dist/data/graph-layout.cjs.map +1 -1
- package/dist/data/graph-layout.d.ts +1 -28
- package/dist/data/graph-layout.d.ts.map +1 -1
- package/dist/data/graph-layout.js +1 -83
- package/dist/data/graph-layout.js.map +1 -1
- package/dist/data/har/HarPanel.cjs +129 -33
- package/dist/data/har/HarPanel.cjs.map +1 -1
- package/dist/data/har/HarPanel.d.ts +13 -1
- package/dist/data/har/HarPanel.d.ts.map +1 -1
- package/dist/data/har/HarPanel.js +130 -34
- package/dist/data/har/HarPanel.js.map +1 -1
- package/dist/data/har/fixtures.d.ts +12 -0
- package/dist/data/har/fixtures.d.ts.map +1 -1
- package/dist/data/har/types.d.ts +12 -0
- package/dist/data/har/types.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBar.cjs +67 -84
- package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBar.d.ts +4 -5
- package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBar.fields.cjs +170 -0
- package/dist/data/runtime/RuntimeBar.fields.cjs.map +1 -0
- package/dist/data/runtime/RuntimeBar.fields.d.ts +16 -0
- package/dist/data/runtime/RuntimeBar.fields.d.ts.map +1 -0
- package/dist/data/runtime/RuntimeBar.fields.js +170 -0
- package/dist/data/runtime/RuntimeBar.fields.js.map +1 -0
- package/dist/data/runtime/RuntimeBar.js +70 -87
- package/dist/data/runtime/RuntimeBar.js.map +1 -1
- package/dist/data/runtime/RuntimeBar.selection.cjs +56 -0
- package/dist/data/runtime/RuntimeBar.selection.cjs.map +1 -0
- package/dist/data/runtime/RuntimeBar.selection.d.ts +20 -0
- package/dist/data/runtime/RuntimeBar.selection.d.ts.map +1 -0
- package/dist/data/runtime/RuntimeBar.selection.js +56 -0
- package/dist/data/runtime/RuntimeBar.selection.js.map +1 -0
- package/dist/data/runtime/RuntimeBarActions.cjs +10 -6
- package/dist/data/runtime/RuntimeBarActions.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBarActions.d.ts +8 -1
- package/dist/data/runtime/RuntimeBarActions.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBarActions.js +10 -6
- package/dist/data/runtime/RuntimeBarActions.js.map +1 -1
- package/dist/data/runtime/RuntimeBarIdentity.cjs +166 -0
- package/dist/data/runtime/RuntimeBarIdentity.cjs.map +1 -0
- package/dist/data/runtime/RuntimeBarIdentity.d.ts +25 -0
- package/dist/data/runtime/RuntimeBarIdentity.d.ts.map +1 -0
- package/dist/data/runtime/RuntimeBarIdentity.js +166 -0
- package/dist/data/runtime/RuntimeBarIdentity.js.map +1 -0
- package/dist/data/runtime/RuntimeBarLayout.cjs +95 -0
- package/dist/data/runtime/RuntimeBarLayout.cjs.map +1 -0
- package/dist/data/runtime/RuntimeBarLayout.d.ts +9 -0
- package/dist/data/runtime/RuntimeBarLayout.d.ts.map +1 -0
- package/dist/data/runtime/RuntimeBarLayout.js +95 -0
- package/dist/data/runtime/RuntimeBarLayout.js.map +1 -0
- package/dist/data/runtime/RuntimeBarSegment.cjs +25 -14
- package/dist/data/runtime/RuntimeBarSegment.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBarSegment.d.ts +4 -0
- package/dist/data/runtime/RuntimeBarSegment.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBarSegment.js +25 -14
- package/dist/data/runtime/RuntimeBarSegment.js.map +1 -1
- package/dist/data/runtime/RuntimeLimitInput.cjs +41 -0
- package/dist/data/runtime/RuntimeLimitInput.cjs.map +1 -0
- package/dist/data/runtime/RuntimeLimitInput.d.ts +9 -0
- package/dist/data/runtime/RuntimeLimitInput.d.ts.map +1 -0
- package/dist/data/runtime/RuntimeLimitInput.js +41 -0
- package/dist/data/runtime/RuntimeLimitInput.js.map +1 -0
- package/dist/data/runtime/use-runtime-bar-overflow.cjs +70 -0
- package/dist/data/runtime/use-runtime-bar-overflow.cjs.map +1 -0
- package/dist/data/runtime/use-runtime-bar-overflow.d.ts +13 -0
- package/dist/data/runtime/use-runtime-bar-overflow.d.ts.map +1 -0
- package/dist/data/runtime/use-runtime-bar-overflow.js +70 -0
- package/dist/data/runtime/use-runtime-bar-overflow.js.map +1 -0
- package/dist/data/use-edge-focus.cjs +20 -0
- package/dist/data/use-edge-focus.cjs.map +1 -0
- package/dist/data/use-edge-focus.d.ts +23 -0
- package/dist/data/use-edge-focus.d.ts.map +1 -0
- package/dist/data/use-edge-focus.js +20 -0
- package/dist/data/use-edge-focus.js.map +1 -0
- package/dist/data/use-pan-zoom.cjs +159 -0
- package/dist/data/use-pan-zoom.cjs.map +1 -0
- package/dist/data/use-pan-zoom.d.ts +79 -0
- package/dist/data/use-pan-zoom.d.ts.map +1 -0
- package/dist/data/use-pan-zoom.js +159 -0
- package/dist/data/use-pan-zoom.js.map +1 -0
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +5 -1
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +4 -3
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +6 -2
- package/dist/data.js.map +1 -1
- package/dist/index.cjs +5 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/overlay/DropdownMenu.cjs +1 -0
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts +4 -0
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js +1 -0
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/overlay/DropdownMenuSubmenu.cjs +31 -15
- package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenuSubmenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenuSubmenu.js +31 -15
- package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
- package/dist/rpc/OperationCatalog.cjs +3 -1
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts +3 -1
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +3 -1
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/useOperationPages.cjs +6 -1
- package/dist/rpc/useOperationPages.cjs.map +1 -1
- package/dist/rpc/useOperationPages.d.ts +3 -1
- package/dist/rpc/useOperationPages.d.ts.map +1 -1
- package/dist/rpc/useOperationPages.js +6 -1
- package/dist/rpc/useOperationPages.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/schemas/json-schema-form.schema.json +5 -0
- package/dist/data/runtime/RuntimeBarCombo.cjs +0 -423
- package/dist/data/runtime/RuntimeBarCombo.cjs.map +0 -1
- package/dist/data/runtime/RuntimeBarCombo.d.ts +0 -33
- package/dist/data/runtime/RuntimeBarCombo.d.ts.map +0 -1
- package/dist/data/runtime/RuntimeBarCombo.js +0 -423
- package/dist/data/runtime/RuntimeBarCombo.js.map +0 -1
- package/dist/data/runtime/RuntimeBarLimits.cjs +0 -262
- package/dist/data/runtime/RuntimeBarLimits.cjs.map +0 -1
- package/dist/data/runtime/RuntimeBarLimits.d.ts +0 -17
- package/dist/data/runtime/RuntimeBarLimits.d.ts.map +0 -1
- package/dist/data/runtime/RuntimeBarLimits.js +0 -262
- package/dist/data/runtime/RuntimeBarLimits.js.map +0 -1
- package/dist/data/runtime/RuntimeBarSegments.cjs +0 -346
- package/dist/data/runtime/RuntimeBarSegments.cjs.map +0 -1
- package/dist/data/runtime/RuntimeBarSegments.d.ts +0 -37
- package/dist/data/runtime/RuntimeBarSegments.d.ts.map +0 -1
- package/dist/data/runtime/RuntimeBarSegments.js +0 -346
- package/dist/data/runtime/RuntimeBarSegments.js.map +0 -1
|
@@ -4,7 +4,7 @@ import { cn } from "../lib/utils.js";
|
|
|
4
4
|
import { formatDateTimeRelative } from "../data/cells/timestamp-format.js";
|
|
5
5
|
import { Combobox } from "./Combobox.js";
|
|
6
6
|
import { DateField } from "./DateField.js";
|
|
7
|
-
import {
|
|
7
|
+
import { RadioGroupControl, SegmentedEnumControl } from "./json-schema-form-enum-choice.js";
|
|
8
8
|
import { GridControl } from "./json-schema-form-grid.js";
|
|
9
9
|
import { LookupTreeControl } from "./json-schema-form-lookup-tree.js";
|
|
10
10
|
import { TagsComboboxControl } from "./json-schema-form-tags-combobox.js";
|
|
@@ -256,44 +256,6 @@ function EnumControl({
|
|
|
256
256
|
}
|
|
257
257
|
);
|
|
258
258
|
}
|
|
259
|
-
const SEGMENTED_SIZE = {
|
|
260
|
-
xs: "sm",
|
|
261
|
-
sm: "sm",
|
|
262
|
-
md: "md",
|
|
263
|
-
lg: "lg",
|
|
264
|
-
xl: "lg"
|
|
265
|
-
};
|
|
266
|
-
function SegmentedEnumControl({
|
|
267
|
-
field,
|
|
268
|
-
fieldId,
|
|
269
|
-
readOnly,
|
|
270
|
-
options,
|
|
271
|
-
value,
|
|
272
|
-
size
|
|
273
|
-
}) {
|
|
274
|
-
const hasDescription = options.some((opt) => opt.description);
|
|
275
|
-
const segSize = hasDescription ? "lg" : SEGMENTED_SIZE[size];
|
|
276
|
-
return /* @__PURE__ */ jsx("div", { id: fieldId, "data-jsf-input": true, className: cn(field.inputClassName), children: /* @__PURE__ */ jsx(
|
|
277
|
-
SegmentedControl,
|
|
278
|
-
{
|
|
279
|
-
"aria-label": field.label,
|
|
280
|
-
value,
|
|
281
|
-
onChange: (next) => field.onChange(next),
|
|
282
|
-
size: segSize,
|
|
283
|
-
wrap: true,
|
|
284
|
-
options: options.map((opt) => ({
|
|
285
|
-
id: opt.value,
|
|
286
|
-
label: opt.label,
|
|
287
|
-
// x-enum-icons resolves to a runtime name string; SegmentedControl
|
|
288
|
-
// renders that via <Icon name>. Non-string (pre-extension) icons are
|
|
289
|
-
// dropped here since the segmented option type only takes name/component.
|
|
290
|
-
...typeof opt.icon === "string" ? { icon: opt.icon } : {},
|
|
291
|
-
...opt.description ? { description: opt.description } : {},
|
|
292
|
-
...readOnly ? { disabled: true } : {}
|
|
293
|
-
}))
|
|
294
|
-
}
|
|
295
|
-
) });
|
|
296
|
-
}
|
|
297
259
|
function LookupControl({
|
|
298
260
|
field,
|
|
299
261
|
fieldId,
|
|
@@ -383,58 +345,6 @@ function LookupControl({
|
|
|
383
345
|
}
|
|
384
346
|
);
|
|
385
347
|
}
|
|
386
|
-
function RadioGroupControl({
|
|
387
|
-
field,
|
|
388
|
-
fieldId,
|
|
389
|
-
readOnly,
|
|
390
|
-
options,
|
|
391
|
-
value,
|
|
392
|
-
size
|
|
393
|
-
}) {
|
|
394
|
-
return /* @__PURE__ */ jsx(
|
|
395
|
-
"div",
|
|
396
|
-
{
|
|
397
|
-
role: "radiogroup",
|
|
398
|
-
"aria-label": field.label,
|
|
399
|
-
id: fieldId,
|
|
400
|
-
"data-jsf-input": true,
|
|
401
|
-
className: cn(
|
|
402
|
-
"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5",
|
|
403
|
-
field.inputClassName
|
|
404
|
-
),
|
|
405
|
-
children: options.map((opt) => {
|
|
406
|
-
const checked = opt.value === value;
|
|
407
|
-
return /* @__PURE__ */ jsxs(
|
|
408
|
-
"label",
|
|
409
|
-
{
|
|
410
|
-
className: cn(
|
|
411
|
-
"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1",
|
|
412
|
-
labelSizeClass[size],
|
|
413
|
-
checked ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
414
|
-
readOnly && "cursor-not-allowed opacity-60"
|
|
415
|
-
),
|
|
416
|
-
children: [
|
|
417
|
-
/* @__PURE__ */ jsx(
|
|
418
|
-
"input",
|
|
419
|
-
{
|
|
420
|
-
type: "radio",
|
|
421
|
-
name: fieldId,
|
|
422
|
-
className: "sr-only",
|
|
423
|
-
value: opt.value,
|
|
424
|
-
checked,
|
|
425
|
-
disabled: readOnly,
|
|
426
|
-
onChange: () => field.onChange(opt.value)
|
|
427
|
-
}
|
|
428
|
-
),
|
|
429
|
-
opt.label
|
|
430
|
-
]
|
|
431
|
-
},
|
|
432
|
-
opt.value
|
|
433
|
-
);
|
|
434
|
-
})
|
|
435
|
-
}
|
|
436
|
-
);
|
|
437
|
-
}
|
|
438
348
|
function TextareaControl({
|
|
439
349
|
field,
|
|
440
350
|
fieldId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-fields.js","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { formatDateTimeRelative } from \"../data/cells/timestamp-format\";\nimport { Combobox } from \"./Combobox\";\nimport { DateField } from \"./DateField\";\nimport { SegmentedControl, type SegmentedSize } from \"./SegmentedControl\";\nimport { GridControl } from \"./json-schema-form-grid\";\nimport { LookupTreeControl } from \"./json-schema-form-lookup-tree\";\nimport { TagsComboboxControl } from \"./json-schema-form-tags-combobox\";\nimport { resolveLookupScope, useLookupFetcher } from \"./form-lookup-context\";\nimport type { FieldControl, FieldOption } from \"./json-schema-form-types\";\nimport {\n comboboxAriaProps,\n defaultPlaceholder,\n fieldAriaProps,\n inputClass,\n toText,\n withSyntheticValue,\n} from \"./json-schema-form-utils\";\nimport {\n controlHeightClass,\n labelSizeClass,\n type FormSize,\n} from \"./json-schema-form-size\";\n\nconst LazyMdxEditorField = lazy(async () => {\n const mod = await import(\"./MdxEditorField\");\n return { default: mod.MdxEditorField };\n});\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nexport function ReadOnlyValue({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const secret = field.schema.format === \"password\";\n const display = secret && text ? \"••••••••\" : field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={secret ? undefined : text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\n// FieldAdornmentWrapper positions a field's leading/trailing in-field adornments\n// (FieldControl.prefix at the left edge, FieldControl.suffix at the right). The\n// container is tagged data-jsf-control so an adornment can locate its sibling\n// input[data-jsf-input] (e.g. for caret-aware insertion). With neither adornment\n// it renders the input bare, so unadorned fields are byte-for-byte unchanged.\nfunction FieldAdornmentWrapper({\n prefix,\n suffix,\n children,\n}: {\n prefix?: ReactNode;\n suffix?: ReactNode;\n children: ReactNode;\n}) {\n if (!prefix && !suffix) return <>{children}</>;\n return (\n <div data-jsf-control className=\"relative\">\n {prefix && <div className=\"absolute inset-y-0 left-1.5 flex items-center\">{prefix}</div>}\n {children}\n {suffix && <div className=\"absolute inset-y-0 right-1.5 flex items-center\">{suffix}</div>}\n </div>\n );\n}\n\nexport function StringControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <input\n id={fieldId}\n // format:\"password\" masks secret material (API keys, client secrets);\n // autoComplete new-password stops browsers from offering saved logins.\n type={field.schema.format === \"password\" ? \"password\" : \"text\"}\n autoComplete={field.schema.format === \"password\" ? \"new-password\" : undefined}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n className={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix && \"pr-8\", field.inputClassName)}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function NumberControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // A bounded number can opt into a single-thumb progress slider.\n if (field.schema[\"x-number-display\"] === \"slider\" && typeof field.schema.maximum === \"number\") {\n return <NumberSliderControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n // Default type=\"text\" (not number) so non-numeric values a consumer permits —\n // e.g. template tokens — are not silently dropped by the browser. A schema that\n // declares `multipleOf` opts into a real `<input type=\"number\">` (native step,\n // spin buttons, min/max), matching a hand-built numeric field.\n const coerce = field.coerceNumber !== false;\n const step = typeof field.schema.multipleOf === \"number\" ? field.schema.multipleOf : undefined;\n const native = step !== undefined && !(field.allowCustomValue && typeof field.value === \"string\" && field.value.includes(\"{{\"));\n // A static unit (e.g. \"%\") rides the right edge of the input as a display-only\n // suffix; a consumer-set `suffix` (e.g. an insert-snippet button) wins if both\n // are present (number insert triggers mount on the left as `prefix`).\n const suffix = field.suffix ?? (field.unit ? (\n <span className=\"pointer-events-none select-none text-muted-foreground\">{field.unit}</span>\n ) : undefined);\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={suffix}>\n <input\n id={fieldId}\n type={native ? \"number\" : \"text\"}\n inputMode=\"decimal\"\n {...(native\n ? {\n step,\n ...(typeof field.schema.minimum === \"number\" ? { min: field.schema.minimum } : {}),\n ...(typeof field.schema.maximum === \"number\" ? { max: field.schema.maximum } : {}),\n }\n : {})}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n className={cn(inputClass(size), field.prefix && \"pl-8\", suffix && \"pr-8\", field.inputClassName)}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n // Coerce mid-typing ONLY when the parse round-trips to the same text\n // (e.g. \"100\", \"33.5\") — so an in-progress decimal like \"33.\" or a\n // trailing-zero \"33.30\" keeps its raw text instead of collapsing to a\n // number and stranding the caret. Non-numeric tokens fall through to\n // the raw string. Blur finalizes any still-uncoerced numeric text.\n if (coerce && raw.trim() !== \"\" && String(Number(raw)) === raw.trim()) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n onBlur={(e) => {\n const raw = e.target.value;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n }\n }}\n />\n </FieldAdornmentWrapper>\n );\n}\n\n// A single-thumb range input styled with a progress-filled track. The input sits\n// above the track/fill divs; only its thumb is painted.\nconst SLIDER_INPUT_CLASS =\n \"absolute inset-0 h-6 w-full cursor-pointer appearance-none bg-transparent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-transparent [&::-webkit-slider-thumb]:size-3.5 [&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-background/80 [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-transparent [&::-moz-range-thumb]:size-3.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow-sm\";\n\n// NumberSliderControl renders a bounded number (`x-number-display: \"slider\"`) as\n// a single-thumb slider whose fill grows with the value, with the live value\n// shown to the right.\nexport function NumberSliderControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const min = typeof field.schema.minimum === \"number\" ? field.schema.minimum : 0;\n const max = typeof field.schema.maximum === \"number\" ? field.schema.maximum : 100;\n const step = typeof field.schema.multipleOf === \"number\" ? field.schema.multipleOf : 1;\n const raw = typeof field.value === \"number\" ? field.value : Number(toText(field.value));\n const hasValue = Number.isFinite(raw);\n const value = hasValue ? Math.min(max, Math.max(min, raw)) : min;\n const percent = max > min ? ((value - min) / (max - min)) * 100 : 0;\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"relative h-6 min-w-0 flex-1\">\n <div className=\"absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border\" />\n <div\n className=\"absolute left-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70\"\n style={{ width: `${percent}%` }}\n />\n <input\n id={fieldId}\n data-jsf-input\n type=\"range\"\n aria-label={field.label}\n {...fieldAriaProps(field, fieldId)}\n min={min}\n max={max}\n step={step}\n value={value}\n disabled={readOnly}\n className={cn(SLIDER_INPUT_CLASS, field.inputClassName)}\n onChange={(event) => field.onChange(Number(event.target.value))}\n />\n </div>\n <span className={cn(\"w-16 shrink-0 text-right tabular-nums\", labelSizeClass[size])}>\n {hasValue ? value.toLocaleString() : \"—\"}\n </span>\n </div>\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 DateField in the schema's date or datetime mode. The raw\n// string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nexport function DateControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (!readOnly && field.allowCustomValue && text.includes(\"{{\")) {\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateField\n mode={field.dateFormat === \"date-time\" ? \"datetime\" : \"date\"}\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n inputClassName={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix ? \"pr-14\" : \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n prefix={field.prefix}\n suffix={field.suffix}\n />\n );\n}\n\nexport function BooleanControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className={cn(\"flex items-center gap-1\", controlHeightClass[size])}>\n {field.prefix}\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n {...fieldAriaProps(field, fieldId)}\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n}\n\nexport function EnumControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"grid\") {\n return <GridControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n if (field.display === \"radio\") {\n return (\n <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} size={size} />\n );\n }\n if (field.display === \"segmented\") {\n return (\n <SegmentedEnumControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} size={size} />\n );\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n prefix={field.prefix}\n suffix={field.suffix}\n {...comboboxAriaProps(field, fieldId)}\n {...(field.inputClassName ? { className: field.inputClassName } : {})}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// The FormSize scale is wider than SegmentedControl's; map the extremes down.\nconst SEGMENTED_SIZE: Record<FormSize, SegmentedSize> = {\n xs: \"sm\",\n sm: \"sm\",\n md: \"md\",\n lg: \"lg\",\n xl: \"lg\",\n};\n\n// SegmentedEnumControl renders an enum (x-enum-display: \"segmented\") with the\n// shared SegmentedControl. Icons come from x-enum-icons, descriptions from\n// x-enum-descriptions (which promote it to the large card layout). The wrapper\n// carries the field id + data-jsf-input so the JSF field contract holds.\nfunction SegmentedEnumControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n size: FormSize;\n}) {\n const hasDescription = options.some((opt) => opt.description);\n const segSize: SegmentedSize = hasDescription ? \"lg\" : SEGMENTED_SIZE[size];\n return (\n <div id={fieldId} data-jsf-input className={cn(field.inputClassName)}>\n <SegmentedControl\n aria-label={field.label}\n value={value}\n onChange={(next) => field.onChange(next)}\n size={segSize}\n wrap\n options={options.map((opt) => ({\n id: opt.value,\n label: opt.label,\n // x-enum-icons resolves to a runtime name string; SegmentedControl\n // renders that via <Icon name>. Non-string (pre-extension) icons are\n // dropped here since the segmented option type only takes name/component.\n ...(typeof opt.icon === \"string\" ? { icon: opt.icon } : {}),\n ...(opt.description ? { description: opt.description } : {}),\n ...(readOnly ? { disabled: true } : {}),\n }))}\n />\n </div>\n );\n}\n\n// LookupControl is the async entity-reference picker for an `x-clicky-lookup`\n// field. It wraps Combobox and fetches options lazily through the form's\n// LookupFetcher (from context): the head set loads when the menu opens and the\n// (debounced) typed query drives server-side search. Single-select keeps\n// allowCustomValue on so a value outside the option set still commits (e.g. an\n// inline DSN). When no fetcher is wired it degrades to a free-text combobox.\nexport function LookupControl({\n field,\n fieldId,\n readOnly,\n size,\n rootValue,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n rootValue?: Record<string, unknown>;\n}) {\n const fetcher = useLookupFetcher();\n const descriptor = field.lookup;\n const value = toText(field.value);\n const [options, setOptions] = useState<FieldOption[]>([]);\n const [loading, setLoading] = useState(false);\n\n // rootValue is read through a ref so onSearch stays referentially stable: a new\n // onSearch each render would retrigger Combobox's search effect on every\n // setOptions, looping. The scopeKey effect below re-fetches when scope changes.\n const rootRef = useRef(rootValue);\n rootRef.current = rootValue;\n\n const onSearch = useCallback(\n (query: string) => {\n if (!descriptor || !fetcher) return;\n setLoading(true);\n const root = rootRef.current;\n fetcher({ descriptor, query, ...(root ? { rootValue: root } : {}) })\n .then((next) => setOptions(next))\n .catch(() => setOptions([]))\n .finally(() => setLoading(false));\n },\n [descriptor, fetcher],\n );\n\n // Re-fetch the head set when the scope (a sibling field, e.g. provider type)\n // changes so the out-of-scope set is replaced rather than shown stale.\n const scopeKey = descriptor ? JSON.stringify(resolveLookupScope(descriptor, rootValue)) : \"\";\n useEffect(() => {\n if (descriptor && fetcher) onSearch(\"\");\n else setOptions([]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scopeKey, onSearch]);\n\n // A descriptor that declares a hierarchy browses its options as a tree rather\n // than scrolling one flat list. It owns the multi-value case too, since the\n // committed value is then an array rather than a single string.\n if (descriptor?.hierarchy) {\n return (\n <LookupTreeControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n options={options}\n loading={loading}\n hierarchy={descriptor.hierarchy}\n />\n );\n }\n\n // A multi lookup commits an ARRAY, so it takes the tags picker rather than the\n // single-value combobox below — which would render the array as an empty box\n // and then overwrite it with a bare string. Without a fetcher the same control\n // renders the already-committed values with an empty option set.\n if (descriptor?.multi) {\n return (\n <TagsComboboxControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n options={options}\n loading={loading}\n {...(fetcher ? { onSearch } : {})}\n />\n );\n }\n\n if (!descriptor || !fetcher) {\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue([], value)}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue\n onChange={(v) => field.onChange(v)}\n {...comboboxAriaProps(field, fieldId)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n }\n\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue(options, value)}\n value={value}\n disabled={readOnly}\n size={size}\n loading={loading}\n allowCustomValue={field.allowCustomValue ?? false}\n onSearch={onSearch}\n onChange={(v) => field.onChange(v)}\n {...comboboxAriaProps(field, fieldId)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// RadioGroupControl renders a small fixed enum as a segmented radio-button group\n// instead of a dropdown. It shares EnumControl's option list (any out-of-enum\n// value is already prepended, so a token still shows). One `radiogroup` role +\n// native radios keep it keyboard-navigable; the visible chip is a styled label.\nfunction RadioGroupControl({\n field,\n fieldId,\n readOnly,\n options,\n value,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n options: FieldOption[];\n value: string;\n size: FormSize;\n}) {\n return (\n <div\n role=\"radiogroup\"\n aria-label={field.label}\n id={fieldId}\n data-jsf-input\n className={cn(\n \"inline-flex flex-wrap items-center gap-1 rounded-md border border-input bg-background p-0.5\",\n field.inputClassName,\n )}\n >\n {options.map((opt) => {\n const checked = opt.value === value;\n return (\n <label\n key={opt.value}\n className={cn(\n \"inline-flex cursor-pointer select-none items-center rounded px-2.5 py-1\",\n labelSizeClass[size],\n checked\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-accent hover:text-foreground\",\n readOnly && \"cursor-not-allowed opacity-60\",\n )}\n >\n <input\n type=\"radio\"\n name={fieldId}\n className=\"sr-only\"\n value={opt.value}\n checked={checked}\n disabled={readOnly}\n onChange={() => field.onChange(opt.value)}\n />\n {opt.label}\n </label>\n );\n })}\n </div>\n );\n}\n\n// TextareaControl edits a long-form string in a multi-line box. Read-only, it\n// shows the value with line breaks preserved; editable, a resizable <textarea>.\n// The raw string is committed unchanged so a consumer-permitted template token\n// survives.\nexport function TextareaControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"block whitespace-pre-wrap break-words text-foreground\", labelSizeClass[size])}\n title={text || undefined}\n >\n {text || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n }\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <textarea\n id={fieldId}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n rows={4}\n className={cn(\n inputClass(size),\n \"h-auto min-h-[5rem] resize-y\",\n field.prefix && \"pl-8\",\n field.suffix && \"pr-8\",\n field.inputClassName,\n )}\n value={text}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function MarkdownControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const fallback = (\n <textarea\n id={fieldId}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n rows={6}\n className={cn(inputClass(size), \"h-auto resize-y font-mono\", field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n\n return (\n <Suspense fallback={fallback}>\n <LazyMdxEditorField\n id={fieldId}\n value={toText(field.value)}\n readOnly={readOnly}\n size={size}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(next) => field.onChange(next)}\n {...field.markdownOptions}\n />\n </Suspense>\n );\n}\n\n// DisplayControl renders a static, non-editable presentation element:\n// Label/Title (heading), Message (info text), Line (divider), or Blank/Filler\n// (spacer). It never collects a value; the heading/text source is the field's\n// title (label) and, for \"text\", its description. Rendered identically in the\n// form and the read-only Viewer.\nexport function DisplayControl({ field, size }: { field: FieldControl; size: FormSize }) {\n const variant = field.displayVariant ?? \"text\";\n if (variant === \"divider\") {\n return <hr data-jsf-input className=\"my-1 w-full border-t border-border\" />;\n }\n if (variant === \"spacer\") {\n return <div data-jsf-input aria-hidden className=\"h-2\" />;\n }\n if (variant === \"heading\") {\n return (\n <div\n data-jsf-input\n className={cn(\"border-b border-border pb-1 font-semibold text-foreground\", labelSizeClass[size])}\n >\n {field.label}\n </div>\n );\n }\n const text = field.description ?? toText(field.value) ?? field.label;\n return (\n <p data-jsf-input className={cn(\"text-muted-foreground\", labelSizeClass[size])}>\n {text || field.label}\n </p>\n );\n}\n\n// LinkControl renders a read-only external hyperlink. The\n// href is field.href, falling back to the value when it is an absolute URL; with\n// neither it degrades to a plain read-only value.\nexport function LinkControl({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const href = field.href ?? (/^https?:\\/\\//i.test(text) ? text : undefined);\n if (!href) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={size} />;\n }\n return (\n <a\n id={fieldId}\n data-jsf-input\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className={cn(\"inline-flex items-center text-primary underline underline-offset-2\", controlHeightClass[size], labelSizeClass[size])}\n >\n {text || field.label || href}\n </a>\n );\n}\n\n// HMR probe\n// HMR probe 2\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-fields.js","sources":["../../src/components/json-schema-form-fields.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { formatDateTimeRelative } from \"../data/cells/timestamp-format\";\nimport { Combobox } from \"./Combobox\";\nimport { DateField } from \"./DateField\";\nimport { RadioGroupControl, SegmentedEnumControl } from \"./json-schema-form-enum-choice\";\nimport { GridControl } from \"./json-schema-form-grid\";\nimport { LookupTreeControl } from \"./json-schema-form-lookup-tree\";\nimport { TagsComboboxControl } from \"./json-schema-form-tags-combobox\";\nimport { resolveLookupScope, useLookupFetcher } from \"./form-lookup-context\";\nimport type { FieldControl, FieldOption } from \"./json-schema-form-types\";\nimport {\n comboboxAriaProps,\n defaultPlaceholder,\n fieldAriaProps,\n inputClass,\n toText,\n withSyntheticValue,\n} from \"./json-schema-form-utils\";\nimport {\n controlHeightClass,\n labelSizeClass,\n type FormSize,\n} from \"./json-schema-form-size\";\n\nconst LazyMdxEditorField = lazy(async () => {\n const mod = await import(\"./MdxEditorField\");\n return { default: mod.MdxEditorField };\n});\n\n// ReadOnlyValue renders a `readOnly` field's current value as static text — no\n// input, no border, just the value (date/date-time formatted human-readably).\n// An empty value shows an em-dash. Carries the same id + data-jsf-input as the\n// editable controls so layout and queries stay uniform.\nexport function ReadOnlyValue({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const secret = field.schema.format === \"password\";\n const display = secret && text ? \"••••••••\" : field.kind === \"date\" && text ? formatDateTimeRelative(text) : text;\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={secret ? undefined : text || undefined}\n >\n {display || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n}\n\n// FieldAdornmentWrapper positions a field's leading/trailing in-field adornments\n// (FieldControl.prefix at the left edge, FieldControl.suffix at the right). The\n// container is tagged data-jsf-control so an adornment can locate its sibling\n// input[data-jsf-input] (e.g. for caret-aware insertion). With neither adornment\n// it renders the input bare, so unadorned fields are byte-for-byte unchanged.\nfunction FieldAdornmentWrapper({\n prefix,\n suffix,\n children,\n}: {\n prefix?: ReactNode;\n suffix?: ReactNode;\n children: ReactNode;\n}) {\n if (!prefix && !suffix) return <>{children}</>;\n return (\n <div data-jsf-control className=\"relative\">\n {prefix && <div className=\"absolute inset-y-0 left-1.5 flex items-center\">{prefix}</div>}\n {children}\n {suffix && <div className=\"absolute inset-y-0 right-1.5 flex items-center\">{suffix}</div>}\n </div>\n );\n}\n\nexport function StringControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <input\n id={fieldId}\n // format:\"password\" masks secret material (API keys, client secrets);\n // autoComplete new-password stops browsers from offering saved logins.\n type={field.schema.format === \"password\" ? \"password\" : \"text\"}\n autoComplete={field.schema.format === \"password\" ? \"new-password\" : undefined}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n className={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix && \"pr-8\", field.inputClassName)}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function NumberControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // A bounded number can opt into a single-thumb progress slider.\n if (field.schema[\"x-number-display\"] === \"slider\" && typeof field.schema.maximum === \"number\") {\n return <NumberSliderControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n // Default type=\"text\" (not number) so non-numeric values a consumer permits —\n // e.g. template tokens — are not silently dropped by the browser. A schema that\n // declares `multipleOf` opts into a real `<input type=\"number\">` (native step,\n // spin buttons, min/max), matching a hand-built numeric field.\n const coerce = field.coerceNumber !== false;\n const step = typeof field.schema.multipleOf === \"number\" ? field.schema.multipleOf : undefined;\n const native = step !== undefined && !(field.allowCustomValue && typeof field.value === \"string\" && field.value.includes(\"{{\"));\n // A static unit (e.g. \"%\") rides the right edge of the input as a display-only\n // suffix; a consumer-set `suffix` (e.g. an insert-snippet button) wins if both\n // are present (number insert triggers mount on the left as `prefix`).\n const suffix = field.suffix ?? (field.unit ? (\n <span className=\"pointer-events-none select-none text-muted-foreground\">{field.unit}</span>\n ) : undefined);\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={suffix}>\n <input\n id={fieldId}\n type={native ? \"number\" : \"text\"}\n inputMode=\"decimal\"\n {...(native\n ? {\n step,\n ...(typeof field.schema.minimum === \"number\" ? { min: field.schema.minimum } : {}),\n ...(typeof field.schema.maximum === \"number\" ? { max: field.schema.maximum } : {}),\n }\n : {})}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n className={cn(inputClass(size), field.prefix && \"pl-8\", suffix && \"pr-8\", field.inputClassName)}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => {\n const raw = e.target.value;\n // Coerce mid-typing ONLY when the parse round-trips to the same text\n // (e.g. \"100\", \"33.5\") — so an in-progress decimal like \"33.\" or a\n // trailing-zero \"33.30\" keeps its raw text instead of collapsing to a\n // number and stranding the caret. Non-numeric tokens fall through to\n // the raw string. Blur finalizes any still-uncoerced numeric text.\n if (coerce && raw.trim() !== \"\" && String(Number(raw)) === raw.trim()) {\n field.onChange(Number(raw));\n } else {\n field.onChange(raw);\n }\n }}\n onBlur={(e) => {\n const raw = e.target.value;\n if (coerce && raw.trim() !== \"\" && Number.isFinite(Number(raw))) {\n field.onChange(Number(raw));\n }\n }}\n />\n </FieldAdornmentWrapper>\n );\n}\n\n// A single-thumb range input styled with a progress-filled track. The input sits\n// above the track/fill divs; only its thumb is painted.\nconst SLIDER_INPUT_CLASS =\n \"absolute inset-0 h-6 w-full cursor-pointer appearance-none bg-transparent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-transparent [&::-webkit-slider-thumb]:size-3.5 [&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-background/80 [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-transparent [&::-moz-range-thumb]:size-3.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow-sm\";\n\n// NumberSliderControl renders a bounded number (`x-number-display: \"slider\"`) as\n// a single-thumb slider whose fill grows with the value, with the live value\n// shown to the right.\nexport function NumberSliderControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const min = typeof field.schema.minimum === \"number\" ? field.schema.minimum : 0;\n const max = typeof field.schema.maximum === \"number\" ? field.schema.maximum : 100;\n const step = typeof field.schema.multipleOf === \"number\" ? field.schema.multipleOf : 1;\n const raw = typeof field.value === \"number\" ? field.value : Number(toText(field.value));\n const hasValue = Number.isFinite(raw);\n const value = hasValue ? Math.min(max, Math.max(min, raw)) : min;\n const percent = max > min ? ((value - min) / (max - min)) * 100 : 0;\n return (\n <div className=\"flex items-center gap-3\">\n <div className=\"relative h-6 min-w-0 flex-1\">\n <div className=\"absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-border\" />\n <div\n className=\"absolute left-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-primary/70\"\n style={{ width: `${percent}%` }}\n />\n <input\n id={fieldId}\n data-jsf-input\n type=\"range\"\n aria-label={field.label}\n {...fieldAriaProps(field, fieldId)}\n min={min}\n max={max}\n step={step}\n value={value}\n disabled={readOnly}\n className={cn(SLIDER_INPUT_CLASS, field.inputClassName)}\n onChange={(event) => field.onChange(Number(event.target.value))}\n />\n </div>\n <span className={cn(\"w-16 shrink-0 text-right tabular-nums\", labelSizeClass[size])}>\n {hasValue ? value.toLocaleString() : \"—\"}\n </span>\n </div>\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 DateField in the schema's date or datetime mode. The raw\n// string is committed unchanged so a\n// consumer-permitted template token in the field is preserved.\nexport function DateControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (!readOnly && field.allowCustomValue && text.includes(\"{{\")) {\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n if (readOnly) {\n return (\n <div\n id={fieldId}\n data-jsf-input\n className={cn(\"flex items-center text-foreground\", controlHeightClass[size], labelSizeClass[size])}\n title={text || undefined}\n >\n {text ? formatDateTimeRelative(text) : <span className=\"text-muted-foreground\">—</span>}\n </div>\n );\n }\n return (\n <DateField\n mode={field.dateFormat === \"date-time\" ? \"datetime\" : \"date\"}\n id={fieldId}\n aria-label={field.label}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n inputClassName={cn(inputClass(size), field.prefix && \"pl-8\", field.suffix ? \"pr-14\" : \"pr-8\")}\n value={text}\n onChange={(next) => field.onChange(next)}\n placeholder={defaultPlaceholder(field.schema)}\n prefix={field.prefix}\n suffix={field.suffix}\n />\n );\n}\n\nexport function BooleanControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n // Only render a checkbox when the value is genuinely boolean (or unset).\n // A non-boolean value (e.g. a token a consumer left in place) renders as text\n // so it is preserved and editable.\n if (typeof field.value === \"boolean\" || field.value === undefined || field.value === null) {\n return (\n <div className={cn(\"flex items-center gap-1\", controlHeightClass[size])}>\n {field.prefix}\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n {...fieldAriaProps(field, fieldId)}\n checked={field.value === true}\n disabled={readOnly}\n onChange={(e) => field.onChange(e.target.checked)}\n />\n </div>\n );\n }\n return <StringControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n}\n\nexport function EnumControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const value = toText(field.value);\n const options = withSyntheticValue(field.options ?? [], value);\n if (field.display === \"grid\") {\n return <GridControl field={field} fieldId={fieldId} readOnly={readOnly} size={size} />;\n }\n if (field.display === \"radio\") {\n return (\n <RadioGroupControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} size={size} />\n );\n }\n if (field.display === \"segmented\") {\n return (\n <SegmentedEnumControl field={field} fieldId={fieldId} readOnly={readOnly} options={options} value={value} size={size} />\n );\n }\n return (\n <Combobox\n id={fieldId}\n options={options}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue={field.allowCustomValue ?? false}\n onChange={(v) => field.onChange(v)}\n prefix={field.prefix}\n suffix={field.suffix}\n {...comboboxAriaProps(field, fieldId)}\n {...(field.inputClassName ? { className: field.inputClassName } : {})}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// LookupControl is the async entity-reference picker for an `x-clicky-lookup`\n// field. It wraps Combobox and fetches options lazily through the form's\n// LookupFetcher (from context): the head set loads when the menu opens and the\n// (debounced) typed query drives server-side search. Single-select keeps\n// allowCustomValue on so a value outside the option set still commits (e.g. an\n// inline DSN). When no fetcher is wired it degrades to a free-text combobox.\nexport function LookupControl({\n field,\n fieldId,\n readOnly,\n size,\n rootValue,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n rootValue?: Record<string, unknown>;\n}) {\n const fetcher = useLookupFetcher();\n const descriptor = field.lookup;\n const value = toText(field.value);\n const [options, setOptions] = useState<FieldOption[]>([]);\n const [loading, setLoading] = useState(false);\n\n // rootValue is read through a ref so onSearch stays referentially stable: a new\n // onSearch each render would retrigger Combobox's search effect on every\n // setOptions, looping. The scopeKey effect below re-fetches when scope changes.\n const rootRef = useRef(rootValue);\n rootRef.current = rootValue;\n\n const onSearch = useCallback(\n (query: string) => {\n if (!descriptor || !fetcher) return;\n setLoading(true);\n const root = rootRef.current;\n fetcher({ descriptor, query, ...(root ? { rootValue: root } : {}) })\n .then((next) => setOptions(next))\n .catch(() => setOptions([]))\n .finally(() => setLoading(false));\n },\n [descriptor, fetcher],\n );\n\n // Re-fetch the head set when the scope (a sibling field, e.g. provider type)\n // changes so the out-of-scope set is replaced rather than shown stale.\n const scopeKey = descriptor ? JSON.stringify(resolveLookupScope(descriptor, rootValue)) : \"\";\n useEffect(() => {\n if (descriptor && fetcher) onSearch(\"\");\n else setOptions([]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scopeKey, onSearch]);\n\n // A descriptor that declares a hierarchy browses its options as a tree rather\n // than scrolling one flat list. It owns the multi-value case too, since the\n // committed value is then an array rather than a single string.\n if (descriptor?.hierarchy) {\n return (\n <LookupTreeControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n options={options}\n loading={loading}\n hierarchy={descriptor.hierarchy}\n />\n );\n }\n\n // A multi lookup commits an ARRAY, so it takes the tags picker rather than the\n // single-value combobox below — which would render the array as an empty box\n // and then overwrite it with a bare string. Without a fetcher the same control\n // renders the already-committed values with an empty option set.\n if (descriptor?.multi) {\n return (\n <TagsComboboxControl\n field={field}\n fieldId={fieldId}\n readOnly={readOnly}\n size={size}\n options={options}\n loading={loading}\n {...(fetcher ? { onSearch } : {})}\n />\n );\n }\n\n if (!descriptor || !fetcher) {\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue([], value)}\n value={value}\n disabled={readOnly}\n size={size}\n allowCustomValue\n onChange={(v) => field.onChange(v)}\n {...comboboxAriaProps(field, fieldId)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n }\n\n return (\n <Combobox\n id={fieldId}\n options={withSyntheticValue(options, value)}\n value={value}\n disabled={readOnly}\n size={size}\n loading={loading}\n allowCustomValue={field.allowCustomValue ?? false}\n onSearch={onSearch}\n onChange={(v) => field.onChange(v)}\n {...comboboxAriaProps(field, fieldId)}\n {...(defaultPlaceholder(field.schema) ? { placeholder: defaultPlaceholder(field.schema) } : {})}\n />\n );\n}\n\n// TextareaControl edits a long-form string in a multi-line box. Read-only, it\n// shows the value with line breaks preserved; editable, a resizable <textarea>.\n// The raw string is committed unchanged so a consumer-permitted template token\n// survives.\nexport function TextareaControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const text = toText(field.value);\n if (readOnly) {\n return (\n <span\n id={fieldId}\n data-jsf-input\n data-jsf-readonly\n className={cn(\"block whitespace-pre-wrap break-words text-foreground\", labelSizeClass[size])}\n title={text || undefined}\n >\n {text || <span className=\"text-muted-foreground\">—</span>}\n </span>\n );\n }\n return (\n <FieldAdornmentWrapper prefix={field.prefix} suffix={field.suffix}>\n <textarea\n id={fieldId}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n rows={4}\n className={cn(\n inputClass(size),\n \"h-auto min-h-[5rem] resize-y\",\n field.prefix && \"pl-8\",\n field.suffix && \"pr-8\",\n field.inputClassName,\n )}\n value={text}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n </FieldAdornmentWrapper>\n );\n}\n\nexport function MarkdownControl({\n field,\n fieldId,\n readOnly,\n size,\n}: {\n field: FieldControl;\n fieldId: string;\n readOnly: boolean;\n size: FormSize;\n}) {\n const fallback = (\n <textarea\n id={fieldId}\n data-jsf-input\n {...fieldAriaProps(field, fieldId)}\n rows={6}\n className={cn(inputClass(size), \"h-auto resize-y font-mono\", field.prefix && \"pl-8\", field.suffix && \"pr-8\")}\n value={toText(field.value)}\n disabled={readOnly}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(e) => field.onChange(e.target.value)}\n />\n );\n\n return (\n <Suspense fallback={fallback}>\n <LazyMdxEditorField\n id={fieldId}\n value={toText(field.value)}\n readOnly={readOnly}\n size={size}\n placeholder={defaultPlaceholder(field.schema)}\n onChange={(next) => field.onChange(next)}\n {...field.markdownOptions}\n />\n </Suspense>\n );\n}\n\n// DisplayControl renders a static, non-editable presentation element:\n// Label/Title (heading), Message (info text), Line (divider), or Blank/Filler\n// (spacer). It never collects a value; the heading/text source is the field's\n// title (label) and, for \"text\", its description. Rendered identically in the\n// form and the read-only Viewer.\nexport function DisplayControl({ field, size }: { field: FieldControl; size: FormSize }) {\n const variant = field.displayVariant ?? \"text\";\n if (variant === \"divider\") {\n return <hr data-jsf-input className=\"my-1 w-full border-t border-border\" />;\n }\n if (variant === \"spacer\") {\n return <div data-jsf-input aria-hidden className=\"h-2\" />;\n }\n if (variant === \"heading\") {\n return (\n <div\n data-jsf-input\n className={cn(\"border-b border-border pb-1 font-semibold text-foreground\", labelSizeClass[size])}\n >\n {field.label}\n </div>\n );\n }\n const text = field.description ?? toText(field.value) ?? field.label;\n return (\n <p data-jsf-input className={cn(\"text-muted-foreground\", labelSizeClass[size])}>\n {text || field.label}\n </p>\n );\n}\n\n// LinkControl renders a read-only external hyperlink. The\n// href is field.href, falling back to the value when it is an absolute URL; with\n// neither it degrades to a plain read-only value.\nexport function LinkControl({ field, fieldId, size }: { field: FieldControl; fieldId: string; size: FormSize }) {\n const text = toText(field.value);\n const href = field.href ?? (/^https?:\\/\\//i.test(text) ? text : undefined);\n if (!href) {\n return <ReadOnlyValue field={field} fieldId={fieldId} size={size} />;\n }\n return (\n <a\n id={fieldId}\n data-jsf-input\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className={cn(\"inline-flex items-center text-primary underline underline-offset-2\", controlHeightClass[size], labelSizeClass[size])}\n >\n {text || field.label || href}\n </a>\n );\n}\n\n// HMR probe\n// HMR probe 2\n"],"names":[],"mappings":"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"}
|
|
@@ -43,7 +43,7 @@ function applyListenerState(schema, value, options) {
|
|
|
43
43
|
const actions = selectActions({ listener, source, self: value, known, options });
|
|
44
44
|
for (const [name, keyword, flag] of STATE_FLAGS) {
|
|
45
45
|
for (const target of list(actions, name)) {
|
|
46
|
-
jsonSchemaFormListenerPaths.patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, [keyword]: flag }) });
|
|
46
|
+
jsonSchemaFormListenerPaths.patchTarget({ properties, value, target, apply: (leaf) => hiddenBy({ ...leaf, [keyword]: flag }, keyword, flag, source.label) });
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
for (const target of list(actions, "require")) {
|
|
@@ -56,6 +56,12 @@ function applyListenerState(schema, value, options) {
|
|
|
56
56
|
}
|
|
57
57
|
return { properties, required: [...requiredSet] };
|
|
58
58
|
}
|
|
59
|
+
function hiddenBy(leaf, keyword, flag, label) {
|
|
60
|
+
if (keyword !== "x-hidden") return leaf;
|
|
61
|
+
if (flag) return { ...leaf, "x-hidden-by": label };
|
|
62
|
+
const { "x-hidden-by": _by, ...shown } = leaf;
|
|
63
|
+
return shown;
|
|
64
|
+
}
|
|
59
65
|
function loadListenersOf(schema, value) {
|
|
60
66
|
var _a;
|
|
61
67
|
const bound = loadListenersAt(schema["x-on-load"], "#/x-on-load");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-listeners.cjs","sources":["../../src/components/json-schema-form-listeners.ts"],"sourcesContent":["import { isPlainObject } from \"../lib/collections\";\nimport {\n effectiveProperties,\n evaluatePredicate,\n matchesIf,\n type EffectiveProperties,\n} from \"./json-schema-form-conditionals\";\nimport { cloneSchemaDefault } from \"./json-schema-form-defaults\";\nimport { isPathTarget, patchTarget, targetSegments } from \"./json-schema-form-listener-paths\";\nimport type {\n ChangeActions,\n ChangeListener,\n ExpressionEvaluator,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// `x-on-change` listeners: a property names what happens to its siblings when\n// its value is, or becomes, something. `x-on-load` listeners: an object names\n// the state its properties start in. See ChangeActions for the split between\n// derived state actions and transitional value actions.\n\nexport interface ListenerOptions {\n root: Record<string, unknown>;\n evaluate?: ExpressionEvaluator;\n}\n\n// ListenerSource says where a listener came from. `label` prefixes every error\n// it raises; `key` is the property whose value `when` reads (and the\n// evaluator's `key`) — for x-on-load, \"\" and the object itself.\ninterface ListenerSource {\n label: string;\n key: string;\n load: boolean;\n}\n\ninterface BoundListener {\n listener: ChangeListener;\n source: ListenerSource;\n}\n\ntype ListName = \"hide\" | \"show\" | \"enable\" | \"disable\" | \"require\" | \"optional\" | \"reset\";\n\n// Actions that write values or required-ness: they act on sibling keys only\n// (never a path), and have no place in x-on-load, which only derives state.\nconst LOCAL_ACTIONS: (\"require\" | \"optional\" | \"reset\" | \"set\")[] = [\"require\", \"optional\", \"reset\", \"set\"];\n\nconst STATE_FLAGS: [ListName, \"x-hidden\" | \"x-disabled\", boolean][] = [\n [\"hide\", \"x-hidden\", true],\n [\"show\", \"x-hidden\", false],\n [\"disable\", \"x-disabled\", true],\n [\"enable\", \"x-disabled\", false],\n];\n\nconst CONTRADICTIONS: [ListName, ListName][] = [\n [\"hide\", \"show\"],\n [\"enable\", \"disable\"],\n [\"require\", \"optional\"],\n];\n\nconst LIST_NAMES: ListName[] = [\"hide\", \"show\", \"enable\", \"disable\", \"require\", \"optional\", \"reset\"];\n\n// Keywords a `patch` may not set, with the tool that does the job instead.\nconst PATCH_DENIED: Record<string, string> = {\n ...Object.fromEntries(\n [\"type\", \"properties\", \"items\", \"additionalProperties\", \"patternProperties\", \"allOf\", \"anyOf\", \"oneOf\", \"if\", \"then\", \"else\", \"not\", \"$ref\", \"$defs\"].map(\n (keyword) => [keyword, \"it changes the field's shape; use an allOf branch\"],\n ),\n ),\n required: \"use require/optional\",\n default: \"a patch changes presentation, not values; use set/reset\",\n const: \"a patch changes presentation, not values; use set/reset\",\n \"x-on-change\": \"listeners cannot be patched in\",\n \"x-on-load\": \"listeners cannot be patched in\",\n};\n\n// applyListenerState is effectiveProperties plus the state actions of every\n// listener, evaluated against the current value: first the object's\n// `x-on-load` listeners, then each property's `x-on-change` listeners — load,\n// then change, the order the events happen in. A listener is applied after\n// `allOf`, so it wins over a branch; later listeners win over earlier ones. A\n// target the current shape does not declare stays absent. Property schemas are\n// cloned, never mutated.\nexport function applyListenerState(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n options: ListenerOptions,\n): EffectiveProperties {\n const { properties, required } = effectiveProperties(schema, value);\n const requiredSet = new Set(required);\n const known = declaredKeys(schema);\n const bound: BoundListener[] = [\n ...loadListenersOf(schema, value),\n ...Object.entries(properties).flatMap(([key, prop]) =>\n listenersOf(key, prop).map((listener) => ({ listener, source: changeSource(key) })),\n ),\n ];\n for (const { listener, source } of bound) {\n const actions = selectActions({ listener, source, self: value, known, options });\n for (const [name, keyword, flag] of STATE_FLAGS) {\n for (const target of list(actions, name)) {\n patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, [keyword]: flag }) });\n }\n }\n for (const target of list(actions, \"require\")) {\n if (properties[target]) requiredSet.add(target);\n }\n for (const target of list(actions, \"optional\")) requiredSet.delete(target);\n for (const [target, keywords] of Object.entries(actions.patch ?? {})) {\n patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, ...keywords }) });\n }\n }\n return { properties, required: [...requiredSet] };\n}\n\n// loadListenersOf collects an object's `x-on-load` listeners in order: the\n// schema's own, then each `allOf` member's — an unconditional member's own, or\n// those of the `then`/`else` branch that applies, selected exactly as\n// effectiveProperties selects the branch it merges.\nfunction loadListenersOf(schema: JsonSchemaObject, value: Record<string, unknown>): BoundListener[] {\n const bound = loadListenersAt(schema[\"x-on-load\"], \"#/x-on-load\");\n for (const [index, clause] of (schema.allOf ?? []).entries()) {\n if (clause.if === undefined && clause.then === undefined) {\n bound.push(...loadListenersAt(clause[\"x-on-load\"], `#/allOf/${index}/x-on-load`));\n continue;\n }\n const branch = matchesIf(clause.if, value) ? \"then\" : \"else\";\n bound.push(...loadListenersAt(clause[branch]?.[\"x-on-load\"], `#/allOf/${index}/${branch}/x-on-load`));\n }\n return bound;\n}\n\nfunction loadListenersAt(listeners: unknown, pointer: string): BoundListener[] {\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`x-on-load at ${pointer} must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners.map((listener: ChangeListener, index) => ({\n listener,\n source: { label: `x-on-load at ${pointer}/${index}`, key: \"\", load: true },\n }));\n}\n\nfunction changeSource(key: string): ListenerSource {\n return { label: `x-on-change on \"${key}\"`, key, load: false };\n}\n\n// applyChangeEffects commits `next` at `key` and runs the value actions\n// (reset/set) of that key's listeners against the post-edit object. A target\n// whose value actually changes fires its own listeners in turn; each key fires\n// at most once per commit, so a cycle ends. When `root` is the edited object\n// itself (the top level), expressions see the post-edit value as root too.\nexport function applyChangeEffects(\n schema: JsonSchemaObject,\n edit: ListenerOptions & { value: Record<string, unknown>; key: string; next: unknown },\n): Record<string, unknown> {\n let current: Record<string, unknown> = { ...edit.value, [edit.key]: edit.next };\n const known = declaredKeys(schema);\n const fired = new Set<string>();\n const queue = [edit.key];\n for (let source = queue.shift(); source !== undefined; source = queue.shift()) {\n if (fired.has(source)) continue;\n fired.add(source);\n const { properties } = effectiveProperties(schema, current);\n const options: ListenerOptions = {\n root: edit.root === edit.value ? current : edit.root,\n ...(edit.evaluate ? { evaluate: edit.evaluate } : {}),\n };\n for (const listener of listenersOf(source, properties[source])) {\n const actions = selectActions({ listener, source: changeSource(source), self: current, known, options });\n for (const [target, nextValue] of valueChanges(actions, properties)) {\n if (Object.is(current[target], nextValue)) continue;\n current = { ...current };\n if (nextValue === undefined) delete current[target];\n else current[target] = nextValue;\n queue.push(target);\n }\n }\n }\n return current;\n}\n\nfunction valueChanges(\n actions: ChangeActions,\n properties: Record<string, JsonSchemaProperty>,\n): [string, unknown][] {\n return [\n ...list(actions, \"reset\").map((target): [string, unknown] => {\n const fallback = properties[target]?.default;\n return [target, fallback === undefined ? undefined : cloneSchemaDefault(fallback)];\n }),\n ...Object.entries(actions.set ?? {}).map(([target, v]): [string, unknown] => [target, cloneSchemaDefault(v)]),\n ];\n}\n\nfunction listenersOf(key: string, prop: JsonSchemaProperty | undefined): ChangeListener[] {\n const listeners = prop?.[\"x-on-change\"];\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`\"${key}\": x-on-change must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners;\n}\n\n// selectActions validates both branches of a listener (so a schema error\n// surfaces whichever branch is live) and returns the one that applies now.\nfunction selectActions({\n listener,\n source,\n self,\n known,\n options,\n}: {\n listener: ChangeListener;\n source: ListenerSource;\n self: Record<string, unknown>;\n known: Set<string>;\n options: ListenerOptions;\n}): ChangeActions {\n validateActions(source, listener, known);\n if (listener.else) validateActions(source, listener.else, known);\n return listenerHolds(listener, source, self, options) ? listener : (listener.else ?? {});\n}\n\n// listenerHolds evaluates `when` against the source's subject: the property's\n// value for x-on-change, the object itself for x-on-load.\nfunction listenerHolds(\n listener: ChangeListener,\n { label, key, load }: ListenerSource,\n self: Record<string, unknown>,\n options: ListenerOptions,\n): boolean {\n if (listener.when === undefined) return true;\n const { expr, ...predicate } = listener.when;\n const hasPredicate = Object.keys(predicate).length > 0;\n const subject = load ? self : self[key];\n if (!hasPredicate && expr === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate`);\n }\n if (expr !== undefined && typeof expr !== \"string\") {\n throw new Error(`${label}: when.expr must be a string, got ${typeof expr}`);\n }\n if (expr !== undefined && !options.evaluate) {\n throw new Error(`${label}: when.expr \"${expr}\" needs the form's expressionEvaluator`);\n }\n if (hasPredicate) {\n const holds = evaluatePredicate(predicate, subject);\n if (holds === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate (${JSON.stringify(predicate)})`);\n }\n if (!holds) return false;\n }\n if (expr === undefined || !options.evaluate) return true;\n const result: unknown = options.evaluate({ expr, key, value: subject, self, root: options.root });\n if (typeof result !== \"boolean\") {\n throw new Error(`${label}: expressionEvaluator returned ${typeof result} for \"${expr}\", expected boolean`);\n }\n return result;\n}\n\nfunction validateActions(source: ListenerSource, actions: ChangeActions, known: Set<string>): void {\n const { label } = source;\n if (actions.set !== undefined && !isPlainObject(actions.set)) {\n throw new Error(`${label}: set must be an object of target → value`);\n }\n if (source.load) {\n const local = LOCAL_ACTIONS.find((name) => actions[name] !== undefined);\n if (local) {\n throw new Error(`${label}: ${local} is not allowed in x-on-load, which only derives state (hide/show/enable/disable/patch)`);\n }\n }\n const setKeys = Object.keys(actions.set ?? {});\n for (const name of LOCAL_ACTIONS) {\n const targets = name === \"set\" ? setKeys : list(actions, name);\n const path = targets.find(isPathTarget);\n if (path !== undefined) {\n throw new Error(`${label}: ${name} \"${path}\" cannot take a path; value and required actions act on sibling keys only`);\n }\n }\n for (const target of [...LIST_NAMES.flatMap((name) => list(actions, name)), ...setKeys]) {\n validateTarget(label, target, known);\n }\n const pairs: [string, string[], string, string[]][] = [\n ...CONTRADICTIONS.map(([a, b]): [string, string[], string, string[]] => [a, list(actions, a), b, list(actions, b)]),\n [\"reset\", list(actions, \"reset\"), \"set\", setKeys],\n ];\n for (const [a, left, b, right] of pairs) {\n const clash = left.find((target) => right.includes(target));\n if (clash !== undefined) {\n throw new Error(`${label}: both ${a} and ${b} \"${clash}\"`);\n }\n }\n validatePatch(label, actions, known);\n}\n\n// validateTarget checks a target's grammar and that its first segment is a key\n// the schema declares in some branch.\nfunction validateTarget(label: string, target: string, known: Set<string>): void {\n if (isPathTarget(target) && known.has(target)) {\n throw new Error(`${label}: target \"${target}\" is both a declared key and a path`);\n }\n const [first = \"\"] = targetSegments(label, target);\n if (!known.has(first)) throw new Error(`${label}: unknown target \"${target}\"`);\n}\n\n// validatePatch checks a `patch`: an object of keyword objects on known\n// targets, no denied keyword, and no keyword a verb in the same actions sets.\nfunction validatePatch(label: string, actions: ChangeActions, known: Set<string>): void {\n const patch: unknown = actions.patch;\n if (patch === undefined) return;\n if (!isPlainObject(patch)) {\n throw new Error(`${label}: patch must be an object of target → keywords`);\n }\n for (const [target, keywords] of Object.entries(patch)) {\n validateTarget(label, target, known);\n if (!isPlainObject(keywords)) {\n throw new Error(`${label}: patch \"${target}\" must be an object of keywords`);\n }\n for (const keyword of Object.keys(keywords)) {\n const denied = PATCH_DENIED[keyword];\n if (denied) throw new Error(`${label}: patch \"${target}\" may not set ${keyword} (${denied})`);\n }\n for (const [verb, keyword] of STATE_FLAGS) {\n if (keyword in keywords && list(actions, verb).includes(target)) {\n throw new Error(`${label}: both ${verb} and patch ${keyword} on \"${target}\"`);\n }\n }\n }\n}\n\nfunction list(actions: ChangeActions, name: ListName): string[] {\n const targets = actions[name];\n if (targets === undefined) return [];\n if (!Array.isArray(targets)) {\n throw new Error(`x-on-change: ${name} must be an array of property keys, got ${typeof targets}`);\n }\n return targets;\n}\n\n// Every key the schema can declare in any branch — a listener may target a\n// field that only exists while some `allOf` branch is live.\nfunction declaredKeys(schema: JsonSchemaObject): Set<string> {\n const keys = new Set(Object.keys(schema.properties ?? {}));\n for (const clause of schema.allOf ?? []) {\n for (const branch of [clause, clause.then, clause.else]) {\n for (const key of Object.keys(branch?.properties ?? {})) keys.add(key);\n }\n }\n return keys;\n}\n"],"names":["effectiveProperties","patchTarget","matchesIf","cloneSchemaDefault","evaluatePredicate","isPlainObject","isPathTarget","targetSegments"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-listeners.cjs","sources":["../../src/components/json-schema-form-listeners.ts"],"sourcesContent":["import { isPlainObject } from \"../lib/collections\";\nimport {\n effectiveProperties,\n evaluatePredicate,\n matchesIf,\n type EffectiveProperties,\n} from \"./json-schema-form-conditionals\";\nimport { cloneSchemaDefault } from \"./json-schema-form-defaults\";\nimport { isPathTarget, patchTarget, targetSegments } from \"./json-schema-form-listener-paths\";\nimport type {\n ChangeActions,\n ChangeListener,\n ExpressionEvaluator,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// `x-on-change` listeners: a property names what happens to its siblings when\n// its value is, or becomes, something. `x-on-load` listeners: an object names\n// the state its properties start in. See ChangeActions for the split between\n// derived state actions and transitional value actions.\n\nexport interface ListenerOptions {\n root: Record<string, unknown>;\n evaluate?: ExpressionEvaluator;\n}\n\n// ListenerSource says where a listener came from. `label` prefixes every error\n// it raises; `key` is the property whose value `when` reads (and the\n// evaluator's `key`) — for x-on-load, \"\" and the object itself.\ninterface ListenerSource {\n label: string;\n key: string;\n load: boolean;\n}\n\ninterface BoundListener {\n listener: ChangeListener;\n source: ListenerSource;\n}\n\ntype ListName = \"hide\" | \"show\" | \"enable\" | \"disable\" | \"require\" | \"optional\" | \"reset\";\n\n// Actions that write values or required-ness: they act on sibling keys only\n// (never a path), and have no place in x-on-load, which only derives state.\nconst LOCAL_ACTIONS: (\"require\" | \"optional\" | \"reset\" | \"set\")[] = [\"require\", \"optional\", \"reset\", \"set\"];\n\nconst STATE_FLAGS: [ListName, \"x-hidden\" | \"x-disabled\", boolean][] = [\n [\"hide\", \"x-hidden\", true],\n [\"show\", \"x-hidden\", false],\n [\"disable\", \"x-disabled\", true],\n [\"enable\", \"x-disabled\", false],\n];\n\nconst CONTRADICTIONS: [ListName, ListName][] = [\n [\"hide\", \"show\"],\n [\"enable\", \"disable\"],\n [\"require\", \"optional\"],\n];\n\nconst LIST_NAMES: ListName[] = [\"hide\", \"show\", \"enable\", \"disable\", \"require\", \"optional\", \"reset\"];\n\n// Keywords a `patch` may not set, with the tool that does the job instead.\nconst PATCH_DENIED: Record<string, string> = {\n ...Object.fromEntries(\n [\"type\", \"properties\", \"items\", \"additionalProperties\", \"patternProperties\", \"allOf\", \"anyOf\", \"oneOf\", \"if\", \"then\", \"else\", \"not\", \"$ref\", \"$defs\"].map(\n (keyword) => [keyword, \"it changes the field's shape; use an allOf branch\"],\n ),\n ),\n required: \"use require/optional\",\n default: \"a patch changes presentation, not values; use set/reset\",\n const: \"a patch changes presentation, not values; use set/reset\",\n \"x-on-change\": \"listeners cannot be patched in\",\n \"x-on-load\": \"listeners cannot be patched in\",\n};\n\n// applyListenerState is effectiveProperties plus the state actions of every\n// listener, evaluated against the current value: first the object's\n// `x-on-load` listeners, then each property's `x-on-change` listeners — load,\n// then change, the order the events happen in. A listener is applied after\n// `allOf`, so it wins over a branch; later listeners win over earlier ones. A\n// target the current shape does not declare stays absent. Property schemas are\n// cloned, never mutated.\nexport function applyListenerState(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n options: ListenerOptions,\n): EffectiveProperties {\n const { properties, required } = effectiveProperties(schema, value);\n const requiredSet = new Set(required);\n const known = declaredKeys(schema);\n const bound: BoundListener[] = [\n ...loadListenersOf(schema, value),\n ...Object.entries(properties).flatMap(([key, prop]) =>\n listenersOf(key, prop).map((listener) => ({ listener, source: changeSource(key) })),\n ),\n ];\n for (const { listener, source } of bound) {\n const actions = selectActions({ listener, source, self: value, known, options });\n for (const [name, keyword, flag] of STATE_FLAGS) {\n for (const target of list(actions, name)) {\n patchTarget({ properties, value, target, apply: (leaf) => hiddenBy({ ...leaf, [keyword]: flag }, keyword, flag, source.label) });\n }\n }\n for (const target of list(actions, \"require\")) {\n if (properties[target]) requiredSet.add(target);\n }\n for (const target of list(actions, \"optional\")) requiredSet.delete(target);\n for (const [target, keywords] of Object.entries(actions.patch ?? {})) {\n patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, ...keywords }) });\n }\n }\n return { properties, required: [...requiredSet] };\n}\n\n// hiddenBy records which listener hid a field (`x-hidden-by`), so the form's\n// debug mode can say why it is missing; a show clears it.\nfunction hiddenBy(leaf: JsonSchemaProperty, keyword: string, flag: boolean, label: string): JsonSchemaProperty {\n if (keyword !== \"x-hidden\") return leaf;\n if (flag) return { ...leaf, \"x-hidden-by\": label };\n const { \"x-hidden-by\": _by, ...shown } = leaf;\n return shown;\n}\n\n// loadListenersOf collects an object's `x-on-load` listeners in order: the\n// schema's own, then each `allOf` member's — an unconditional member's own, or\n// those of the `then`/`else` branch that applies, selected exactly as\n// effectiveProperties selects the branch it merges.\nfunction loadListenersOf(schema: JsonSchemaObject, value: Record<string, unknown>): BoundListener[] {\n const bound = loadListenersAt(schema[\"x-on-load\"], \"#/x-on-load\");\n for (const [index, clause] of (schema.allOf ?? []).entries()) {\n if (clause.if === undefined && clause.then === undefined) {\n bound.push(...loadListenersAt(clause[\"x-on-load\"], `#/allOf/${index}/x-on-load`));\n continue;\n }\n const branch = matchesIf(clause.if, value) ? \"then\" : \"else\";\n bound.push(...loadListenersAt(clause[branch]?.[\"x-on-load\"], `#/allOf/${index}/${branch}/x-on-load`));\n }\n return bound;\n}\n\nfunction loadListenersAt(listeners: unknown, pointer: string): BoundListener[] {\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`x-on-load at ${pointer} must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners.map((listener: ChangeListener, index) => ({\n listener,\n source: { label: `x-on-load at ${pointer}/${index}`, key: \"\", load: true },\n }));\n}\n\nfunction changeSource(key: string): ListenerSource {\n return { label: `x-on-change on \"${key}\"`, key, load: false };\n}\n\n// applyChangeEffects commits `next` at `key` and runs the value actions\n// (reset/set) of that key's listeners against the post-edit object. A target\n// whose value actually changes fires its own listeners in turn; each key fires\n// at most once per commit, so a cycle ends. When `root` is the edited object\n// itself (the top level), expressions see the post-edit value as root too.\nexport function applyChangeEffects(\n schema: JsonSchemaObject,\n edit: ListenerOptions & { value: Record<string, unknown>; key: string; next: unknown },\n): Record<string, unknown> {\n let current: Record<string, unknown> = { ...edit.value, [edit.key]: edit.next };\n const known = declaredKeys(schema);\n const fired = new Set<string>();\n const queue = [edit.key];\n for (let source = queue.shift(); source !== undefined; source = queue.shift()) {\n if (fired.has(source)) continue;\n fired.add(source);\n const { properties } = effectiveProperties(schema, current);\n const options: ListenerOptions = {\n root: edit.root === edit.value ? current : edit.root,\n ...(edit.evaluate ? { evaluate: edit.evaluate } : {}),\n };\n for (const listener of listenersOf(source, properties[source])) {\n const actions = selectActions({ listener, source: changeSource(source), self: current, known, options });\n for (const [target, nextValue] of valueChanges(actions, properties)) {\n if (Object.is(current[target], nextValue)) continue;\n current = { ...current };\n if (nextValue === undefined) delete current[target];\n else current[target] = nextValue;\n queue.push(target);\n }\n }\n }\n return current;\n}\n\nfunction valueChanges(\n actions: ChangeActions,\n properties: Record<string, JsonSchemaProperty>,\n): [string, unknown][] {\n return [\n ...list(actions, \"reset\").map((target): [string, unknown] => {\n const fallback = properties[target]?.default;\n return [target, fallback === undefined ? undefined : cloneSchemaDefault(fallback)];\n }),\n ...Object.entries(actions.set ?? {}).map(([target, v]): [string, unknown] => [target, cloneSchemaDefault(v)]),\n ];\n}\n\nfunction listenersOf(key: string, prop: JsonSchemaProperty | undefined): ChangeListener[] {\n const listeners = prop?.[\"x-on-change\"];\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`\"${key}\": x-on-change must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners;\n}\n\n// selectActions validates both branches of a listener (so a schema error\n// surfaces whichever branch is live) and returns the one that applies now.\nfunction selectActions({\n listener,\n source,\n self,\n known,\n options,\n}: {\n listener: ChangeListener;\n source: ListenerSource;\n self: Record<string, unknown>;\n known: Set<string>;\n options: ListenerOptions;\n}): ChangeActions {\n validateActions(source, listener, known);\n if (listener.else) validateActions(source, listener.else, known);\n return listenerHolds(listener, source, self, options) ? listener : (listener.else ?? {});\n}\n\n// listenerHolds evaluates `when` against the source's subject: the property's\n// value for x-on-change, the object itself for x-on-load.\nfunction listenerHolds(\n listener: ChangeListener,\n { label, key, load }: ListenerSource,\n self: Record<string, unknown>,\n options: ListenerOptions,\n): boolean {\n if (listener.when === undefined) return true;\n const { expr, ...predicate } = listener.when;\n const hasPredicate = Object.keys(predicate).length > 0;\n const subject = load ? self : self[key];\n if (!hasPredicate && expr === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate`);\n }\n if (expr !== undefined && typeof expr !== \"string\") {\n throw new Error(`${label}: when.expr must be a string, got ${typeof expr}`);\n }\n if (expr !== undefined && !options.evaluate) {\n throw new Error(`${label}: when.expr \"${expr}\" needs the form's expressionEvaluator`);\n }\n if (hasPredicate) {\n const holds = evaluatePredicate(predicate, subject);\n if (holds === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate (${JSON.stringify(predicate)})`);\n }\n if (!holds) return false;\n }\n if (expr === undefined || !options.evaluate) return true;\n const result: unknown = options.evaluate({ expr, key, value: subject, self, root: options.root });\n if (typeof result !== \"boolean\") {\n throw new Error(`${label}: expressionEvaluator returned ${typeof result} for \"${expr}\", expected boolean`);\n }\n return result;\n}\n\nfunction validateActions(source: ListenerSource, actions: ChangeActions, known: Set<string>): void {\n const { label } = source;\n if (actions.set !== undefined && !isPlainObject(actions.set)) {\n throw new Error(`${label}: set must be an object of target → value`);\n }\n if (source.load) {\n const local = LOCAL_ACTIONS.find((name) => actions[name] !== undefined);\n if (local) {\n throw new Error(`${label}: ${local} is not allowed in x-on-load, which only derives state (hide/show/enable/disable/patch)`);\n }\n }\n const setKeys = Object.keys(actions.set ?? {});\n for (const name of LOCAL_ACTIONS) {\n const targets = name === \"set\" ? setKeys : list(actions, name);\n const path = targets.find(isPathTarget);\n if (path !== undefined) {\n throw new Error(`${label}: ${name} \"${path}\" cannot take a path; value and required actions act on sibling keys only`);\n }\n }\n for (const target of [...LIST_NAMES.flatMap((name) => list(actions, name)), ...setKeys]) {\n validateTarget(label, target, known);\n }\n const pairs: [string, string[], string, string[]][] = [\n ...CONTRADICTIONS.map(([a, b]): [string, string[], string, string[]] => [a, list(actions, a), b, list(actions, b)]),\n [\"reset\", list(actions, \"reset\"), \"set\", setKeys],\n ];\n for (const [a, left, b, right] of pairs) {\n const clash = left.find((target) => right.includes(target));\n if (clash !== undefined) {\n throw new Error(`${label}: both ${a} and ${b} \"${clash}\"`);\n }\n }\n validatePatch(label, actions, known);\n}\n\n// validateTarget checks a target's grammar and that its first segment is a key\n// the schema declares in some branch.\nfunction validateTarget(label: string, target: string, known: Set<string>): void {\n if (isPathTarget(target) && known.has(target)) {\n throw new Error(`${label}: target \"${target}\" is both a declared key and a path`);\n }\n const [first = \"\"] = targetSegments(label, target);\n if (!known.has(first)) throw new Error(`${label}: unknown target \"${target}\"`);\n}\n\n// validatePatch checks a `patch`: an object of keyword objects on known\n// targets, no denied keyword, and no keyword a verb in the same actions sets.\nfunction validatePatch(label: string, actions: ChangeActions, known: Set<string>): void {\n const patch: unknown = actions.patch;\n if (patch === undefined) return;\n if (!isPlainObject(patch)) {\n throw new Error(`${label}: patch must be an object of target → keywords`);\n }\n for (const [target, keywords] of Object.entries(patch)) {\n validateTarget(label, target, known);\n if (!isPlainObject(keywords)) {\n throw new Error(`${label}: patch \"${target}\" must be an object of keywords`);\n }\n for (const keyword of Object.keys(keywords)) {\n const denied = PATCH_DENIED[keyword];\n if (denied) throw new Error(`${label}: patch \"${target}\" may not set ${keyword} (${denied})`);\n }\n for (const [verb, keyword] of STATE_FLAGS) {\n if (keyword in keywords && list(actions, verb).includes(target)) {\n throw new Error(`${label}: both ${verb} and patch ${keyword} on \"${target}\"`);\n }\n }\n }\n}\n\nfunction list(actions: ChangeActions, name: ListName): string[] {\n const targets = actions[name];\n if (targets === undefined) return [];\n if (!Array.isArray(targets)) {\n throw new Error(`x-on-change: ${name} must be an array of property keys, got ${typeof targets}`);\n }\n return targets;\n}\n\n// Every key the schema can declare in any branch — a listener may target a\n// field that only exists while some `allOf` branch is live.\nfunction declaredKeys(schema: JsonSchemaObject): Set<string> {\n const keys = new Set(Object.keys(schema.properties ?? {}));\n for (const clause of schema.allOf ?? []) {\n for (const branch of [clause, clause.then, clause.else]) {\n for (const key of Object.keys(branch?.properties ?? {})) keys.add(key);\n }\n }\n return keys;\n}\n"],"names":["effectiveProperties","patchTarget","matchesIf","cloneSchemaDefault","evaluatePredicate","isPlainObject","isPathTarget","targetSegments"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-listeners.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-listeners.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,KAAK,EAGV,mBAAmB,EACnB,gBAAgB,EAEjB,MAAM,0BAA0B,CAAC;AAOlC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AA0DD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,eAAe,GACvB,mBAAmB,CA0BrB;
|
|
1
|
+
{"version":3,"file":"json-schema-form-listeners.d.ts","sourceRoot":"","sources":["../../src/components/json-schema-form-listeners.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,KAAK,EAGV,mBAAmB,EACnB,gBAAgB,EAEjB,MAAM,0BAA0B,CAAC;AAOlC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AA0DD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,eAAe,GACvB,mBAAmB,CA0BrB;AAgDD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GACrF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBzB"}
|
|
@@ -41,7 +41,7 @@ function applyListenerState(schema, value, options) {
|
|
|
41
41
|
const actions = selectActions({ listener, source, self: value, known, options });
|
|
42
42
|
for (const [name, keyword, flag] of STATE_FLAGS) {
|
|
43
43
|
for (const target of list(actions, name)) {
|
|
44
|
-
patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, [keyword]: flag }) });
|
|
44
|
+
patchTarget({ properties, value, target, apply: (leaf) => hiddenBy({ ...leaf, [keyword]: flag }, keyword, flag, source.label) });
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
for (const target of list(actions, "require")) {
|
|
@@ -54,6 +54,12 @@ function applyListenerState(schema, value, options) {
|
|
|
54
54
|
}
|
|
55
55
|
return { properties, required: [...requiredSet] };
|
|
56
56
|
}
|
|
57
|
+
function hiddenBy(leaf, keyword, flag, label) {
|
|
58
|
+
if (keyword !== "x-hidden") return leaf;
|
|
59
|
+
if (flag) return { ...leaf, "x-hidden-by": label };
|
|
60
|
+
const { "x-hidden-by": _by, ...shown } = leaf;
|
|
61
|
+
return shown;
|
|
62
|
+
}
|
|
57
63
|
function loadListenersOf(schema, value) {
|
|
58
64
|
var _a;
|
|
59
65
|
const bound = loadListenersAt(schema["x-on-load"], "#/x-on-load");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-schema-form-listeners.js","sources":["../../src/components/json-schema-form-listeners.ts"],"sourcesContent":["import { isPlainObject } from \"../lib/collections\";\nimport {\n effectiveProperties,\n evaluatePredicate,\n matchesIf,\n type EffectiveProperties,\n} from \"./json-schema-form-conditionals\";\nimport { cloneSchemaDefault } from \"./json-schema-form-defaults\";\nimport { isPathTarget, patchTarget, targetSegments } from \"./json-schema-form-listener-paths\";\nimport type {\n ChangeActions,\n ChangeListener,\n ExpressionEvaluator,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// `x-on-change` listeners: a property names what happens to its siblings when\n// its value is, or becomes, something. `x-on-load` listeners: an object names\n// the state its properties start in. See ChangeActions for the split between\n// derived state actions and transitional value actions.\n\nexport interface ListenerOptions {\n root: Record<string, unknown>;\n evaluate?: ExpressionEvaluator;\n}\n\n// ListenerSource says where a listener came from. `label` prefixes every error\n// it raises; `key` is the property whose value `when` reads (and the\n// evaluator's `key`) — for x-on-load, \"\" and the object itself.\ninterface ListenerSource {\n label: string;\n key: string;\n load: boolean;\n}\n\ninterface BoundListener {\n listener: ChangeListener;\n source: ListenerSource;\n}\n\ntype ListName = \"hide\" | \"show\" | \"enable\" | \"disable\" | \"require\" | \"optional\" | \"reset\";\n\n// Actions that write values or required-ness: they act on sibling keys only\n// (never a path), and have no place in x-on-load, which only derives state.\nconst LOCAL_ACTIONS: (\"require\" | \"optional\" | \"reset\" | \"set\")[] = [\"require\", \"optional\", \"reset\", \"set\"];\n\nconst STATE_FLAGS: [ListName, \"x-hidden\" | \"x-disabled\", boolean][] = [\n [\"hide\", \"x-hidden\", true],\n [\"show\", \"x-hidden\", false],\n [\"disable\", \"x-disabled\", true],\n [\"enable\", \"x-disabled\", false],\n];\n\nconst CONTRADICTIONS: [ListName, ListName][] = [\n [\"hide\", \"show\"],\n [\"enable\", \"disable\"],\n [\"require\", \"optional\"],\n];\n\nconst LIST_NAMES: ListName[] = [\"hide\", \"show\", \"enable\", \"disable\", \"require\", \"optional\", \"reset\"];\n\n// Keywords a `patch` may not set, with the tool that does the job instead.\nconst PATCH_DENIED: Record<string, string> = {\n ...Object.fromEntries(\n [\"type\", \"properties\", \"items\", \"additionalProperties\", \"patternProperties\", \"allOf\", \"anyOf\", \"oneOf\", \"if\", \"then\", \"else\", \"not\", \"$ref\", \"$defs\"].map(\n (keyword) => [keyword, \"it changes the field's shape; use an allOf branch\"],\n ),\n ),\n required: \"use require/optional\",\n default: \"a patch changes presentation, not values; use set/reset\",\n const: \"a patch changes presentation, not values; use set/reset\",\n \"x-on-change\": \"listeners cannot be patched in\",\n \"x-on-load\": \"listeners cannot be patched in\",\n};\n\n// applyListenerState is effectiveProperties plus the state actions of every\n// listener, evaluated against the current value: first the object's\n// `x-on-load` listeners, then each property's `x-on-change` listeners — load,\n// then change, the order the events happen in. A listener is applied after\n// `allOf`, so it wins over a branch; later listeners win over earlier ones. A\n// target the current shape does not declare stays absent. Property schemas are\n// cloned, never mutated.\nexport function applyListenerState(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n options: ListenerOptions,\n): EffectiveProperties {\n const { properties, required } = effectiveProperties(schema, value);\n const requiredSet = new Set(required);\n const known = declaredKeys(schema);\n const bound: BoundListener[] = [\n ...loadListenersOf(schema, value),\n ...Object.entries(properties).flatMap(([key, prop]) =>\n listenersOf(key, prop).map((listener) => ({ listener, source: changeSource(key) })),\n ),\n ];\n for (const { listener, source } of bound) {\n const actions = selectActions({ listener, source, self: value, known, options });\n for (const [name, keyword, flag] of STATE_FLAGS) {\n for (const target of list(actions, name)) {\n patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, [keyword]: flag }) });\n }\n }\n for (const target of list(actions, \"require\")) {\n if (properties[target]) requiredSet.add(target);\n }\n for (const target of list(actions, \"optional\")) requiredSet.delete(target);\n for (const [target, keywords] of Object.entries(actions.patch ?? {})) {\n patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, ...keywords }) });\n }\n }\n return { properties, required: [...requiredSet] };\n}\n\n// loadListenersOf collects an object's `x-on-load` listeners in order: the\n// schema's own, then each `allOf` member's — an unconditional member's own, or\n// those of the `then`/`else` branch that applies, selected exactly as\n// effectiveProperties selects the branch it merges.\nfunction loadListenersOf(schema: JsonSchemaObject, value: Record<string, unknown>): BoundListener[] {\n const bound = loadListenersAt(schema[\"x-on-load\"], \"#/x-on-load\");\n for (const [index, clause] of (schema.allOf ?? []).entries()) {\n if (clause.if === undefined && clause.then === undefined) {\n bound.push(...loadListenersAt(clause[\"x-on-load\"], `#/allOf/${index}/x-on-load`));\n continue;\n }\n const branch = matchesIf(clause.if, value) ? \"then\" : \"else\";\n bound.push(...loadListenersAt(clause[branch]?.[\"x-on-load\"], `#/allOf/${index}/${branch}/x-on-load`));\n }\n return bound;\n}\n\nfunction loadListenersAt(listeners: unknown, pointer: string): BoundListener[] {\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`x-on-load at ${pointer} must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners.map((listener: ChangeListener, index) => ({\n listener,\n source: { label: `x-on-load at ${pointer}/${index}`, key: \"\", load: true },\n }));\n}\n\nfunction changeSource(key: string): ListenerSource {\n return { label: `x-on-change on \"${key}\"`, key, load: false };\n}\n\n// applyChangeEffects commits `next` at `key` and runs the value actions\n// (reset/set) of that key's listeners against the post-edit object. A target\n// whose value actually changes fires its own listeners in turn; each key fires\n// at most once per commit, so a cycle ends. When `root` is the edited object\n// itself (the top level), expressions see the post-edit value as root too.\nexport function applyChangeEffects(\n schema: JsonSchemaObject,\n edit: ListenerOptions & { value: Record<string, unknown>; key: string; next: unknown },\n): Record<string, unknown> {\n let current: Record<string, unknown> = { ...edit.value, [edit.key]: edit.next };\n const known = declaredKeys(schema);\n const fired = new Set<string>();\n const queue = [edit.key];\n for (let source = queue.shift(); source !== undefined; source = queue.shift()) {\n if (fired.has(source)) continue;\n fired.add(source);\n const { properties } = effectiveProperties(schema, current);\n const options: ListenerOptions = {\n root: edit.root === edit.value ? current : edit.root,\n ...(edit.evaluate ? { evaluate: edit.evaluate } : {}),\n };\n for (const listener of listenersOf(source, properties[source])) {\n const actions = selectActions({ listener, source: changeSource(source), self: current, known, options });\n for (const [target, nextValue] of valueChanges(actions, properties)) {\n if (Object.is(current[target], nextValue)) continue;\n current = { ...current };\n if (nextValue === undefined) delete current[target];\n else current[target] = nextValue;\n queue.push(target);\n }\n }\n }\n return current;\n}\n\nfunction valueChanges(\n actions: ChangeActions,\n properties: Record<string, JsonSchemaProperty>,\n): [string, unknown][] {\n return [\n ...list(actions, \"reset\").map((target): [string, unknown] => {\n const fallback = properties[target]?.default;\n return [target, fallback === undefined ? undefined : cloneSchemaDefault(fallback)];\n }),\n ...Object.entries(actions.set ?? {}).map(([target, v]): [string, unknown] => [target, cloneSchemaDefault(v)]),\n ];\n}\n\nfunction listenersOf(key: string, prop: JsonSchemaProperty | undefined): ChangeListener[] {\n const listeners = prop?.[\"x-on-change\"];\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`\"${key}\": x-on-change must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners;\n}\n\n// selectActions validates both branches of a listener (so a schema error\n// surfaces whichever branch is live) and returns the one that applies now.\nfunction selectActions({\n listener,\n source,\n self,\n known,\n options,\n}: {\n listener: ChangeListener;\n source: ListenerSource;\n self: Record<string, unknown>;\n known: Set<string>;\n options: ListenerOptions;\n}): ChangeActions {\n validateActions(source, listener, known);\n if (listener.else) validateActions(source, listener.else, known);\n return listenerHolds(listener, source, self, options) ? listener : (listener.else ?? {});\n}\n\n// listenerHolds evaluates `when` against the source's subject: the property's\n// value for x-on-change, the object itself for x-on-load.\nfunction listenerHolds(\n listener: ChangeListener,\n { label, key, load }: ListenerSource,\n self: Record<string, unknown>,\n options: ListenerOptions,\n): boolean {\n if (listener.when === undefined) return true;\n const { expr, ...predicate } = listener.when;\n const hasPredicate = Object.keys(predicate).length > 0;\n const subject = load ? self : self[key];\n if (!hasPredicate && expr === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate`);\n }\n if (expr !== undefined && typeof expr !== \"string\") {\n throw new Error(`${label}: when.expr must be a string, got ${typeof expr}`);\n }\n if (expr !== undefined && !options.evaluate) {\n throw new Error(`${label}: when.expr \"${expr}\" needs the form's expressionEvaluator`);\n }\n if (hasPredicate) {\n const holds = evaluatePredicate(predicate, subject);\n if (holds === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate (${JSON.stringify(predicate)})`);\n }\n if (!holds) return false;\n }\n if (expr === undefined || !options.evaluate) return true;\n const result: unknown = options.evaluate({ expr, key, value: subject, self, root: options.root });\n if (typeof result !== \"boolean\") {\n throw new Error(`${label}: expressionEvaluator returned ${typeof result} for \"${expr}\", expected boolean`);\n }\n return result;\n}\n\nfunction validateActions(source: ListenerSource, actions: ChangeActions, known: Set<string>): void {\n const { label } = source;\n if (actions.set !== undefined && !isPlainObject(actions.set)) {\n throw new Error(`${label}: set must be an object of target → value`);\n }\n if (source.load) {\n const local = LOCAL_ACTIONS.find((name) => actions[name] !== undefined);\n if (local) {\n throw new Error(`${label}: ${local} is not allowed in x-on-load, which only derives state (hide/show/enable/disable/patch)`);\n }\n }\n const setKeys = Object.keys(actions.set ?? {});\n for (const name of LOCAL_ACTIONS) {\n const targets = name === \"set\" ? setKeys : list(actions, name);\n const path = targets.find(isPathTarget);\n if (path !== undefined) {\n throw new Error(`${label}: ${name} \"${path}\" cannot take a path; value and required actions act on sibling keys only`);\n }\n }\n for (const target of [...LIST_NAMES.flatMap((name) => list(actions, name)), ...setKeys]) {\n validateTarget(label, target, known);\n }\n const pairs: [string, string[], string, string[]][] = [\n ...CONTRADICTIONS.map(([a, b]): [string, string[], string, string[]] => [a, list(actions, a), b, list(actions, b)]),\n [\"reset\", list(actions, \"reset\"), \"set\", setKeys],\n ];\n for (const [a, left, b, right] of pairs) {\n const clash = left.find((target) => right.includes(target));\n if (clash !== undefined) {\n throw new Error(`${label}: both ${a} and ${b} \"${clash}\"`);\n }\n }\n validatePatch(label, actions, known);\n}\n\n// validateTarget checks a target's grammar and that its first segment is a key\n// the schema declares in some branch.\nfunction validateTarget(label: string, target: string, known: Set<string>): void {\n if (isPathTarget(target) && known.has(target)) {\n throw new Error(`${label}: target \"${target}\" is both a declared key and a path`);\n }\n const [first = \"\"] = targetSegments(label, target);\n if (!known.has(first)) throw new Error(`${label}: unknown target \"${target}\"`);\n}\n\n// validatePatch checks a `patch`: an object of keyword objects on known\n// targets, no denied keyword, and no keyword a verb in the same actions sets.\nfunction validatePatch(label: string, actions: ChangeActions, known: Set<string>): void {\n const patch: unknown = actions.patch;\n if (patch === undefined) return;\n if (!isPlainObject(patch)) {\n throw new Error(`${label}: patch must be an object of target → keywords`);\n }\n for (const [target, keywords] of Object.entries(patch)) {\n validateTarget(label, target, known);\n if (!isPlainObject(keywords)) {\n throw new Error(`${label}: patch \"${target}\" must be an object of keywords`);\n }\n for (const keyword of Object.keys(keywords)) {\n const denied = PATCH_DENIED[keyword];\n if (denied) throw new Error(`${label}: patch \"${target}\" may not set ${keyword} (${denied})`);\n }\n for (const [verb, keyword] of STATE_FLAGS) {\n if (keyword in keywords && list(actions, verb).includes(target)) {\n throw new Error(`${label}: both ${verb} and patch ${keyword} on \"${target}\"`);\n }\n }\n }\n}\n\nfunction list(actions: ChangeActions, name: ListName): string[] {\n const targets = actions[name];\n if (targets === undefined) return [];\n if (!Array.isArray(targets)) {\n throw new Error(`x-on-change: ${name} must be an array of property keys, got ${typeof targets}`);\n }\n return targets;\n}\n\n// Every key the schema can declare in any branch — a listener may target a\n// field that only exists while some `allOf` branch is live.\nfunction declaredKeys(schema: JsonSchemaObject): Set<string> {\n const keys = new Set(Object.keys(schema.properties ?? {}));\n for (const clause of schema.allOf ?? []) {\n for (const branch of [clause, clause.then, clause.else]) {\n for (const key of Object.keys(branch?.properties ?? {})) keys.add(key);\n }\n }\n return keys;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"json-schema-form-listeners.js","sources":["../../src/components/json-schema-form-listeners.ts"],"sourcesContent":["import { isPlainObject } from \"../lib/collections\";\nimport {\n effectiveProperties,\n evaluatePredicate,\n matchesIf,\n type EffectiveProperties,\n} from \"./json-schema-form-conditionals\";\nimport { cloneSchemaDefault } from \"./json-schema-form-defaults\";\nimport { isPathTarget, patchTarget, targetSegments } from \"./json-schema-form-listener-paths\";\nimport type {\n ChangeActions,\n ChangeListener,\n ExpressionEvaluator,\n JsonSchemaObject,\n JsonSchemaProperty,\n} from \"./json-schema-form-types\";\n\n// `x-on-change` listeners: a property names what happens to its siblings when\n// its value is, or becomes, something. `x-on-load` listeners: an object names\n// the state its properties start in. See ChangeActions for the split between\n// derived state actions and transitional value actions.\n\nexport interface ListenerOptions {\n root: Record<string, unknown>;\n evaluate?: ExpressionEvaluator;\n}\n\n// ListenerSource says where a listener came from. `label` prefixes every error\n// it raises; `key` is the property whose value `when` reads (and the\n// evaluator's `key`) — for x-on-load, \"\" and the object itself.\ninterface ListenerSource {\n label: string;\n key: string;\n load: boolean;\n}\n\ninterface BoundListener {\n listener: ChangeListener;\n source: ListenerSource;\n}\n\ntype ListName = \"hide\" | \"show\" | \"enable\" | \"disable\" | \"require\" | \"optional\" | \"reset\";\n\n// Actions that write values or required-ness: they act on sibling keys only\n// (never a path), and have no place in x-on-load, which only derives state.\nconst LOCAL_ACTIONS: (\"require\" | \"optional\" | \"reset\" | \"set\")[] = [\"require\", \"optional\", \"reset\", \"set\"];\n\nconst STATE_FLAGS: [ListName, \"x-hidden\" | \"x-disabled\", boolean][] = [\n [\"hide\", \"x-hidden\", true],\n [\"show\", \"x-hidden\", false],\n [\"disable\", \"x-disabled\", true],\n [\"enable\", \"x-disabled\", false],\n];\n\nconst CONTRADICTIONS: [ListName, ListName][] = [\n [\"hide\", \"show\"],\n [\"enable\", \"disable\"],\n [\"require\", \"optional\"],\n];\n\nconst LIST_NAMES: ListName[] = [\"hide\", \"show\", \"enable\", \"disable\", \"require\", \"optional\", \"reset\"];\n\n// Keywords a `patch` may not set, with the tool that does the job instead.\nconst PATCH_DENIED: Record<string, string> = {\n ...Object.fromEntries(\n [\"type\", \"properties\", \"items\", \"additionalProperties\", \"patternProperties\", \"allOf\", \"anyOf\", \"oneOf\", \"if\", \"then\", \"else\", \"not\", \"$ref\", \"$defs\"].map(\n (keyword) => [keyword, \"it changes the field's shape; use an allOf branch\"],\n ),\n ),\n required: \"use require/optional\",\n default: \"a patch changes presentation, not values; use set/reset\",\n const: \"a patch changes presentation, not values; use set/reset\",\n \"x-on-change\": \"listeners cannot be patched in\",\n \"x-on-load\": \"listeners cannot be patched in\",\n};\n\n// applyListenerState is effectiveProperties plus the state actions of every\n// listener, evaluated against the current value: first the object's\n// `x-on-load` listeners, then each property's `x-on-change` listeners — load,\n// then change, the order the events happen in. A listener is applied after\n// `allOf`, so it wins over a branch; later listeners win over earlier ones. A\n// target the current shape does not declare stays absent. Property schemas are\n// cloned, never mutated.\nexport function applyListenerState(\n schema: JsonSchemaObject,\n value: Record<string, unknown>,\n options: ListenerOptions,\n): EffectiveProperties {\n const { properties, required } = effectiveProperties(schema, value);\n const requiredSet = new Set(required);\n const known = declaredKeys(schema);\n const bound: BoundListener[] = [\n ...loadListenersOf(schema, value),\n ...Object.entries(properties).flatMap(([key, prop]) =>\n listenersOf(key, prop).map((listener) => ({ listener, source: changeSource(key) })),\n ),\n ];\n for (const { listener, source } of bound) {\n const actions = selectActions({ listener, source, self: value, known, options });\n for (const [name, keyword, flag] of STATE_FLAGS) {\n for (const target of list(actions, name)) {\n patchTarget({ properties, value, target, apply: (leaf) => hiddenBy({ ...leaf, [keyword]: flag }, keyword, flag, source.label) });\n }\n }\n for (const target of list(actions, \"require\")) {\n if (properties[target]) requiredSet.add(target);\n }\n for (const target of list(actions, \"optional\")) requiredSet.delete(target);\n for (const [target, keywords] of Object.entries(actions.patch ?? {})) {\n patchTarget({ properties, value, target, apply: (leaf) => ({ ...leaf, ...keywords }) });\n }\n }\n return { properties, required: [...requiredSet] };\n}\n\n// hiddenBy records which listener hid a field (`x-hidden-by`), so the form's\n// debug mode can say why it is missing; a show clears it.\nfunction hiddenBy(leaf: JsonSchemaProperty, keyword: string, flag: boolean, label: string): JsonSchemaProperty {\n if (keyword !== \"x-hidden\") return leaf;\n if (flag) return { ...leaf, \"x-hidden-by\": label };\n const { \"x-hidden-by\": _by, ...shown } = leaf;\n return shown;\n}\n\n// loadListenersOf collects an object's `x-on-load` listeners in order: the\n// schema's own, then each `allOf` member's — an unconditional member's own, or\n// those of the `then`/`else` branch that applies, selected exactly as\n// effectiveProperties selects the branch it merges.\nfunction loadListenersOf(schema: JsonSchemaObject, value: Record<string, unknown>): BoundListener[] {\n const bound = loadListenersAt(schema[\"x-on-load\"], \"#/x-on-load\");\n for (const [index, clause] of (schema.allOf ?? []).entries()) {\n if (clause.if === undefined && clause.then === undefined) {\n bound.push(...loadListenersAt(clause[\"x-on-load\"], `#/allOf/${index}/x-on-load`));\n continue;\n }\n const branch = matchesIf(clause.if, value) ? \"then\" : \"else\";\n bound.push(...loadListenersAt(clause[branch]?.[\"x-on-load\"], `#/allOf/${index}/${branch}/x-on-load`));\n }\n return bound;\n}\n\nfunction loadListenersAt(listeners: unknown, pointer: string): BoundListener[] {\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`x-on-load at ${pointer} must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners.map((listener: ChangeListener, index) => ({\n listener,\n source: { label: `x-on-load at ${pointer}/${index}`, key: \"\", load: true },\n }));\n}\n\nfunction changeSource(key: string): ListenerSource {\n return { label: `x-on-change on \"${key}\"`, key, load: false };\n}\n\n// applyChangeEffects commits `next` at `key` and runs the value actions\n// (reset/set) of that key's listeners against the post-edit object. A target\n// whose value actually changes fires its own listeners in turn; each key fires\n// at most once per commit, so a cycle ends. When `root` is the edited object\n// itself (the top level), expressions see the post-edit value as root too.\nexport function applyChangeEffects(\n schema: JsonSchemaObject,\n edit: ListenerOptions & { value: Record<string, unknown>; key: string; next: unknown },\n): Record<string, unknown> {\n let current: Record<string, unknown> = { ...edit.value, [edit.key]: edit.next };\n const known = declaredKeys(schema);\n const fired = new Set<string>();\n const queue = [edit.key];\n for (let source = queue.shift(); source !== undefined; source = queue.shift()) {\n if (fired.has(source)) continue;\n fired.add(source);\n const { properties } = effectiveProperties(schema, current);\n const options: ListenerOptions = {\n root: edit.root === edit.value ? current : edit.root,\n ...(edit.evaluate ? { evaluate: edit.evaluate } : {}),\n };\n for (const listener of listenersOf(source, properties[source])) {\n const actions = selectActions({ listener, source: changeSource(source), self: current, known, options });\n for (const [target, nextValue] of valueChanges(actions, properties)) {\n if (Object.is(current[target], nextValue)) continue;\n current = { ...current };\n if (nextValue === undefined) delete current[target];\n else current[target] = nextValue;\n queue.push(target);\n }\n }\n }\n return current;\n}\n\nfunction valueChanges(\n actions: ChangeActions,\n properties: Record<string, JsonSchemaProperty>,\n): [string, unknown][] {\n return [\n ...list(actions, \"reset\").map((target): [string, unknown] => {\n const fallback = properties[target]?.default;\n return [target, fallback === undefined ? undefined : cloneSchemaDefault(fallback)];\n }),\n ...Object.entries(actions.set ?? {}).map(([target, v]): [string, unknown] => [target, cloneSchemaDefault(v)]),\n ];\n}\n\nfunction listenersOf(key: string, prop: JsonSchemaProperty | undefined): ChangeListener[] {\n const listeners = prop?.[\"x-on-change\"];\n if (listeners === undefined) return [];\n if (!Array.isArray(listeners)) {\n throw new Error(`\"${key}\": x-on-change must be an array of listeners, got ${typeof listeners}`);\n }\n return listeners;\n}\n\n// selectActions validates both branches of a listener (so a schema error\n// surfaces whichever branch is live) and returns the one that applies now.\nfunction selectActions({\n listener,\n source,\n self,\n known,\n options,\n}: {\n listener: ChangeListener;\n source: ListenerSource;\n self: Record<string, unknown>;\n known: Set<string>;\n options: ListenerOptions;\n}): ChangeActions {\n validateActions(source, listener, known);\n if (listener.else) validateActions(source, listener.else, known);\n return listenerHolds(listener, source, self, options) ? listener : (listener.else ?? {});\n}\n\n// listenerHolds evaluates `when` against the source's subject: the property's\n// value for x-on-change, the object itself for x-on-load.\nfunction listenerHolds(\n listener: ChangeListener,\n { label, key, load }: ListenerSource,\n self: Record<string, unknown>,\n options: ListenerOptions,\n): boolean {\n if (listener.when === undefined) return true;\n const { expr, ...predicate } = listener.when;\n const hasPredicate = Object.keys(predicate).length > 0;\n const subject = load ? self : self[key];\n if (!hasPredicate && expr === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate`);\n }\n if (expr !== undefined && typeof expr !== \"string\") {\n throw new Error(`${label}: when.expr must be a string, got ${typeof expr}`);\n }\n if (expr !== undefined && !options.evaluate) {\n throw new Error(`${label}: when.expr \"${expr}\" needs the form's expressionEvaluator`);\n }\n if (hasPredicate) {\n const holds = evaluatePredicate(predicate, subject);\n if (holds === undefined) {\n throw new Error(`${label}: when states nothing it can evaluate (${JSON.stringify(predicate)})`);\n }\n if (!holds) return false;\n }\n if (expr === undefined || !options.evaluate) return true;\n const result: unknown = options.evaluate({ expr, key, value: subject, self, root: options.root });\n if (typeof result !== \"boolean\") {\n throw new Error(`${label}: expressionEvaluator returned ${typeof result} for \"${expr}\", expected boolean`);\n }\n return result;\n}\n\nfunction validateActions(source: ListenerSource, actions: ChangeActions, known: Set<string>): void {\n const { label } = source;\n if (actions.set !== undefined && !isPlainObject(actions.set)) {\n throw new Error(`${label}: set must be an object of target → value`);\n }\n if (source.load) {\n const local = LOCAL_ACTIONS.find((name) => actions[name] !== undefined);\n if (local) {\n throw new Error(`${label}: ${local} is not allowed in x-on-load, which only derives state (hide/show/enable/disable/patch)`);\n }\n }\n const setKeys = Object.keys(actions.set ?? {});\n for (const name of LOCAL_ACTIONS) {\n const targets = name === \"set\" ? setKeys : list(actions, name);\n const path = targets.find(isPathTarget);\n if (path !== undefined) {\n throw new Error(`${label}: ${name} \"${path}\" cannot take a path; value and required actions act on sibling keys only`);\n }\n }\n for (const target of [...LIST_NAMES.flatMap((name) => list(actions, name)), ...setKeys]) {\n validateTarget(label, target, known);\n }\n const pairs: [string, string[], string, string[]][] = [\n ...CONTRADICTIONS.map(([a, b]): [string, string[], string, string[]] => [a, list(actions, a), b, list(actions, b)]),\n [\"reset\", list(actions, \"reset\"), \"set\", setKeys],\n ];\n for (const [a, left, b, right] of pairs) {\n const clash = left.find((target) => right.includes(target));\n if (clash !== undefined) {\n throw new Error(`${label}: both ${a} and ${b} \"${clash}\"`);\n }\n }\n validatePatch(label, actions, known);\n}\n\n// validateTarget checks a target's grammar and that its first segment is a key\n// the schema declares in some branch.\nfunction validateTarget(label: string, target: string, known: Set<string>): void {\n if (isPathTarget(target) && known.has(target)) {\n throw new Error(`${label}: target \"${target}\" is both a declared key and a path`);\n }\n const [first = \"\"] = targetSegments(label, target);\n if (!known.has(first)) throw new Error(`${label}: unknown target \"${target}\"`);\n}\n\n// validatePatch checks a `patch`: an object of keyword objects on known\n// targets, no denied keyword, and no keyword a verb in the same actions sets.\nfunction validatePatch(label: string, actions: ChangeActions, known: Set<string>): void {\n const patch: unknown = actions.patch;\n if (patch === undefined) return;\n if (!isPlainObject(patch)) {\n throw new Error(`${label}: patch must be an object of target → keywords`);\n }\n for (const [target, keywords] of Object.entries(patch)) {\n validateTarget(label, target, known);\n if (!isPlainObject(keywords)) {\n throw new Error(`${label}: patch \"${target}\" must be an object of keywords`);\n }\n for (const keyword of Object.keys(keywords)) {\n const denied = PATCH_DENIED[keyword];\n if (denied) throw new Error(`${label}: patch \"${target}\" may not set ${keyword} (${denied})`);\n }\n for (const [verb, keyword] of STATE_FLAGS) {\n if (keyword in keywords && list(actions, verb).includes(target)) {\n throw new Error(`${label}: both ${verb} and patch ${keyword} on \"${target}\"`);\n }\n }\n }\n}\n\nfunction list(actions: ChangeActions, name: ListName): string[] {\n const targets = actions[name];\n if (targets === undefined) return [];\n if (!Array.isArray(targets)) {\n throw new Error(`x-on-change: ${name} must be an array of property keys, got ${typeof targets}`);\n }\n return targets;\n}\n\n// Every key the schema can declare in any branch — a listener may target a\n// field that only exists while some `allOf` branch is live.\nfunction declaredKeys(schema: JsonSchemaObject): Set<string> {\n const keys = new Set(Object.keys(schema.properties ?? {}));\n for (const clause of schema.allOf ?? []) {\n for (const branch of [clause, clause.then, clause.else]) {\n for (const key of Object.keys(branch?.properties ?? {})) keys.add(key);\n }\n }\n return keys;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -31,6 +31,7 @@ function readPreferences(storageKey) {
|
|
|
31
31
|
if (isFormSize(record.size)) prefs.size = record.size;
|
|
32
32
|
if (isLayoutMode(record.layoutMode)) prefs.layoutMode = record.layoutMode;
|
|
33
33
|
if (isSortMode(record.sortMode)) prefs.sortMode = record.sortMode;
|
|
34
|
+
if (typeof record.debug === "boolean") prefs.debug = record.debug;
|
|
34
35
|
return prefs;
|
|
35
36
|
}
|
|
36
37
|
function writePreferences(storageKey, prefs) {
|