@flanksource/clicky-ui 0.3.40 → 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/README.md +24 -0
- package/dist/ai.cjs +14 -0
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.js +14 -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/AccordionList.cjs +5 -1
- package/dist/components/AccordionList.cjs.map +1 -1
- package/dist/components/AccordionList.d.ts +3 -1
- package/dist/components/AccordionList.d.ts.map +1 -1
- package/dist/components/AccordionList.js +5 -1
- package/dist/components/AccordionList.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 +39 -11
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.d.ts +1 -1
- package/dist/components/JsonSchemaForm.d.ts.map +1 -1
- package/dist/components/JsonSchemaForm.js +38 -10
- 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-accordion-array.cjs +3 -1
- package/dist/components/json-schema-form-accordion-array.cjs.map +1 -1
- package/dist/components/json-schema-form-accordion-array.d.ts +4 -1
- package/dist/components/json-schema-form-accordion-array.d.ts.map +1 -1
- package/dist/components/json-schema-form-accordion-array.js +3 -1
- package/dist/components/json-schema-form-accordion-array.js.map +1 -1
- package/dist/components/json-schema-form-array-view.cjs +63 -0
- package/dist/components/json-schema-form-array-view.cjs.map +1 -0
- package/dist/components/json-schema-form-array-view.d.ts +21 -0
- package/dist/components/json-schema-form-array-view.d.ts.map +1 -0
- package/dist/components/json-schema-form-array-view.js +63 -0
- package/dist/components/json-schema-form-array-view.js.map +1 -0
- package/dist/components/json-schema-form-array.cjs +3 -7
- package/dist/components/json-schema-form-array.cjs.map +1 -1
- package/dist/components/json-schema-form-array.d.ts.map +1 -1
- package/dist/components/json-schema-form-array.js +3 -7
- package/dist/components/json-schema-form-array.js.map +1 -1
- package/dist/components/json-schema-form-conditionals.cjs +67 -0
- package/dist/components/json-schema-form-conditionals.cjs.map +1 -0
- package/dist/components/json-schema-form-conditionals.d.ts +9 -0
- package/dist/components/json-schema-form-conditionals.d.ts.map +1 -0
- package/dist/components/json-schema-form-conditionals.js +67 -0
- package/dist/components/json-schema-form-conditionals.js.map +1 -0
- 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-defaults.cjs +68 -0
- package/dist/components/json-schema-form-defaults.cjs.map +1 -0
- package/dist/components/json-schema-form-defaults.d.ts +4 -0
- package/dist/components/json-schema-form-defaults.d.ts.map +1 -0
- package/dist/components/json-schema-form-defaults.js +68 -0
- package/dist/components/json-schema-form-defaults.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-errors.cjs +49 -31
- package/dist/components/json-schema-form-errors.cjs.map +1 -1
- package/dist/components/json-schema-form-errors.d.ts +4 -2
- package/dist/components/json-schema-form-errors.d.ts.map +1 -1
- package/dist/components/json-schema-form-errors.js +51 -33
- package/dist/components/json-schema-form-errors.js.map +1 -1
- 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-filter.cjs +2 -1
- package/dist/components/json-schema-form-filter.cjs.map +1 -1
- package/dist/components/json-schema-form-filter.js +2 -1
- package/dist/components/json-schema-form-filter.js.map +1 -1
- package/dist/components/json-schema-form-item-summary.cjs +6 -2
- package/dist/components/json-schema-form-item-summary.cjs.map +1 -1
- package/dist/components/json-schema-form-item-summary.d.ts.map +1 -1
- package/dist/components/json-schema-form-item-summary.js +6 -2
- package/dist/components/json-schema-form-item-summary.js.map +1 -1
- package/dist/components/json-schema-form-layout.cjs +28 -19
- package/dist/components/json-schema-form-layout.cjs.map +1 -1
- package/dist/components/json-schema-form-layout.d.ts +8 -6
- package/dist/components/json-schema-form-layout.d.ts.map +1 -1
- package/dist/components/json-schema-form-layout.js +29 -20
- package/dist/components/json-schema-form-layout.js.map +1 -1
- package/dist/components/json-schema-form-listener-paths.cjs +52 -0
- package/dist/components/json-schema-form-listener-paths.cjs.map +1 -0
- package/dist/components/json-schema-form-listener-paths.d.ts +10 -0
- package/dist/components/json-schema-form-listener-paths.d.ts.map +1 -0
- package/dist/components/json-schema-form-listener-paths.js +52 -0
- package/dist/components/json-schema-form-listener-paths.js.map +1 -0
- package/dist/components/json-schema-form-listener-types.d.ts +22 -0
- package/dist/components/json-schema-form-listener-types.d.ts.map +1 -0
- package/dist/components/json-schema-form-listeners.cjs +256 -0
- package/dist/components/json-schema-form-listeners.cjs.map +1 -0
- package/dist/components/json-schema-form-listeners.d.ts +13 -0
- package/dist/components/json-schema-form-listeners.d.ts.map +1 -0
- package/dist/components/json-schema-form-listeners.js +256 -0
- package/dist/components/json-schema-form-listeners.js.map +1 -0
- package/dist/components/json-schema-form-object-array-view.cjs +62 -0
- package/dist/components/json-schema-form-object-array-view.cjs.map +1 -0
- package/dist/components/json-schema-form-object-array-view.d.ts +14 -0
- package/dist/components/json-schema-form-object-array-view.d.ts.map +1 -0
- package/dist/components/json-schema-form-object-array-view.js +62 -0
- package/dist/components/json-schema-form-object-array-view.js.map +1 -0
- package/dist/components/json-schema-form-object.cjs +3 -0
- package/dist/components/json-schema-form-object.cjs.map +1 -1
- package/dist/components/json-schema-form-object.d.ts.map +1 -1
- package/dist/components/json-schema-form-object.js +3 -0
- package/dist/components/json-schema-form-object.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 +36 -12
- 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 +38 -14
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +6 -99
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.d.ts +1 -8
- package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
- package/dist/components/json-schema-form-resolve.js +5 -98
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components/json-schema-form-runtime-types.d.ts +16 -0
- package/dist/components/json-schema-form-runtime-types.d.ts.map +1 -1
- package/dist/components/json-schema-form-table-array.cjs +67 -16
- package/dist/components/json-schema-form-table-array.cjs.map +1 -1
- package/dist/components/json-schema-form-table-array.d.ts +4 -1
- package/dist/components/json-schema-form-table-array.d.ts.map +1 -1
- package/dist/components/json-schema-form-table-array.js +70 -19
- package/dist/components/json-schema-form-table-array.js.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 +17 -0
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components/json-schema-form-utils.cjs +7 -1
- package/dist/components/json-schema-form-utils.cjs.map +1 -1
- package/dist/components/json-schema-form-utils.d.ts +2 -1
- package/dist/components/json-schema-form-utils.d.ts.map +1 -1
- package/dist/components/json-schema-form-utils.js +7 -1
- package/dist/components/json-schema-form-utils.js.map +1 -1
- package/dist/components.cjs +3 -2
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +3 -2
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +2 -1
- package/dist/components.js.map +1 -1
- package/dist/data/DataTable.cjs +9 -3
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +6 -0
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +9 -3
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/FixtureEditor/FixtureEditor.cjs +43 -24
- package/dist/data/FixtureEditor/FixtureEditor.cjs.map +1 -1
- package/dist/data/FixtureEditor/FixtureEditor.d.ts.map +1 -1
- package/dist/data/FixtureEditor/FixtureEditor.js +43 -24
- package/dist/data/FixtureEditor/FixtureEditor.js.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/Tree.cjs +10 -2
- package/dist/data/Tree.cjs.map +1 -1
- package/dist/data/Tree.d.ts +6 -1
- package/dist/data/Tree.d.ts.map +1 -1
- package/dist/data/Tree.js +10 -2
- package/dist/data/Tree.js.map +1 -1
- 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.cjs +143 -167
- package/dist/data/ai/SessionInspector.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.collection-types.d.ts +5 -0
- package/dist/data/ai/SessionInspector.collection-types.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.collection.cjs +18 -5
- package/dist/data/ai/SessionInspector.collection.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.collection.d.ts +2 -0
- package/dist/data/ai/SessionInspector.collection.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.collection.fixtures.d.ts +6 -0
- package/dist/data/ai/SessionInspector.collection.fixtures.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.collection.js +18 -5
- package/dist/data/ai/SessionInspector.collection.js.map +1 -1
- package/dist/data/ai/SessionInspector.d.ts +24 -2
- package/dist/data/ai/SessionInspector.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.hierarchy-state.cjs +105 -7
- package/dist/data/ai/SessionInspector.hierarchy-state.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.hierarchy-state.d.ts +12 -1
- package/dist/data/ai/SessionInspector.hierarchy-state.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.hierarchy-state.js +107 -9
- package/dist/data/ai/SessionInspector.hierarchy-state.js.map +1 -1
- package/dist/data/ai/SessionInspector.hierarchy.cjs +1 -1
- package/dist/data/ai/SessionInspector.hierarchy.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.hierarchy.js +1 -1
- package/dist/data/ai/SessionInspector.hierarchy.js.map +1 -1
- package/dist/data/ai/SessionInspector.js +144 -168
- package/dist/data/ai/SessionInspector.js.map +1 -1
- package/dist/data/ai/SessionInspector.legacy.cjs +116 -0
- package/dist/data/ai/SessionInspector.legacy.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.legacy.d.ts +19 -0
- package/dist/data/ai/SessionInspector.legacy.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.legacy.js +116 -0
- package/dist/data/ai/SessionInspector.legacy.js.map +1 -0
- package/dist/data/ai/SessionInspector.panels.cjs +3 -0
- package/dist/data/ai/SessionInspector.panels.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.panels.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.panels.js +3 -0
- package/dist/data/ai/SessionInspector.panels.js.map +1 -1
- package/dist/data/ai/SessionInspector.plan.cjs +29 -12
- package/dist/data/ai/SessionInspector.plan.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.plan.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.plan.js +30 -13
- package/dist/data/ai/SessionInspector.plan.js.map +1 -1
- package/dist/data/ai/SessionInspector.remote-view.cjs +44 -0
- package/dist/data/ai/SessionInspector.remote-view.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.remote-view.d.ts +11 -0
- package/dist/data/ai/SessionInspector.remote-view.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.remote-view.js +44 -0
- package/dist/data/ai/SessionInspector.remote-view.js.map +1 -0
- package/dist/data/ai/SessionInspector.remote.cjs +275 -0
- package/dist/data/ai/SessionInspector.remote.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.remote.d.ts +57 -0
- package/dist/data/ai/SessionInspector.remote.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.remote.js +275 -0
- package/dist/data/ai/SessionInspector.remote.js.map +1 -0
- package/dist/data/ai/SessionInspector.summary.cjs +9 -159
- package/dist/data/ai/SessionInspector.summary.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.summary.d.ts +0 -3
- package/dist/data/ai/SessionInspector.summary.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.summary.js +11 -161
- package/dist/data/ai/SessionInspector.summary.js.map +1 -1
- package/dist/data/ai/SessionInspector.tab-state.cjs +15 -0
- package/dist/data/ai/SessionInspector.tab-state.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.tab-state.d.ts +3 -0
- package/dist/data/ai/SessionInspector.tab-state.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.tab-state.js +15 -0
- package/dist/data/ai/SessionInspector.tab-state.js.map +1 -0
- package/dist/data/ai/SessionInspector.tabs.model.cjs +31 -18
- package/dist/data/ai/SessionInspector.tabs.model.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.tabs.model.d.ts +3 -1
- package/dist/data/ai/SessionInspector.tabs.model.d.ts.map +1 -1
- package/dist/data/ai/SessionInspector.tabs.model.js +32 -19
- package/dist/data/ai/SessionInspector.tabs.model.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/SessionInspector.verification.cjs +53 -0
- package/dist/data/ai/SessionInspector.verification.cjs.map +1 -0
- package/dist/data/ai/SessionInspector.verification.d.ts +7 -0
- package/dist/data/ai/SessionInspector.verification.d.ts.map +1 -0
- package/dist/data/ai/SessionInspector.verification.js +53 -0
- package/dist/data/ai/SessionInspector.verification.js.map +1 -0
- 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 +7 -1
- package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.model.d.ts +25 -3
- package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.model.js +7 -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 +17 -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 +6 -1
- 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/devtools/useDebugStream.cjs +5 -1
- package/dist/devtools/useDebugStream.cjs.map +1 -1
- package/dist/devtools/useDebugStream.d.ts.map +1 -1
- package/dist/devtools/useDebugStream.js +6 -2
- package/dist/devtools/useDebugStream.js.map +1 -1
- package/dist/hooks/event-source-provider.cjs +9 -0
- package/dist/hooks/event-source-provider.cjs.map +1 -0
- package/dist/hooks/event-source-provider.d.ts +15 -0
- package/dist/hooks/event-source-provider.d.ts.map +1 -0
- package/dist/hooks/event-source-provider.js +9 -0
- package/dist/hooks/event-source-provider.js.map +1 -0
- package/dist/hooks/event-source.cjs +11 -0
- package/dist/hooks/event-source.cjs.map +1 -0
- package/dist/hooks/event-source.d.ts +22 -0
- package/dist/hooks/event-source.d.ts.map +1 -0
- package/dist/hooks/event-source.js +11 -0
- package/dist/hooks/event-source.js.map +1 -0
- package/dist/hooks/use-log-tail.cjs +5 -1
- package/dist/hooks/use-log-tail.cjs.map +1 -1
- package/dist/hooks/use-log-tail.d.ts.map +1 -1
- package/dist/hooks/use-log-tail.js +5 -1
- package/dist/hooks/use-log-tail.js.map +1 -1
- package/dist/hooks/use-prompts.cjs +5 -1
- package/dist/hooks/use-prompts.cjs.map +1 -1
- package/dist/hooks/use-prompts.d.ts.map +1 -1
- package/dist/hooks/use-prompts.js +6 -2
- package/dist/hooks/use-prompts.js.map +1 -1
- package/dist/hooks/use-task-run.cjs +9 -2
- package/dist/hooks/use-task-run.cjs.map +1 -1
- package/dist/hooks/use-task-run.d.ts.map +1 -1
- package/dist/hooks/use-task-run.js +10 -3
- package/dist/hooks/use-task-run.js.map +1 -1
- package/dist/hooks.cjs +4 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +4 -0
- package/dist/hooks.js.map +1 -1
- package/dist/icons/programmingCatalog.cjs +34 -34
- package/dist/icons/programmingCatalog.cjs.map +1 -1
- package/dist/icons/programmingCatalog.js +34 -34
- package/dist/icons/programmingCatalog.js.map +1 -1
- package/dist/index.cjs +14 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/monaco/MonacoEditor.cjs +4 -1
- package/dist/monaco/MonacoEditor.cjs.map +1 -1
- package/dist/monaco/MonacoEditor.d.ts +1 -1
- package/dist/monaco/MonacoEditor.d.ts.map +1 -1
- package/dist/monaco/MonacoEditor.js +4 -1
- package/dist/monaco/MonacoEditor.js.map +1 -1
- package/dist/monaco/types.d.ts +2 -1
- package/dist/monaco/types.d.ts.map +1 -1
- package/dist/overlay/CommandPalette.cjs +14 -4
- package/dist/overlay/CommandPalette.cjs.map +1 -1
- package/dist/overlay/CommandPalette.d.ts +5 -1
- package/dist/overlay/CommandPalette.d.ts.map +1 -1
- package/dist/overlay/CommandPalette.js +14 -4
- package/dist/overlay/CommandPalette.js.map +1 -1
- package/dist/overlay/CommandPaletteList.cjs +5 -0
- package/dist/overlay/CommandPaletteList.cjs.map +1 -1
- package/dist/overlay/CommandPaletteList.d.ts +4 -2
- package/dist/overlay/CommandPaletteList.d.ts.map +1 -1
- package/dist/overlay/CommandPaletteList.js +5 -0
- package/dist/overlay/CommandPaletteList.js.map +1 -1
- package/dist/overlay/DropdownMenu.cjs +2 -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 +2 -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 +32 -27
- package/dist/rpc/OperationCatalog.cjs.map +1 -1
- package/dist/rpc/OperationCatalog.d.ts +11 -1
- package/dist/rpc/OperationCatalog.d.ts.map +1 -1
- package/dist/rpc/OperationCatalog.js +32 -27
- package/dist/rpc/OperationCatalog.js.map +1 -1
- package/dist/rpc/OperationEntityContextPicker.cjs +62 -256
- package/dist/rpc/OperationEntityContextPicker.cjs.map +1 -1
- package/dist/rpc/OperationEntityContextPicker.d.ts.map +1 -1
- package/dist/rpc/OperationEntityContextPicker.js +64 -258
- package/dist/rpc/OperationEntityContextPicker.js.map +1 -1
- package/dist/rpc/OperationEntityPicker.cjs +185 -0
- package/dist/rpc/OperationEntityPicker.cjs.map +1 -0
- package/dist/rpc/OperationEntityPicker.d.ts +51 -0
- package/dist/rpc/OperationEntityPicker.d.ts.map +1 -0
- package/dist/rpc/OperationEntityPicker.js +185 -0
- package/dist/rpc/OperationEntityPicker.js.map +1 -0
- package/dist/rpc/OperationEntityPicker.model.cjs +39 -0
- package/dist/rpc/OperationEntityPicker.model.cjs.map +1 -0
- package/dist/rpc/OperationEntityPicker.model.d.ts +27 -0
- package/dist/rpc/OperationEntityPicker.model.d.ts.map +1 -0
- package/dist/rpc/OperationEntityPicker.model.js +39 -0
- package/dist/rpc/OperationEntityPicker.model.js.map +1 -0
- package/dist/rpc/operationCatalogRowSelection.cjs +85 -0
- package/dist/rpc/operationCatalogRowSelection.cjs.map +1 -0
- package/dist/rpc/operationCatalogRowSelection.d.ts +57 -0
- package/dist/rpc/operationCatalogRowSelection.d.ts.map +1 -0
- package/dist/rpc/operationCatalogRowSelection.js +85 -0
- package/dist/rpc/operationCatalogRowSelection.js.map +1 -0
- package/dist/rpc/operationEntityPicker.fixtures.d.ts +13 -0
- package/dist/rpc/operationEntityPicker.fixtures.d.ts.map +1 -0
- 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/rpc.cjs +2 -0
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.d.ts +2 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -0
- package/dist/rpc.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +4 -1
- package/schemas/json-schema-form.schema.json +571 -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
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
const CURVE_OFFSET = 22;
|
|
2
|
+
const MIN_SIDE_REACH = 36;
|
|
3
|
+
const LOOP_BASE_REACH = 24;
|
|
4
|
+
const LOOP_SPAN_RATE = 0.18;
|
|
5
|
+
const MAX_LOOP_REACH = 240;
|
|
6
|
+
const LOOP_GAP_SHARE = 0.6;
|
|
7
|
+
const CUBIC_PEAK = 0.75;
|
|
8
|
+
const PORT_INSET = 12;
|
|
9
|
+
function unorderedPairKey(a, b) {
|
|
10
|
+
return a < b ? `${a}\0${b}` : `${b}\0${a}`;
|
|
11
|
+
}
|
|
12
|
+
function requirePosition(positions, id) {
|
|
13
|
+
const position = positions[id];
|
|
14
|
+
if (!position) {
|
|
15
|
+
throw new Error(`routeEdges: no layout position for node "${id}"`);
|
|
16
|
+
}
|
|
17
|
+
return position;
|
|
18
|
+
}
|
|
19
|
+
function requireEdge(group, index) {
|
|
20
|
+
const edge = group[index];
|
|
21
|
+
if (!edge) {
|
|
22
|
+
throw new Error(`routeEdges: expected an edge at index ${index}`);
|
|
23
|
+
}
|
|
24
|
+
return edge;
|
|
25
|
+
}
|
|
26
|
+
function clipToRect(center, towards, halfW, halfH) {
|
|
27
|
+
const dx = towards.x - center.x;
|
|
28
|
+
const dy = towards.y - center.y;
|
|
29
|
+
if (dx === 0 && dy === 0) return { x: center.x, y: center.y };
|
|
30
|
+
const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Number.POSITIVE_INFINITY;
|
|
31
|
+
const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Number.POSITIVE_INFINITY;
|
|
32
|
+
const scale = Math.min(scaleX, scaleY);
|
|
33
|
+
return { x: center.x + dx * scale, y: center.y + dy * scale };
|
|
34
|
+
}
|
|
35
|
+
function quadraticMidpoint(p0, p1, p2) {
|
|
36
|
+
return {
|
|
37
|
+
x: 0.25 * p0.x + 0.5 * p1.x + 0.25 * p2.x,
|
|
38
|
+
y: 0.25 * p0.y + 0.5 * p1.y + 0.25 * p2.y
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function groupEdgesByPair(edges, positions) {
|
|
42
|
+
const groups = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const edge of edges) {
|
|
44
|
+
if (!(edge.from in positions)) {
|
|
45
|
+
throw new Error(`routeEdges: edge "${edge.id}" references unknown node "${edge.from}"`);
|
|
46
|
+
}
|
|
47
|
+
if (!(edge.to in positions)) {
|
|
48
|
+
throw new Error(`routeEdges: edge "${edge.id}" references unknown node "${edge.to}"`);
|
|
49
|
+
}
|
|
50
|
+
const key = unorderedPairKey(edge.from, edge.to);
|
|
51
|
+
const group = groups.get(key);
|
|
52
|
+
if (group) {
|
|
53
|
+
group.push(edge);
|
|
54
|
+
} else {
|
|
55
|
+
groups.set(key, [edge]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return [...groups.values()];
|
|
59
|
+
}
|
|
60
|
+
function routeCenterGroup(group, positions, dimensions, routes) {
|
|
61
|
+
const halfW = dimensions.nodeWidth / 2;
|
|
62
|
+
const halfH = dimensions.nodeHeight / 2;
|
|
63
|
+
const first = requireEdge(group, 0);
|
|
64
|
+
const posA = requirePosition(positions, first.from);
|
|
65
|
+
const posB = requirePosition(positions, first.to);
|
|
66
|
+
const dx = posB.x - posA.x;
|
|
67
|
+
const dy = posB.y - posA.y;
|
|
68
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
69
|
+
const perpX = -dy / len;
|
|
70
|
+
const perpY = dx / len;
|
|
71
|
+
const midX = (posA.x + posB.x) / 2;
|
|
72
|
+
const midY = (posA.y + posB.y) / 2;
|
|
73
|
+
group.forEach((edge, index) => {
|
|
74
|
+
const isCurved = group.length > 1;
|
|
75
|
+
const sign = index % 2 === 0 ? 1 : -1;
|
|
76
|
+
const magnitude = Math.floor(index / 2) + 1;
|
|
77
|
+
const offset = isCurved ? sign * magnitude * CURVE_OFFSET : 0;
|
|
78
|
+
const control = { x: midX + perpX * offset, y: midY + perpY * offset };
|
|
79
|
+
const fromCenter = requirePosition(positions, edge.from);
|
|
80
|
+
const toCenter = requirePosition(positions, edge.to);
|
|
81
|
+
const start = clipToRect(fromCenter, control, halfW, halfH);
|
|
82
|
+
const end = clipToRect(toCenter, control, halfW, halfH);
|
|
83
|
+
const path = isCurved ? `M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}` : `M ${start.x} ${start.y} L ${end.x} ${end.y}`;
|
|
84
|
+
const label = isCurved ? quadraticMidpoint(start, control, end) : { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };
|
|
85
|
+
routes[edge.id] = { path, labelX: label.x, labelY: label.y };
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function pointOnCurve([p0, c1, c2, p3], t) {
|
|
89
|
+
const u = 1 - t;
|
|
90
|
+
const weights = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t];
|
|
91
|
+
return {
|
|
92
|
+
x: weights[0] * p0.x + weights[1] * c1.x + weights[2] * c2.x + weights[3] * p3.x,
|
|
93
|
+
y: weights[0] * p0.y + weights[1] * c1.y + weights[2] * c2.y + weights[3] * p3.y
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function cubicRoute(curve) {
|
|
97
|
+
const [p0, c1, c2, p3] = curve;
|
|
98
|
+
const label = pointOnCurve(curve, 0.5);
|
|
99
|
+
return {
|
|
100
|
+
path: `M ${p0.x} ${p0.y} C ${c1.x} ${c1.y} ${c2.x} ${c2.y} ${p3.x} ${p3.y}`,
|
|
101
|
+
labelX: label.x,
|
|
102
|
+
labelY: label.y
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function isLoop(from, to, nodeWidth) {
|
|
106
|
+
return Math.abs(to.x - from.x) < nodeWidth;
|
|
107
|
+
}
|
|
108
|
+
function planLoops(edges, positions, nodeWidth) {
|
|
109
|
+
const attached = /* @__PURE__ */ new Map();
|
|
110
|
+
for (const { x } of Object.values(positions)) attached.set(x, { left: 0, right: 0 });
|
|
111
|
+
const attach = (x, side) => {
|
|
112
|
+
const tally = attached.get(x);
|
|
113
|
+
if (tally) tally[side] += 1;
|
|
114
|
+
};
|
|
115
|
+
for (const edge of edges) {
|
|
116
|
+
const from = requirePosition(positions, edge.from);
|
|
117
|
+
const to = requirePosition(positions, edge.to);
|
|
118
|
+
if (isLoop(from, to, nodeWidth)) continue;
|
|
119
|
+
const forward = to.x > from.x;
|
|
120
|
+
attach(from.x, forward ? "right" : "left");
|
|
121
|
+
attach(to.x, forward ? "left" : "right");
|
|
122
|
+
}
|
|
123
|
+
const columns = [...attached.keys()];
|
|
124
|
+
return new Map(
|
|
125
|
+
columns.map((x) => {
|
|
126
|
+
const tally = attached.get(x) ?? { left: 0, right: 0 };
|
|
127
|
+
const side = tally.left < tally.right ? -1 : 1;
|
|
128
|
+
const gaps = columns.filter((other) => (other - x) * side > 0).map((other) => Math.abs(other - x) - nodeWidth);
|
|
129
|
+
const room = gaps.length === 0 ? Number.POSITIVE_INFINITY : LOOP_GAP_SHARE * Math.min(...gaps) / CUBIC_PEAK;
|
|
130
|
+
return [x, { side, maxReach: Math.min(MAX_LOOP_REACH, Math.max(0, room)) }];
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
function loopRoute(from, to, options) {
|
|
135
|
+
const { side, maxReach } = options.plan;
|
|
136
|
+
const halfW = options.dimensions.nodeWidth / 2;
|
|
137
|
+
const spread = options.self ? options.dimensions.nodeHeight / 4 : 0;
|
|
138
|
+
const startY = from.y - spread;
|
|
139
|
+
const endY = to.y + spread;
|
|
140
|
+
const reach = Math.min(maxReach, Math.max(MIN_SIDE_REACH, LOOP_BASE_REACH + LOOP_SPAN_RATE * Math.abs(endY - startY))) + options.index * CURVE_OFFSET;
|
|
141
|
+
const outer = side > 0 ? Math.max(from.x, to.x) : Math.min(from.x, to.x);
|
|
142
|
+
const bulge = outer + side * (halfW + reach);
|
|
143
|
+
return {
|
|
144
|
+
...cubicRoute([
|
|
145
|
+
{ x: from.x + side * halfW, y: startY },
|
|
146
|
+
{ x: bulge, y: startY },
|
|
147
|
+
{ x: bulge, y: endY },
|
|
148
|
+
{ x: to.x + side * halfW, y: endY }
|
|
149
|
+
]),
|
|
150
|
+
labelAnchor: side > 0 ? "start" : "end"
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function routeSideGroup(group, positions, dimensions, loops, routes) {
|
|
154
|
+
const halfW = dimensions.nodeWidth / 2;
|
|
155
|
+
const step = group.length > 1 ? Math.min(CURVE_OFFSET, (dimensions.nodeHeight - PORT_INSET) / (group.length - 1)) : 0;
|
|
156
|
+
group.forEach((edge, index) => {
|
|
157
|
+
const from = requirePosition(positions, edge.from);
|
|
158
|
+
const to = requirePosition(positions, edge.to);
|
|
159
|
+
if (isLoop(from, to, dimensions.nodeWidth)) {
|
|
160
|
+
const plan = loops.get(from.x);
|
|
161
|
+
if (!plan) throw new Error(`routeEdges: no loop plan for the column of "${edge.from}"`);
|
|
162
|
+
routes[edge.id] = loopRoute(from, to, { self: edge.from === edge.to, index, dimensions, plan });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const direction = to.x > from.x ? 1 : -1;
|
|
166
|
+
const shift = (index - (group.length - 1) / 2) * step;
|
|
167
|
+
const start = { x: from.x + direction * halfW, y: from.y + shift };
|
|
168
|
+
const end = { x: to.x - direction * halfW, y: to.y + shift };
|
|
169
|
+
const reach = Math.max(MIN_SIDE_REACH, Math.abs(end.x - start.x) / 2);
|
|
170
|
+
const curve = [
|
|
171
|
+
start,
|
|
172
|
+
{ x: start.x + direction * reach, y: start.y },
|
|
173
|
+
{ x: end.x - direction * reach, y: end.y },
|
|
174
|
+
end
|
|
175
|
+
];
|
|
176
|
+
routes[edge.id] = { ...cubicRoute(curve), curve };
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function routeEdges(edges, positions, dimensions, options = {}) {
|
|
180
|
+
const routes = {};
|
|
181
|
+
const groups = groupEdgesByPair(edges, positions);
|
|
182
|
+
if (options.anchor !== "side") {
|
|
183
|
+
for (const group of groups) routeCenterGroup(group, positions, dimensions, routes);
|
|
184
|
+
return routes;
|
|
185
|
+
}
|
|
186
|
+
const loops = planLoops(edges, positions, dimensions.nodeWidth);
|
|
187
|
+
for (const group of groups) routeSideGroup(group, positions, dimensions, loops, routes);
|
|
188
|
+
return routes;
|
|
189
|
+
}
|
|
190
|
+
function loopOverhang(edges, positions, dimensions) {
|
|
191
|
+
const xs = Object.values(positions).map((position) => position.x);
|
|
192
|
+
const loops = Object.values(routeEdges(edges, positions, dimensions, { anchor: "side" })).filter(
|
|
193
|
+
(route) => route.labelAnchor !== void 0
|
|
194
|
+
);
|
|
195
|
+
if (loops.length === 0) return { left: 0, right: 0 };
|
|
196
|
+
const peaks = loops.map((route) => route.labelX);
|
|
197
|
+
const halfW = dimensions.nodeWidth / 2;
|
|
198
|
+
return {
|
|
199
|
+
left: Math.max(0, Math.min(...xs) - halfW - Math.min(...peaks)),
|
|
200
|
+
right: Math.max(0, Math.max(...peaks) - (Math.max(...xs) + halfW))
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function labelLeft(box) {
|
|
204
|
+
if (box.anchor === "start") return box.x;
|
|
205
|
+
return box.anchor === "end" ? box.x - box.width : box.x - box.width / 2;
|
|
206
|
+
}
|
|
207
|
+
function spreadLabels(boxes, gap = 2) {
|
|
208
|
+
const placed = [];
|
|
209
|
+
const ys = {};
|
|
210
|
+
for (const box of [...boxes].sort((a, b) => a.y - b.y)) {
|
|
211
|
+
const left = labelLeft(box);
|
|
212
|
+
const right = left + box.width;
|
|
213
|
+
let y = box.y;
|
|
214
|
+
for (let moved = true; moved; ) {
|
|
215
|
+
moved = false;
|
|
216
|
+
for (const other of placed) {
|
|
217
|
+
const clearance = (box.height + other.height) / 2 + gap;
|
|
218
|
+
if (left < other.right && other.left < right && Math.abs(y - other.y) < clearance) {
|
|
219
|
+
y = other.y + clearance;
|
|
220
|
+
moved = true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
placed.push({ left, right, y, height: box.height });
|
|
225
|
+
ys[box.id] = y;
|
|
226
|
+
}
|
|
227
|
+
return ys;
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
loopOverhang,
|
|
231
|
+
pointOnCurve,
|
|
232
|
+
routeEdges,
|
|
233
|
+
spreadLabels
|
|
234
|
+
};
|
|
235
|
+
//# sourceMappingURL=graph-edge-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-edge-routing.js","sources":["../../src/data/graph-edge-routing.ts"],"sourcesContent":["// Edge routing and label placement for GraphDiagram: pure math, no React.\n// Split from graph-layout.ts, which owns the position types and `ringLayout`\n// and re-exports this file's API.\n\nimport type { GraphLayoutPosition } from \"./graph-layout\";\n\nexport interface GraphLayoutEdge {\n id: string;\n from: string;\n to: string;\n}\n\n/** Start, two control points and end of a cubic Bézier. */\nexport type CubicCurve = readonly [GraphLayoutPosition, GraphLayoutPosition, GraphLayoutPosition, GraphLayoutPosition];\n\nexport interface EdgeRoute {\n /** SVG path `d` attribute, clipped to the node rectangle boundaries. */\n path: string;\n /** Midpoint of the rendered path, for placing an edge label. */\n labelX: number;\n labelY: number;\n /**\n * Set on a loop, whose midpoint is its outermost point: \"start\" when a label\n * should begin at the point and run right of it, \"end\" when it should end\n * there and run left. A centred label would reach back over the node.\n */\n labelAnchor?: \"start\" | \"end\";\n /** A side-anchored edge between two columns: its curve, for placing a label elsewhere than its midpoint. */\n curve?: CubicCurve;\n}\n\nexport interface RouteEdgesDimensions {\n nodeWidth: number;\n nodeHeight: number;\n}\n\nexport interface RouteEdgesOptions {\n /** Where edges attach: clipped toward the node centre, or at the left/right side middles. Defaults to \"center\". */\n anchor?: \"center\" | \"side\";\n}\n\nconst CURVE_OFFSET = 22;\nconst MIN_SIDE_REACH = 36;\n/** A loop reaches this far plus a share of the height it spans, so a longer loop arcs outside a shorter one. */\nconst LOOP_BASE_REACH = 24;\nconst LOOP_SPAN_RATE = 0.18;\nconst MAX_LOOP_REACH = 240;\n/** The share of the gap to the next column a loop may bulge into. */\nconst LOOP_GAP_SHARE = 0.6;\n/** A cubic whose two control points share an x peaks at 3/4 of their offset. */\nconst CUBIC_PEAK = 0.75;\n/** Vertical margin kept between fanned side anchors and the node's corners. */\nconst PORT_INSET = 12;\n\nfunction unorderedPairKey(a: string, b: string): string {\n return a < b ? `${a}\\0${b}` : `${b}\\0${a}`;\n}\n\nfunction requirePosition(positions: Record<string, GraphLayoutPosition>, id: string): GraphLayoutPosition {\n const position = positions[id];\n if (!position) {\n throw new Error(`routeEdges: no layout position for node \"${id}\"`);\n }\n return position;\n}\n\nfunction requireEdge(group: readonly GraphLayoutEdge[], index: number): GraphLayoutEdge {\n const edge = group[index];\n if (!edge) {\n throw new Error(`routeEdges: expected an edge at index ${index}`);\n }\n return edge;\n}\n\n/** Point on the rectangle (centred at `center`, half-extents `halfW`/`halfH`) where the ray toward `towards` exits. */\nfunction clipToRect(\n center: GraphLayoutPosition,\n towards: GraphLayoutPosition,\n halfW: number,\n halfH: number,\n): GraphLayoutPosition {\n const dx = towards.x - center.x;\n const dy = towards.y - center.y;\n if (dx === 0 && dy === 0) return { x: center.x, y: center.y };\n\n const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Number.POSITIVE_INFINITY;\n const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Number.POSITIVE_INFINITY;\n const scale = Math.min(scaleX, scaleY);\n\n return { x: center.x + dx * scale, y: center.y + dy * scale };\n}\n\n/** Point at t=0.5 on the quadratic Bézier defined by p0 (start), p1 (control), p2 (end). */\nfunction quadraticMidpoint(\n p0: GraphLayoutPosition,\n p1: GraphLayoutPosition,\n p2: GraphLayoutPosition,\n): GraphLayoutPosition {\n return {\n x: 0.25 * p0.x + 0.5 * p1.x + 0.25 * p2.x,\n y: 0.25 * p0.y + 0.5 * p1.y + 0.25 * p2.y,\n };\n}\n\n/** Edges sharing an unordered node pair, in input order; throws on an edge whose node has no position. */\nfunction groupEdgesByPair(\n edges: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n): GraphLayoutEdge[][] {\n const groups = new Map<string, GraphLayoutEdge[]>();\n for (const edge of edges) {\n if (!(edge.from in positions)) {\n throw new Error(`routeEdges: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!(edge.to in positions)) {\n throw new Error(`routeEdges: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n const key = unorderedPairKey(edge.from, edge.to);\n const group = groups.get(key);\n if (group) {\n group.push(edge);\n } else {\n groups.set(key, [edge]);\n }\n }\n return [...groups.values()];\n}\n\nfunction routeCenterGroup(\n group: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n dimensions: RouteEdgesDimensions,\n routes: Record<string, EdgeRoute>,\n): void {\n const halfW = dimensions.nodeWidth / 2;\n const halfH = dimensions.nodeHeight / 2;\n const first = requireEdge(group, 0);\n const posA = requirePosition(positions, first.from);\n const posB = requirePosition(positions, first.to);\n const dx = posB.x - posA.x;\n const dy = posB.y - posA.y;\n const len = Math.hypot(dx, dy) || 1;\n const perpX = -dy / len;\n const perpY = dx / len;\n const midX = (posA.x + posB.x) / 2;\n const midY = (posA.y + posB.y) / 2;\n\n group.forEach((edge, index) => {\n const isCurved = group.length > 1;\n const sign = index % 2 === 0 ? 1 : -1;\n const magnitude = Math.floor(index / 2) + 1;\n const offset = isCurved ? sign * magnitude * CURVE_OFFSET : 0;\n\n const control = { x: midX + perpX * offset, y: midY + perpY * offset };\n const fromCenter = requirePosition(positions, edge.from);\n const toCenter = requirePosition(positions, edge.to);\n const start = clipToRect(fromCenter, control, halfW, halfH);\n const end = clipToRect(toCenter, control, halfW, halfH);\n\n const path = isCurved\n ? `M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}`\n : `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n\n const label = isCurved\n ? quadraticMidpoint(start, control, end)\n : { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };\n\n routes[edge.id] = { path, labelX: label.x, labelY: label.y };\n });\n}\n\n/** The point at `t` (0 at the start, 1 at the end) along a cubic Bézier. */\nexport function pointOnCurve([p0, c1, c2, p3]: CubicCurve, t: number): GraphLayoutPosition {\n const u = 1 - t;\n const weights = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t] as const;\n return {\n x: weights[0] * p0.x + weights[1] * c1.x + weights[2] * c2.x + weights[3] * p3.x,\n y: weights[0] * p0.y + weights[1] * c1.y + weights[2] * c2.y + weights[3] * p3.y,\n };\n}\n\nfunction cubicRoute(curve: CubicCurve): EdgeRoute {\n const [p0, c1, c2, p3] = curve;\n const label = pointOnCurve(curve, 0.5);\n return {\n path: `M ${p0.x} ${p0.y} C ${c1.x} ${c1.y} ${c2.x} ${c2.y} ${p3.x} ${p3.y}`,\n labelX: label.x,\n labelY: label.y,\n };\n}\n\ninterface LoopPlan {\n /** 1 when the column's loops bulge right of it, -1 when left. */\n side: 1 | -1;\n /** The furthest a loop's control points may sit from the column, so it stays clear of the next one. */\n maxReach: number;\n}\n\nfunction isLoop(from: GraphLayoutPosition, to: GraphLayoutPosition, nodeWidth: number): boolean {\n return Math.abs(to.x - from.x) < nodeWidth;\n}\n\n/**\n * For each column (each distinct node x), where its loops go: the side with\n * fewer edges to other columns attached, the right on a tie, and no further\n * than a share of the gap to the next column on that side.\n */\nfunction planLoops(\n edges: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n nodeWidth: number,\n): Map<number, LoopPlan> {\n const attached = new Map<number, { left: number; right: number }>();\n for (const { x } of Object.values(positions)) attached.set(x, { left: 0, right: 0 });\n const attach = (x: number, side: \"left\" | \"right\") => {\n const tally = attached.get(x);\n if (tally) tally[side] += 1;\n };\n for (const edge of edges) {\n const from = requirePosition(positions, edge.from);\n const to = requirePosition(positions, edge.to);\n if (isLoop(from, to, nodeWidth)) continue;\n const forward = to.x > from.x;\n attach(from.x, forward ? \"right\" : \"left\");\n attach(to.x, forward ? \"left\" : \"right\");\n }\n const columns = [...attached.keys()];\n return new Map(\n columns.map((x) => {\n const tally = attached.get(x) ?? { left: 0, right: 0 };\n const side = tally.left < tally.right ? -1 : 1;\n const gaps = columns.filter((other) => (other - x) * side > 0).map((other) => Math.abs(other - x) - nodeWidth);\n const room = gaps.length === 0 ? Number.POSITIVE_INFINITY : (LOOP_GAP_SHARE * Math.min(...gaps)) / CUBIC_PEAK;\n return [x, { side, maxReach: Math.min(MAX_LOOP_REACH, Math.max(0, room)) }];\n }),\n );\n}\n\n/** Out of one side of a column and back into it: an edge inside one column, or a self-edge. */\nfunction loopRoute(\n from: GraphLayoutPosition,\n to: GraphLayoutPosition,\n options: { self: boolean; index: number; dimensions: RouteEdgesDimensions; plan: LoopPlan },\n): EdgeRoute {\n const { side, maxReach } = options.plan;\n const halfW = options.dimensions.nodeWidth / 2;\n const spread = options.self ? options.dimensions.nodeHeight / 4 : 0;\n const startY = from.y - spread;\n const endY = to.y + spread;\n const reach =\n Math.min(maxReach, Math.max(MIN_SIDE_REACH, LOOP_BASE_REACH + LOOP_SPAN_RATE * Math.abs(endY - startY))) +\n options.index * CURVE_OFFSET;\n const outer = side > 0 ? Math.max(from.x, to.x) : Math.min(from.x, to.x);\n const bulge = outer + side * (halfW + reach);\n return {\n ...cubicRoute([\n { x: from.x + side * halfW, y: startY },\n { x: bulge, y: startY },\n { x: bulge, y: endY },\n { x: to.x + side * halfW, y: endY },\n ]),\n labelAnchor: side > 0 ? \"start\" : \"end\",\n };\n}\n\nfunction routeSideGroup(\n group: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n dimensions: RouteEdgesDimensions,\n loops: ReadonlyMap<number, LoopPlan>,\n routes: Record<string, EdgeRoute>,\n): void {\n const halfW = dimensions.nodeWidth / 2;\n const step =\n group.length > 1\n ? Math.min(CURVE_OFFSET, (dimensions.nodeHeight - PORT_INSET) / (group.length - 1))\n : 0;\n\n group.forEach((edge, index) => {\n const from = requirePosition(positions, edge.from);\n const to = requirePosition(positions, edge.to);\n if (isLoop(from, to, dimensions.nodeWidth)) {\n const plan = loops.get(from.x);\n if (!plan) throw new Error(`routeEdges: no loop plan for the column of \"${edge.from}\"`);\n routes[edge.id] = loopRoute(from, to, { self: edge.from === edge.to, index, dimensions, plan });\n return;\n }\n const direction = to.x > from.x ? 1 : -1;\n const shift = (index - (group.length - 1) / 2) * step;\n const start = { x: from.x + direction * halfW, y: from.y + shift };\n const end = { x: to.x - direction * halfW, y: to.y + shift };\n const reach = Math.max(MIN_SIDE_REACH, Math.abs(end.x - start.x) / 2);\n const curve: CubicCurve = [\n start,\n { x: start.x + direction * reach, y: start.y },\n { x: end.x - direction * reach, y: end.y },\n end,\n ];\n routes[edge.id] = { ...cubicRoute(curve), curve };\n });\n}\n\n/**\n * Routes each edge as an SVG path. Edges sharing an unordered node pair — a\n * reciprocal A→B + B→A, or literal duplicates — are always fanned apart so\n * they never overlap.\n *\n * `anchor: \"center\"` (the default) clips each edge to the source/target node\n * rectangles: a lone edge is a straight line, a fanned one a quadratic curve\n * offset from the line between the two node centres.\n *\n * `anchor: \"side\"` is for column layouts: an edge leaves the side of its\n * source facing the target and enters the facing side of the target as a\n * cubic curve. An edge between two nodes of one column, and a self-edge, is a\n * loop: it arcs out of the column and back on the side with fewer edges to\n * other columns, the further the more height it spans, so loops nest.\n *\n * Throws when an edge references a node id absent from `positions`, naming\n * the edge id, rather than silently dropping or mis-routing it.\n */\nexport function routeEdges(\n edges: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n dimensions: RouteEdgesDimensions,\n options: RouteEdgesOptions = {},\n): Record<string, EdgeRoute> {\n const routes: Record<string, EdgeRoute> = {};\n const groups = groupEdgesByPair(edges, positions);\n if (options.anchor !== \"side\") {\n for (const group of groups) routeCenterGroup(group, positions, dimensions, routes);\n return routes;\n }\n const loops = planLoops(edges, positions, dimensions.nodeWidth);\n for (const group of groups) routeSideGroup(group, positions, dimensions, loops, routes);\n return routes;\n}\n\n/** How far the side-anchored loops of `edges` reach past the outermost columns, on each side. */\nexport function loopOverhang(\n edges: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n dimensions: RouteEdgesDimensions,\n): { left: number; right: number } {\n const xs = Object.values(positions).map((position) => position.x);\n const loops = Object.values(routeEdges(edges, positions, dimensions, { anchor: \"side\" })).filter(\n (route) => route.labelAnchor !== undefined,\n );\n if (loops.length === 0) return { left: 0, right: 0 };\n const peaks = loops.map((route) => route.labelX);\n const halfW = dimensions.nodeWidth / 2;\n return {\n left: Math.max(0, Math.min(...xs) - halfW - Math.min(...peaks)),\n right: Math.max(0, Math.max(...peaks) - (Math.max(...xs) + halfW)),\n };\n}\n\nexport interface EdgeLabelBox {\n id: string;\n /** The label's anchor: its centre, its left edge when `anchor` is \"start\", its right edge when \"end\". */\n x: number;\n y: number;\n width: number;\n height: number;\n anchor?: \"start\" | \"end\";\n}\n\nfunction labelLeft(box: EdgeLabelBox): number {\n if (box.anchor === \"start\") return box.x;\n return box.anchor === \"end\" ? box.x - box.width : box.x - box.width / 2;\n}\n\n/**\n * Resolves the y of each edge label so no two labels cover each other: taken\n * top to bottom, a label that would overlap one already placed drops just\n * below it. Labels keep their x, and a label that overlaps nothing keeps its y.\n */\nexport function spreadLabels(boxes: readonly EdgeLabelBox[], gap = 2): Record<string, number> {\n const placed: { left: number; right: number; y: number; height: number }[] = [];\n const ys: Record<string, number> = {};\n for (const box of [...boxes].sort((a, b) => a.y - b.y)) {\n const left = labelLeft(box);\n const right = left + box.width;\n let y = box.y;\n for (let moved = true; moved; ) {\n moved = false;\n for (const other of placed) {\n const clearance = (box.height + other.height) / 2 + gap;\n if (left < other.right && other.left < right && Math.abs(y - other.y) < clearance) {\n y = other.y + clearance;\n moved = true;\n }\n }\n }\n placed.push({ left, right, y, height: box.height });\n ys[box.id] = y;\n }\n return ys;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -42,87 +42,5 @@ function ringLayout(nodes, options = {}) {
|
|
|
42
42
|
positions
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
-
const CURVE_OFFSET = 22;
|
|
46
|
-
function unorderedPairKey(a, b) {
|
|
47
|
-
return a < b ? `${a}\0${b}` : `${b}\0${a}`;
|
|
48
|
-
}
|
|
49
|
-
function requirePosition(positions, id) {
|
|
50
|
-
const position = positions[id];
|
|
51
|
-
if (!position) {
|
|
52
|
-
throw new Error(`routeEdges: no layout position for node "${id}"`);
|
|
53
|
-
}
|
|
54
|
-
return position;
|
|
55
|
-
}
|
|
56
|
-
function requireEdge(group, index) {
|
|
57
|
-
const edge = group[index];
|
|
58
|
-
if (!edge) {
|
|
59
|
-
throw new Error(`routeEdges: expected an edge at index ${index}`);
|
|
60
|
-
}
|
|
61
|
-
return edge;
|
|
62
|
-
}
|
|
63
|
-
function clipToRect(center, towards, halfW, halfH) {
|
|
64
|
-
const dx = towards.x - center.x;
|
|
65
|
-
const dy = towards.y - center.y;
|
|
66
|
-
if (dx === 0 && dy === 0) return { x: center.x, y: center.y };
|
|
67
|
-
const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Number.POSITIVE_INFINITY;
|
|
68
|
-
const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Number.POSITIVE_INFINITY;
|
|
69
|
-
const scale = Math.min(scaleX, scaleY);
|
|
70
|
-
return { x: center.x + dx * scale, y: center.y + dy * scale };
|
|
71
|
-
}
|
|
72
|
-
function quadraticMidpoint(p0, p1, p2) {
|
|
73
|
-
return {
|
|
74
|
-
x: 0.25 * p0.x + 0.5 * p1.x + 0.25 * p2.x,
|
|
75
|
-
y: 0.25 * p0.y + 0.5 * p1.y + 0.25 * p2.y
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function routeEdges(edges, positions, dimensions) {
|
|
79
|
-
const halfW = dimensions.nodeWidth / 2;
|
|
80
|
-
const halfH = dimensions.nodeHeight / 2;
|
|
81
|
-
const groups = /* @__PURE__ */ new Map();
|
|
82
|
-
for (const edge of edges) {
|
|
83
|
-
if (!(edge.from in positions)) {
|
|
84
|
-
throw new Error(`routeEdges: edge "${edge.id}" references unknown node "${edge.from}"`);
|
|
85
|
-
}
|
|
86
|
-
if (!(edge.to in positions)) {
|
|
87
|
-
throw new Error(`routeEdges: edge "${edge.id}" references unknown node "${edge.to}"`);
|
|
88
|
-
}
|
|
89
|
-
const key = unorderedPairKey(edge.from, edge.to);
|
|
90
|
-
const group = groups.get(key);
|
|
91
|
-
if (group) {
|
|
92
|
-
group.push(edge);
|
|
93
|
-
} else {
|
|
94
|
-
groups.set(key, [edge]);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const routes = {};
|
|
98
|
-
for (const group of groups.values()) {
|
|
99
|
-
const first = requireEdge(group, 0);
|
|
100
|
-
const posA = requirePosition(positions, first.from);
|
|
101
|
-
const posB = requirePosition(positions, first.to);
|
|
102
|
-
const dx = posB.x - posA.x;
|
|
103
|
-
const dy = posB.y - posA.y;
|
|
104
|
-
const len = Math.hypot(dx, dy) || 1;
|
|
105
|
-
const perpX = -dy / len;
|
|
106
|
-
const perpY = dx / len;
|
|
107
|
-
const midX = (posA.x + posB.x) / 2;
|
|
108
|
-
const midY = (posA.y + posB.y) / 2;
|
|
109
|
-
group.forEach((edge, index) => {
|
|
110
|
-
const isCurved = group.length > 1;
|
|
111
|
-
const sign = index % 2 === 0 ? 1 : -1;
|
|
112
|
-
const magnitude = Math.floor(index / 2) + 1;
|
|
113
|
-
const offset = isCurved ? sign * magnitude * CURVE_OFFSET : 0;
|
|
114
|
-
const control = { x: midX + perpX * offset, y: midY + perpY * offset };
|
|
115
|
-
const fromCenter = requirePosition(positions, edge.from);
|
|
116
|
-
const toCenter = requirePosition(positions, edge.to);
|
|
117
|
-
const start = clipToRect(fromCenter, control, halfW, halfH);
|
|
118
|
-
const end = clipToRect(toCenter, control, halfW, halfH);
|
|
119
|
-
const path = isCurved ? `M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}` : `M ${start.x} ${start.y} L ${end.x} ${end.y}`;
|
|
120
|
-
const label = isCurved ? quadraticMidpoint(start, control, end) : { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };
|
|
121
|
-
routes[edge.id] = { path, labelX: label.x, labelY: label.y };
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
return routes;
|
|
125
|
-
}
|
|
126
45
|
exports.ringLayout = ringLayout;
|
|
127
|
-
exports.routeEdges = routeEdges;
|
|
128
46
|
//# sourceMappingURL=graph-layout.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-layout.cjs","sources":["../../src/data/graph-layout.ts"],"sourcesContent":["// Pure, framework-free layout and edge-routing math for GraphDiagram. Kept\n// free of React so it can be unit tested without rendering, and so a future\n// \"columns\" layout can live alongside `ringLayout` without dragging in DOM\n// concerns.\n\nexport interface GraphLayoutNode {\n id: string;\n}\n\nexport interface RingLayoutOptions {\n /** Node bounding-box width in px. Defaults to 168. */\n nodeWidth?: number;\n /** Node bounding-box height in px. Defaults to 60. */\n nodeHeight?: number;\n /** Minimum gap between adjacent node edges in px. Defaults to 40. */\n gap?: number;\n /** Space reserved around the ring before the viewport edge. Defaults to 24. */\n padding?: number;\n}\n\nexport interface GraphLayoutPosition {\n /** Node centre x, in the same coordinate space as `width`/`height`. */\n x: number;\n /** Node centre y. */\n y: number;\n}\n\nexport interface GraphLayoutResult {\n width: number;\n height: number;\n positions: Record<string, GraphLayoutPosition>;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_GAP = 40;\nconst DEFAULT_PADDING = 24;\nconst MIN_RADIUS = 96;\n\nfunction requireNode<T extends GraphLayoutNode>(nodes: readonly T[], index: number): T {\n const node = nodes[index];\n if (!node) {\n throw new Error(`ringLayout: expected a node at index ${index}`);\n }\n return node;\n}\n\n/**\n * Places nodes on a circle in the given order, starting at 12 o'clock and\n * running clockwise. `n=1` is centred (radius 0); `n=2` is a special case —\n * left/right — because 180° clockwise from 12 o'clock lands at 6 o'clock,\n * which reads poorly for a two-node relationship.\n *\n * The radius is sized so the straight-line (chord) distance between any two\n * angularly-adjacent nodes is at least `nodeWidth + gap`, with a sensible\n * floor (`MIN_RADIUS`) for small rings.\n */\nexport function ringLayout(\n nodes: readonly GraphLayoutNode[],\n options: RingLayoutOptions = {},\n): GraphLayoutResult {\n const nodeWidth = options.nodeWidth ?? DEFAULT_NODE_WIDTH;\n const nodeHeight = options.nodeHeight ?? DEFAULT_NODE_HEIGHT;\n const gap = options.gap ?? DEFAULT_GAP;\n const padding = options.padding ?? DEFAULT_PADDING;\n const n = nodes.length;\n\n const radius = n <= 1 ? 0 : Math.max(MIN_RADIUS, (nodeWidth + gap) / (2 * Math.sin(Math.PI / n)));\n const cx = radius + nodeWidth / 2 + padding;\n const cy = radius + nodeHeight / 2 + padding;\n\n const positions: Record<string, GraphLayoutPosition> = {};\n\n if (n === 1) {\n positions[requireNode(nodes, 0).id] = { x: cx, y: cy };\n } else if (n === 2) {\n positions[requireNode(nodes, 0).id] = { x: cx - radius, y: cy };\n positions[requireNode(nodes, 1).id] = { x: cx + radius, y: cy };\n } else {\n nodes.forEach((node, i) => {\n const theta = -Math.PI / 2 + i * ((2 * Math.PI) / n);\n positions[node.id] = {\n x: cx + radius * Math.cos(theta),\n y: cy + radius * Math.sin(theta),\n };\n });\n }\n\n return {\n width: 2 * cx,\n height: 2 * cy,\n positions,\n };\n}\n\nexport interface GraphLayoutEdge {\n id: string;\n from: string;\n to: string;\n}\n\nexport interface EdgeRoute {\n /** SVG path `d` attribute, clipped to the node rectangle boundaries. */\n path: string;\n /** Midpoint of the rendered path, for placing an edge label. */\n labelX: number;\n labelY: number;\n}\n\nexport interface RouteEdgesDimensions {\n nodeWidth: number;\n nodeHeight: number;\n}\n\nconst CURVE_OFFSET = 22;\n\nfunction unorderedPairKey(a: string, b: string): string {\n return a < b ? `${a}\u0000${b}` : `${b}\u0000${a}`;\n}\n\nfunction requirePosition(\n positions: Record<string, GraphLayoutPosition>,\n id: string,\n): GraphLayoutPosition {\n const position = positions[id];\n if (!position) {\n throw new Error(`routeEdges: no layout position for node \"${id}\"`);\n }\n return position;\n}\n\nfunction requireEdge(group: readonly GraphLayoutEdge[], index: number): GraphLayoutEdge {\n const edge = group[index];\n if (!edge) {\n throw new Error(`routeEdges: expected an edge at index ${index}`);\n }\n return edge;\n}\n\n/** Point on the rectangle (centred at `center`, half-extents `halfW`/`halfH`) where the ray toward `towards` exits. */\nfunction clipToRect(\n center: GraphLayoutPosition,\n towards: GraphLayoutPosition,\n halfW: number,\n halfH: number,\n): GraphLayoutPosition {\n const dx = towards.x - center.x;\n const dy = towards.y - center.y;\n if (dx === 0 && dy === 0) return { x: center.x, y: center.y };\n\n const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Number.POSITIVE_INFINITY;\n const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Number.POSITIVE_INFINITY;\n const scale = Math.min(scaleX, scaleY);\n\n return { x: center.x + dx * scale, y: center.y + dy * scale };\n}\n\n/** Point at t=0.5 on the quadratic Bézier defined by p0 (start), p1 (control), p2 (end). */\nfunction quadraticMidpoint(\n p0: GraphLayoutPosition,\n p1: GraphLayoutPosition,\n p2: GraphLayoutPosition,\n): GraphLayoutPosition {\n return {\n x: 0.25 * p0.x + 0.5 * p1.x + 0.25 * p2.x,\n y: 0.25 * p0.y + 0.5 * p1.y + 0.25 * p2.y,\n };\n}\n\n/**\n * Routes each edge as an SVG path clipped to the source/target node\n * rectangles. Edges sharing an unordered node pair — a reciprocal A→B + B→A,\n * or literal duplicates — are fanned out as quadratic curves with\n * alternating, increasing offsets from the straight line between the two\n * node centres, so they never overlap. A lone edge between a pair is a\n * straight line.\n *\n * Throws when an edge references a node id absent from `positions`, naming\n * the edge id, rather than silently dropping or mis-routing it.\n */\nexport function routeEdges(\n edges: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n dimensions: RouteEdgesDimensions,\n): Record<string, EdgeRoute> {\n const halfW = dimensions.nodeWidth / 2;\n const halfH = dimensions.nodeHeight / 2;\n\n const groups = new Map<string, GraphLayoutEdge[]>();\n for (const edge of edges) {\n if (!(edge.from in positions)) {\n throw new Error(`routeEdges: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!(edge.to in positions)) {\n throw new Error(`routeEdges: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n const key = unorderedPairKey(edge.from, edge.to);\n const group = groups.get(key);\n if (group) {\n group.push(edge);\n } else {\n groups.set(key, [edge]);\n }\n }\n\n const routes: Record<string, EdgeRoute> = {};\n\n for (const group of groups.values()) {\n const first = requireEdge(group, 0);\n const posA = requirePosition(positions, first.from);\n const posB = requirePosition(positions, first.to);\n const dx = posB.x - posA.x;\n const dy = posB.y - posA.y;\n const len = Math.hypot(dx, dy) || 1;\n const perpX = -dy / len;\n const perpY = dx / len;\n const midX = (posA.x + posB.x) / 2;\n const midY = (posA.y + posB.y) / 2;\n\n group.forEach((edge, index) => {\n const isCurved = group.length > 1;\n const sign = index % 2 === 0 ? 1 : -1;\n const magnitude = Math.floor(index / 2) + 1;\n const offset = isCurved ? sign * magnitude * CURVE_OFFSET : 0;\n\n const control = { x: midX + perpX * offset, y: midY + perpY * offset };\n const fromCenter = requirePosition(positions, edge.from);\n const toCenter = requirePosition(positions, edge.to);\n const start = clipToRect(fromCenter, control, halfW, halfH);\n const end = clipToRect(toCenter, control, halfW, halfH);\n\n const path = isCurved\n ? `M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}`\n : `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n\n const label = isCurved\n ? quadraticMidpoint(start, control, end)\n : { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };\n\n routes[edge.id] = { path, labelX: label.x, labelY: label.y };\n });\n }\n\n return routes;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graph-layout.cjs","sources":["../../src/data/graph-layout.ts"],"sourcesContent":["// Pure, framework-free layout math for GraphDiagram. Kept free of React so it\n// can be unit tested without rendering. `ringLayout` places nodes on a circle;\n// the level-column layout lives in graph-columns-layout.ts, and the edge\n// routing and label placement in graph-edge-routing.ts, re-exported here.\n\nexport {\n routeEdges,\n spreadLabels,\n type EdgeLabelBox,\n type EdgeRoute,\n type GraphLayoutEdge,\n type RouteEdgesDimensions,\n type RouteEdgesOptions,\n} from \"./graph-edge-routing\";\n\nexport interface GraphLayoutNode {\n id: string;\n}\n\nexport interface RingLayoutOptions {\n /** Node bounding-box width in px. Defaults to 168. */\n nodeWidth?: number;\n /** Node bounding-box height in px. Defaults to 60. */\n nodeHeight?: number;\n /** Minimum gap between adjacent node edges in px. Defaults to 40. */\n gap?: number;\n /** Space reserved around the ring before the viewport edge. Defaults to 24. */\n padding?: number;\n}\n\nexport interface GraphLayoutPosition {\n /** Node centre x, in the same coordinate space as `width`/`height`. */\n x: number;\n /** Node centre y. */\n y: number;\n}\n\nexport interface GraphLayoutResult {\n width: number;\n height: number;\n positions: Record<string, GraphLayoutPosition>;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_GAP = 40;\nconst DEFAULT_PADDING = 24;\nconst MIN_RADIUS = 96;\n\nfunction requireNode<T extends GraphLayoutNode>(nodes: readonly T[], index: number): T {\n const node = nodes[index];\n if (!node) {\n throw new Error(`ringLayout: expected a node at index ${index}`);\n }\n return node;\n}\n\n/**\n * Places nodes on a circle in the given order, starting at 12 o'clock and\n * running clockwise. `n=1` is centred (radius 0); `n=2` is a special case —\n * left/right — because 180° clockwise from 12 o'clock lands at 6 o'clock,\n * which reads poorly for a two-node relationship.\n *\n * The radius is sized so the straight-line (chord) distance between any two\n * angularly-adjacent nodes is at least `nodeWidth + gap`, with a sensible\n * floor (`MIN_RADIUS`) for small rings.\n */\nexport function ringLayout(\n nodes: readonly GraphLayoutNode[],\n options: RingLayoutOptions = {},\n): GraphLayoutResult {\n const nodeWidth = options.nodeWidth ?? DEFAULT_NODE_WIDTH;\n const nodeHeight = options.nodeHeight ?? DEFAULT_NODE_HEIGHT;\n const gap = options.gap ?? DEFAULT_GAP;\n const padding = options.padding ?? DEFAULT_PADDING;\n const n = nodes.length;\n\n const radius = n <= 1 ? 0 : Math.max(MIN_RADIUS, (nodeWidth + gap) / (2 * Math.sin(Math.PI / n)));\n const cx = radius + nodeWidth / 2 + padding;\n const cy = radius + nodeHeight / 2 + padding;\n\n const positions: Record<string, GraphLayoutPosition> = {};\n\n if (n === 1) {\n positions[requireNode(nodes, 0).id] = { x: cx, y: cy };\n } else if (n === 2) {\n positions[requireNode(nodes, 0).id] = { x: cx - radius, y: cy };\n positions[requireNode(nodes, 1).id] = { x: cx + radius, y: cy };\n } else {\n nodes.forEach((node, i) => {\n const theta = -Math.PI / 2 + i * ((2 * Math.PI) / n);\n positions[node.id] = {\n x: cx + radius * Math.cos(theta),\n y: cy + radius * Math.sin(theta),\n };\n });\n }\n\n return {\n width: 2 * cx,\n height: 2 * cy,\n positions,\n };\n}\n"],"names":[],"mappings":";;AA2CA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,cAAc;AACpB,MAAM,kBAAkB;AACxB,MAAM,aAAa;AAEnB,SAAS,YAAuC,OAAqB,OAAkB;AACrF,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,wCAAwC,KAAK,EAAE;AAAA,EACjE;AACA,SAAO;AACT;AAYO,SAAS,WACd,OACA,UAA6B,IACV;AACnB,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,MAAM,QAAQ,OAAO;AAC3B,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,IAAI,MAAM;AAEhB,QAAM,SAAS,KAAK,IAAI,IAAI,KAAK,IAAI,aAAa,YAAY,QAAQ,IAAI,KAAK,IAAI,KAAK,KAAK,CAAC,EAAE;AAChG,QAAM,KAAK,SAAS,YAAY,IAAI;AACpC,QAAM,KAAK,SAAS,aAAa,IAAI;AAErC,QAAM,YAAiD,CAAA;AAEvD,MAAI,MAAM,GAAG;AACX,cAAU,YAAY,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,GAAA;AAAA,EACpD,WAAW,MAAM,GAAG;AAClB,cAAU,YAAY,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,QAAQ,GAAG,GAAA;AAC3D,cAAU,YAAY,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,QAAQ,GAAG,GAAA;AAAA,EAC7D,OAAO;AACL,UAAM,QAAQ,CAAC,MAAM,MAAM;AACzB,YAAM,QAAQ,CAAC,KAAK,KAAK,IAAI,KAAM,IAAI,KAAK,KAAM;AAClD,gBAAU,KAAK,EAAE,IAAI;AAAA,QACnB,GAAG,KAAK,SAAS,KAAK,IAAI,KAAK;AAAA,QAC/B,GAAG,KAAK,SAAS,KAAK,IAAI,KAAK;AAAA,MAAA;AAAA,IAEnC,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ;AAAA,EAAA;AAEJ;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { routeEdges, spreadLabels, type EdgeLabelBox, type EdgeRoute, type GraphLayoutEdge, type RouteEdgesDimensions, type RouteEdgesOptions, } from './graph-edge-routing.js';
|
|
1
2
|
export interface GraphLayoutNode {
|
|
2
3
|
id: string;
|
|
3
4
|
}
|
|
@@ -33,32 +34,4 @@ export interface GraphLayoutResult {
|
|
|
33
34
|
* floor (`MIN_RADIUS`) for small rings.
|
|
34
35
|
*/
|
|
35
36
|
export declare function ringLayout(nodes: readonly GraphLayoutNode[], options?: RingLayoutOptions): GraphLayoutResult;
|
|
36
|
-
export interface GraphLayoutEdge {
|
|
37
|
-
id: string;
|
|
38
|
-
from: string;
|
|
39
|
-
to: string;
|
|
40
|
-
}
|
|
41
|
-
export interface EdgeRoute {
|
|
42
|
-
/** SVG path `d` attribute, clipped to the node rectangle boundaries. */
|
|
43
|
-
path: string;
|
|
44
|
-
/** Midpoint of the rendered path, for placing an edge label. */
|
|
45
|
-
labelX: number;
|
|
46
|
-
labelY: number;
|
|
47
|
-
}
|
|
48
|
-
export interface RouteEdgesDimensions {
|
|
49
|
-
nodeWidth: number;
|
|
50
|
-
nodeHeight: number;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Routes each edge as an SVG path clipped to the source/target node
|
|
54
|
-
* rectangles. Edges sharing an unordered node pair — a reciprocal A→B + B→A,
|
|
55
|
-
* or literal duplicates — are fanned out as quadratic curves with
|
|
56
|
-
* alternating, increasing offsets from the straight line between the two
|
|
57
|
-
* node centres, so they never overlap. A lone edge between a pair is a
|
|
58
|
-
* straight line.
|
|
59
|
-
*
|
|
60
|
-
* Throws when an edge references a node id absent from `positions`, naming
|
|
61
|
-
* the edge id, rather than silently dropping or mis-routing it.
|
|
62
|
-
*/
|
|
63
|
-
export declare function routeEdges(edges: readonly GraphLayoutEdge[], positions: Record<string, GraphLayoutPosition>, dimensions: RouteEdgesDimensions): Record<string, EdgeRoute>;
|
|
64
37
|
//# sourceMappingURL=graph-layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-layout.d.ts","sourceRoot":"","sources":["../../src/data/graph-layout.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,CAAC,EAAE,MAAM,CAAC;IACV,qBAAqB;IACrB,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAChD;AAgBD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,OAAO,GAAE,iBAAsB,GAC9B,iBAAiB,CAiCnB
|
|
1
|
+
{"version":3,"file":"graph-layout.d.ts","sourceRoot":"","sources":["../../src/data/graph-layout.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,UAAU,EACV,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,CAAC,EAAE,MAAM,CAAC;IACV,qBAAqB;IACrB,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAChD;AAgBD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,OAAO,GAAE,iBAAsB,GAC9B,iBAAiB,CAiCnB"}
|
|
@@ -40,89 +40,7 @@ function ringLayout(nodes, options = {}) {
|
|
|
40
40
|
positions
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
const CURVE_OFFSET = 22;
|
|
44
|
-
function unorderedPairKey(a, b) {
|
|
45
|
-
return a < b ? `${a}\0${b}` : `${b}\0${a}`;
|
|
46
|
-
}
|
|
47
|
-
function requirePosition(positions, id) {
|
|
48
|
-
const position = positions[id];
|
|
49
|
-
if (!position) {
|
|
50
|
-
throw new Error(`routeEdges: no layout position for node "${id}"`);
|
|
51
|
-
}
|
|
52
|
-
return position;
|
|
53
|
-
}
|
|
54
|
-
function requireEdge(group, index) {
|
|
55
|
-
const edge = group[index];
|
|
56
|
-
if (!edge) {
|
|
57
|
-
throw new Error(`routeEdges: expected an edge at index ${index}`);
|
|
58
|
-
}
|
|
59
|
-
return edge;
|
|
60
|
-
}
|
|
61
|
-
function clipToRect(center, towards, halfW, halfH) {
|
|
62
|
-
const dx = towards.x - center.x;
|
|
63
|
-
const dy = towards.y - center.y;
|
|
64
|
-
if (dx === 0 && dy === 0) return { x: center.x, y: center.y };
|
|
65
|
-
const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Number.POSITIVE_INFINITY;
|
|
66
|
-
const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Number.POSITIVE_INFINITY;
|
|
67
|
-
const scale = Math.min(scaleX, scaleY);
|
|
68
|
-
return { x: center.x + dx * scale, y: center.y + dy * scale };
|
|
69
|
-
}
|
|
70
|
-
function quadraticMidpoint(p0, p1, p2) {
|
|
71
|
-
return {
|
|
72
|
-
x: 0.25 * p0.x + 0.5 * p1.x + 0.25 * p2.x,
|
|
73
|
-
y: 0.25 * p0.y + 0.5 * p1.y + 0.25 * p2.y
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function routeEdges(edges, positions, dimensions) {
|
|
77
|
-
const halfW = dimensions.nodeWidth / 2;
|
|
78
|
-
const halfH = dimensions.nodeHeight / 2;
|
|
79
|
-
const groups = /* @__PURE__ */ new Map();
|
|
80
|
-
for (const edge of edges) {
|
|
81
|
-
if (!(edge.from in positions)) {
|
|
82
|
-
throw new Error(`routeEdges: edge "${edge.id}" references unknown node "${edge.from}"`);
|
|
83
|
-
}
|
|
84
|
-
if (!(edge.to in positions)) {
|
|
85
|
-
throw new Error(`routeEdges: edge "${edge.id}" references unknown node "${edge.to}"`);
|
|
86
|
-
}
|
|
87
|
-
const key = unorderedPairKey(edge.from, edge.to);
|
|
88
|
-
const group = groups.get(key);
|
|
89
|
-
if (group) {
|
|
90
|
-
group.push(edge);
|
|
91
|
-
} else {
|
|
92
|
-
groups.set(key, [edge]);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const routes = {};
|
|
96
|
-
for (const group of groups.values()) {
|
|
97
|
-
const first = requireEdge(group, 0);
|
|
98
|
-
const posA = requirePosition(positions, first.from);
|
|
99
|
-
const posB = requirePosition(positions, first.to);
|
|
100
|
-
const dx = posB.x - posA.x;
|
|
101
|
-
const dy = posB.y - posA.y;
|
|
102
|
-
const len = Math.hypot(dx, dy) || 1;
|
|
103
|
-
const perpX = -dy / len;
|
|
104
|
-
const perpY = dx / len;
|
|
105
|
-
const midX = (posA.x + posB.x) / 2;
|
|
106
|
-
const midY = (posA.y + posB.y) / 2;
|
|
107
|
-
group.forEach((edge, index) => {
|
|
108
|
-
const isCurved = group.length > 1;
|
|
109
|
-
const sign = index % 2 === 0 ? 1 : -1;
|
|
110
|
-
const magnitude = Math.floor(index / 2) + 1;
|
|
111
|
-
const offset = isCurved ? sign * magnitude * CURVE_OFFSET : 0;
|
|
112
|
-
const control = { x: midX + perpX * offset, y: midY + perpY * offset };
|
|
113
|
-
const fromCenter = requirePosition(positions, edge.from);
|
|
114
|
-
const toCenter = requirePosition(positions, edge.to);
|
|
115
|
-
const start = clipToRect(fromCenter, control, halfW, halfH);
|
|
116
|
-
const end = clipToRect(toCenter, control, halfW, halfH);
|
|
117
|
-
const path = isCurved ? `M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}` : `M ${start.x} ${start.y} L ${end.x} ${end.y}`;
|
|
118
|
-
const label = isCurved ? quadraticMidpoint(start, control, end) : { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };
|
|
119
|
-
routes[edge.id] = { path, labelX: label.x, labelY: label.y };
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return routes;
|
|
123
|
-
}
|
|
124
43
|
export {
|
|
125
|
-
ringLayout
|
|
126
|
-
routeEdges
|
|
44
|
+
ringLayout
|
|
127
45
|
};
|
|
128
46
|
//# sourceMappingURL=graph-layout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-layout.js","sources":["../../src/data/graph-layout.ts"],"sourcesContent":["// Pure, framework-free layout and edge-routing math for GraphDiagram. Kept\n// free of React so it can be unit tested without rendering, and so a future\n// \"columns\" layout can live alongside `ringLayout` without dragging in DOM\n// concerns.\n\nexport interface GraphLayoutNode {\n id: string;\n}\n\nexport interface RingLayoutOptions {\n /** Node bounding-box width in px. Defaults to 168. */\n nodeWidth?: number;\n /** Node bounding-box height in px. Defaults to 60. */\n nodeHeight?: number;\n /** Minimum gap between adjacent node edges in px. Defaults to 40. */\n gap?: number;\n /** Space reserved around the ring before the viewport edge. Defaults to 24. */\n padding?: number;\n}\n\nexport interface GraphLayoutPosition {\n /** Node centre x, in the same coordinate space as `width`/`height`. */\n x: number;\n /** Node centre y. */\n y: number;\n}\n\nexport interface GraphLayoutResult {\n width: number;\n height: number;\n positions: Record<string, GraphLayoutPosition>;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_GAP = 40;\nconst DEFAULT_PADDING = 24;\nconst MIN_RADIUS = 96;\n\nfunction requireNode<T extends GraphLayoutNode>(nodes: readonly T[], index: number): T {\n const node = nodes[index];\n if (!node) {\n throw new Error(`ringLayout: expected a node at index ${index}`);\n }\n return node;\n}\n\n/**\n * Places nodes on a circle in the given order, starting at 12 o'clock and\n * running clockwise. `n=1` is centred (radius 0); `n=2` is a special case —\n * left/right — because 180° clockwise from 12 o'clock lands at 6 o'clock,\n * which reads poorly for a two-node relationship.\n *\n * The radius is sized so the straight-line (chord) distance between any two\n * angularly-adjacent nodes is at least `nodeWidth + gap`, with a sensible\n * floor (`MIN_RADIUS`) for small rings.\n */\nexport function ringLayout(\n nodes: readonly GraphLayoutNode[],\n options: RingLayoutOptions = {},\n): GraphLayoutResult {\n const nodeWidth = options.nodeWidth ?? DEFAULT_NODE_WIDTH;\n const nodeHeight = options.nodeHeight ?? DEFAULT_NODE_HEIGHT;\n const gap = options.gap ?? DEFAULT_GAP;\n const padding = options.padding ?? DEFAULT_PADDING;\n const n = nodes.length;\n\n const radius = n <= 1 ? 0 : Math.max(MIN_RADIUS, (nodeWidth + gap) / (2 * Math.sin(Math.PI / n)));\n const cx = radius + nodeWidth / 2 + padding;\n const cy = radius + nodeHeight / 2 + padding;\n\n const positions: Record<string, GraphLayoutPosition> = {};\n\n if (n === 1) {\n positions[requireNode(nodes, 0).id] = { x: cx, y: cy };\n } else if (n === 2) {\n positions[requireNode(nodes, 0).id] = { x: cx - radius, y: cy };\n positions[requireNode(nodes, 1).id] = { x: cx + radius, y: cy };\n } else {\n nodes.forEach((node, i) => {\n const theta = -Math.PI / 2 + i * ((2 * Math.PI) / n);\n positions[node.id] = {\n x: cx + radius * Math.cos(theta),\n y: cy + radius * Math.sin(theta),\n };\n });\n }\n\n return {\n width: 2 * cx,\n height: 2 * cy,\n positions,\n };\n}\n\nexport interface GraphLayoutEdge {\n id: string;\n from: string;\n to: string;\n}\n\nexport interface EdgeRoute {\n /** SVG path `d` attribute, clipped to the node rectangle boundaries. */\n path: string;\n /** Midpoint of the rendered path, for placing an edge label. */\n labelX: number;\n labelY: number;\n}\n\nexport interface RouteEdgesDimensions {\n nodeWidth: number;\n nodeHeight: number;\n}\n\nconst CURVE_OFFSET = 22;\n\nfunction unorderedPairKey(a: string, b: string): string {\n return a < b ? `${a}\u0000${b}` : `${b}\u0000${a}`;\n}\n\nfunction requirePosition(\n positions: Record<string, GraphLayoutPosition>,\n id: string,\n): GraphLayoutPosition {\n const position = positions[id];\n if (!position) {\n throw new Error(`routeEdges: no layout position for node \"${id}\"`);\n }\n return position;\n}\n\nfunction requireEdge(group: readonly GraphLayoutEdge[], index: number): GraphLayoutEdge {\n const edge = group[index];\n if (!edge) {\n throw new Error(`routeEdges: expected an edge at index ${index}`);\n }\n return edge;\n}\n\n/** Point on the rectangle (centred at `center`, half-extents `halfW`/`halfH`) where the ray toward `towards` exits. */\nfunction clipToRect(\n center: GraphLayoutPosition,\n towards: GraphLayoutPosition,\n halfW: number,\n halfH: number,\n): GraphLayoutPosition {\n const dx = towards.x - center.x;\n const dy = towards.y - center.y;\n if (dx === 0 && dy === 0) return { x: center.x, y: center.y };\n\n const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Number.POSITIVE_INFINITY;\n const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Number.POSITIVE_INFINITY;\n const scale = Math.min(scaleX, scaleY);\n\n return { x: center.x + dx * scale, y: center.y + dy * scale };\n}\n\n/** Point at t=0.5 on the quadratic Bézier defined by p0 (start), p1 (control), p2 (end). */\nfunction quadraticMidpoint(\n p0: GraphLayoutPosition,\n p1: GraphLayoutPosition,\n p2: GraphLayoutPosition,\n): GraphLayoutPosition {\n return {\n x: 0.25 * p0.x + 0.5 * p1.x + 0.25 * p2.x,\n y: 0.25 * p0.y + 0.5 * p1.y + 0.25 * p2.y,\n };\n}\n\n/**\n * Routes each edge as an SVG path clipped to the source/target node\n * rectangles. Edges sharing an unordered node pair — a reciprocal A→B + B→A,\n * or literal duplicates — are fanned out as quadratic curves with\n * alternating, increasing offsets from the straight line between the two\n * node centres, so they never overlap. A lone edge between a pair is a\n * straight line.\n *\n * Throws when an edge references a node id absent from `positions`, naming\n * the edge id, rather than silently dropping or mis-routing it.\n */\nexport function routeEdges(\n edges: readonly GraphLayoutEdge[],\n positions: Record<string, GraphLayoutPosition>,\n dimensions: RouteEdgesDimensions,\n): Record<string, EdgeRoute> {\n const halfW = dimensions.nodeWidth / 2;\n const halfH = dimensions.nodeHeight / 2;\n\n const groups = new Map<string, GraphLayoutEdge[]>();\n for (const edge of edges) {\n if (!(edge.from in positions)) {\n throw new Error(`routeEdges: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!(edge.to in positions)) {\n throw new Error(`routeEdges: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n const key = unorderedPairKey(edge.from, edge.to);\n const group = groups.get(key);\n if (group) {\n group.push(edge);\n } else {\n groups.set(key, [edge]);\n }\n }\n\n const routes: Record<string, EdgeRoute> = {};\n\n for (const group of groups.values()) {\n const first = requireEdge(group, 0);\n const posA = requirePosition(positions, first.from);\n const posB = requirePosition(positions, first.to);\n const dx = posB.x - posA.x;\n const dy = posB.y - posA.y;\n const len = Math.hypot(dx, dy) || 1;\n const perpX = -dy / len;\n const perpY = dx / len;\n const midX = (posA.x + posB.x) / 2;\n const midY = (posA.y + posB.y) / 2;\n\n group.forEach((edge, index) => {\n const isCurved = group.length > 1;\n const sign = index % 2 === 0 ? 1 : -1;\n const magnitude = Math.floor(index / 2) + 1;\n const offset = isCurved ? sign * magnitude * CURVE_OFFSET : 0;\n\n const control = { x: midX + perpX * offset, y: midY + perpY * offset };\n const fromCenter = requirePosition(positions, edge.from);\n const toCenter = requirePosition(positions, edge.to);\n const start = clipToRect(fromCenter, control, halfW, halfH);\n const end = clipToRect(toCenter, control, halfW, halfH);\n\n const path = isCurved\n ? `M ${start.x} ${start.y} Q ${control.x} ${control.y} ${end.x} ${end.y}`\n : `M ${start.x} ${start.y} L ${end.x} ${end.y}`;\n\n const label = isCurved\n ? quadraticMidpoint(start, control, end)\n : { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };\n\n routes[edge.id] = { path, labelX: label.x, labelY: label.y };\n });\n }\n\n return routes;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graph-layout.js","sources":["../../src/data/graph-layout.ts"],"sourcesContent":["// Pure, framework-free layout math for GraphDiagram. Kept free of React so it\n// can be unit tested without rendering. `ringLayout` places nodes on a circle;\n// the level-column layout lives in graph-columns-layout.ts, and the edge\n// routing and label placement in graph-edge-routing.ts, re-exported here.\n\nexport {\n routeEdges,\n spreadLabels,\n type EdgeLabelBox,\n type EdgeRoute,\n type GraphLayoutEdge,\n type RouteEdgesDimensions,\n type RouteEdgesOptions,\n} from \"./graph-edge-routing\";\n\nexport interface GraphLayoutNode {\n id: string;\n}\n\nexport interface RingLayoutOptions {\n /** Node bounding-box width in px. Defaults to 168. */\n nodeWidth?: number;\n /** Node bounding-box height in px. Defaults to 60. */\n nodeHeight?: number;\n /** Minimum gap between adjacent node edges in px. Defaults to 40. */\n gap?: number;\n /** Space reserved around the ring before the viewport edge. Defaults to 24. */\n padding?: number;\n}\n\nexport interface GraphLayoutPosition {\n /** Node centre x, in the same coordinate space as `width`/`height`. */\n x: number;\n /** Node centre y. */\n y: number;\n}\n\nexport interface GraphLayoutResult {\n width: number;\n height: number;\n positions: Record<string, GraphLayoutPosition>;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_GAP = 40;\nconst DEFAULT_PADDING = 24;\nconst MIN_RADIUS = 96;\n\nfunction requireNode<T extends GraphLayoutNode>(nodes: readonly T[], index: number): T {\n const node = nodes[index];\n if (!node) {\n throw new Error(`ringLayout: expected a node at index ${index}`);\n }\n return node;\n}\n\n/**\n * Places nodes on a circle in the given order, starting at 12 o'clock and\n * running clockwise. `n=1` is centred (radius 0); `n=2` is a special case —\n * left/right — because 180° clockwise from 12 o'clock lands at 6 o'clock,\n * which reads poorly for a two-node relationship.\n *\n * The radius is sized so the straight-line (chord) distance between any two\n * angularly-adjacent nodes is at least `nodeWidth + gap`, with a sensible\n * floor (`MIN_RADIUS`) for small rings.\n */\nexport function ringLayout(\n nodes: readonly GraphLayoutNode[],\n options: RingLayoutOptions = {},\n): GraphLayoutResult {\n const nodeWidth = options.nodeWidth ?? DEFAULT_NODE_WIDTH;\n const nodeHeight = options.nodeHeight ?? DEFAULT_NODE_HEIGHT;\n const gap = options.gap ?? DEFAULT_GAP;\n const padding = options.padding ?? DEFAULT_PADDING;\n const n = nodes.length;\n\n const radius = n <= 1 ? 0 : Math.max(MIN_RADIUS, (nodeWidth + gap) / (2 * Math.sin(Math.PI / n)));\n const cx = radius + nodeWidth / 2 + padding;\n const cy = radius + nodeHeight / 2 + padding;\n\n const positions: Record<string, GraphLayoutPosition> = {};\n\n if (n === 1) {\n positions[requireNode(nodes, 0).id] = { x: cx, y: cy };\n } else if (n === 2) {\n positions[requireNode(nodes, 0).id] = { x: cx - radius, y: cy };\n positions[requireNode(nodes, 1).id] = { x: cx + radius, y: cy };\n } else {\n nodes.forEach((node, i) => {\n const theta = -Math.PI / 2 + i * ((2 * Math.PI) / n);\n positions[node.id] = {\n x: cx + radius * Math.cos(theta),\n y: cy + radius * Math.sin(theta),\n };\n });\n }\n\n return {\n width: 2 * cx,\n height: 2 * cy,\n positions,\n };\n}\n"],"names":[],"mappings":"AA2CA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,cAAc;AACpB,MAAM,kBAAkB;AACxB,MAAM,aAAa;AAEnB,SAAS,YAAuC,OAAqB,OAAkB;AACrF,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,wCAAwC,KAAK,EAAE;AAAA,EACjE;AACA,SAAO;AACT;AAYO,SAAS,WACd,OACA,UAA6B,IACV;AACnB,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,MAAM,QAAQ,OAAO;AAC3B,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,IAAI,MAAM;AAEhB,QAAM,SAAS,KAAK,IAAI,IAAI,KAAK,IAAI,aAAa,YAAY,QAAQ,IAAI,KAAK,IAAI,KAAK,KAAK,CAAC,EAAE;AAChG,QAAM,KAAK,SAAS,YAAY,IAAI;AACpC,QAAM,KAAK,SAAS,aAAa,IAAI;AAErC,QAAM,YAAiD,CAAA;AAEvD,MAAI,MAAM,GAAG;AACX,cAAU,YAAY,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,GAAA;AAAA,EACpD,WAAW,MAAM,GAAG;AAClB,cAAU,YAAY,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,QAAQ,GAAG,GAAA;AAC3D,cAAU,YAAY,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,QAAQ,GAAG,GAAA;AAAA,EAC7D,OAAO;AACL,UAAM,QAAQ,CAAC,MAAM,MAAM;AACzB,YAAM,QAAQ,CAAC,KAAK,KAAK,IAAI,KAAM,IAAI,KAAK,KAAM;AAClD,gBAAU,KAAK,EAAE,IAAI;AAAA,QACnB,GAAG,KAAK,SAAS,KAAK,IAAI,KAAK;AAAA,QAC/B,GAAG,KAAK,SAAS,KAAK,IAAI,KAAK;AAAA,MAAA;AAAA,IAEnC,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ;AAAA,EAAA;AAEJ;"}
|