@kiberon-labs/behave-graph-flow 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/manager.ts +6 -0
- package/.storybook/preview.ts +49 -1
- package/.storybook/styles.css +9 -3
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +368 -0
- package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
- package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
- package/dist/index.css +36 -33
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1865 -550
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14357 -11221
- package/dist/index.js.map +1 -1
- package/dist/noteImpl-KkrrWgJd.js +242 -0
- package/dist/noteImpl-KkrrWgJd.js.map +1 -0
- package/dist/styles.module-CvmpDkZj.css +3 -0
- package/dist/styles.module-CvmpDkZj.css.map +1 -0
- package/dist/styles.module-DZxg8aW9.js +271 -0
- package/dist/styles.module-DZxg8aW9.js.map +1 -0
- package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
- package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
- package/docs/protocol.md +43 -20
- package/package.json +5 -9
- package/src/components/FloatingToolbar/index.module.css +5 -13
- package/src/components/FloatingToolbar/index.tsx +9 -9
- package/src/components/Flow.tsx +34 -23
- package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
- package/src/components/contextMenus/NodePicker.module.css +13 -13
- package/src/components/contextMenus/edge.tsx +9 -95
- package/src/components/contextMenus/node.tsx +9 -149
- package/src/components/contextMenus/selection.tsx +5 -71
- package/src/components/controls/any/AnyControlImpl.tsx +14 -0
- package/src/components/controls/any/index.tsx +13 -2
- package/src/components/edges/index.tsx +75 -69
- package/src/components/layoutController/index.module.css +3 -0
- package/src/components/layoutController/index.tsx +24 -1
- package/src/components/layoutController/utils.ts +46 -3
- package/src/components/menubar/defaults.tsx +55 -19
- package/src/components/menubar/menuItem.module.css +18 -3
- package/src/components/menubar/menuItem.tsx +34 -1
- package/src/components/nodes/behave/NodeContainer.module.css +26 -25
- package/src/components/nodes/group/index.tsx +3 -3
- package/src/components/nodes/wrapper/styles.module.css +6 -32
- package/src/components/panels/alignment/index.module.css +0 -10
- package/src/components/panels/alignment/index.tsx +4 -4
- package/src/components/panels/base/styles.module.css +2 -2
- package/src/components/panels/common/PanelHeader.module.css +24 -0
- package/src/components/panels/common/PanelHeader.tsx +22 -0
- package/src/components/panels/common/SectionTitle.module.css +13 -0
- package/src/components/panels/common/SectionTitle.tsx +10 -0
- package/src/components/panels/events/EditEventPanel.tsx +14 -5
- package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
- package/src/components/panels/events/styles.module.css +6 -64
- package/src/components/panels/graphProperties/index.tsx +125 -0
- package/src/components/panels/history/index.tsx +2 -2
- package/src/components/panels/history/styles.module.css +0 -9
- package/src/components/panels/keymaps/index.module.css +3 -13
- package/src/components/panels/keymaps/index.tsx +1 -2
- package/src/components/panels/layers/index.tsx +20 -15
- package/src/components/panels/layers/styles.module.css +9 -12
- package/src/components/panels/legend/index.tsx +1 -1
- package/src/components/panels/logs/index.module.css +25 -19
- package/src/components/panels/logs/index.tsx +7 -7
- package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
- package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
- package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
- package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
- package/src/components/panels/nodeInputs/index.module.css +99 -75
- package/src/components/panels/nodeInputs/index.tsx +21 -11
- package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
- package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
- package/src/components/panels/nodePicker/index.tsx +8 -8
- package/src/components/panels/panel/index.module.css +7 -7
- package/src/components/panels/search/index.module.css +0 -50
- package/src/components/panels/search/index.tsx +2 -2
- package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
- package/src/components/panels/systemSettings/index.tsx +221 -176
- package/src/components/panels/systemSettings/styles.module.css +135 -8
- package/src/components/panels/traces/GridLines.tsx +1 -1
- package/src/components/panels/traces/TimeGrid.tsx +3 -3
- package/src/components/panels/traces/TraceLane.tsx +1 -1
- package/src/components/panels/traces/index.module.css +1 -8
- package/src/components/panels/traces/index.tsx +8 -4
- package/src/components/panels/traces/useDerivedSpans.ts +241 -146
- package/src/components/panels/traces/utils.ts +8 -0
- package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
- package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
- package/src/components/panels/variables/index.tsx +2 -2
- package/src/components/panels/variables/styles.module.css +4 -91
- package/src/components/primitives/icon.module.css +4 -4
- package/src/components/sockets/input/index.tsx +9 -2
- package/src/components/sockets/input/styles.module.css +2 -3
- package/src/components/sockets/output/index.tsx +10 -3
- package/src/components/sockets/output/styles.module.css +1 -6
- package/src/css/notes.css +135 -0
- package/src/css/prosemirror.css +3 -3
- package/src/css/rc-dock.css +143 -43
- package/src/css/rc-menu.css +56 -55
- package/src/css/themes/kiberon.css +127 -0
- package/src/css/vars.css +197 -13
- package/src/css/vscode-elements.css +124 -0
- package/src/generators/CallSubgraphGenerator.tsx +136 -0
- package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
- package/src/generators/GraphBoundaryGenerator.module.css +32 -0
- package/src/generators/GraphBoundaryGenerator.tsx +193 -0
- package/src/generators/SequenceGenerator.tsx +2 -2
- package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
- package/src/generators/SwitchOnStringGenerator.tsx +2 -2
- package/src/generators/callSubgraphSync.ts +126 -0
- package/src/generators/registerDefaultGenerators.ts +21 -0
- package/src/generators/registerDefaults.ts +26 -0
- package/src/hooks/useBehaveGraphFlow.ts +2 -2
- package/src/hooks/useFlowHandlers.ts +47 -9
- package/src/hooks/useWasdPan.ts +26 -4
- package/src/index.css +4 -16
- package/src/index.ts +17 -0
- package/src/manifest/contributionRegistry.ts +93 -0
- package/src/manifest/index.ts +4 -0
- package/src/manifest/loadManifest.ts +82 -0
- package/src/manifest/manifestPlugin.ts +29 -0
- package/src/manifest/passthroughValueType.ts +40 -0
- package/src/plugin/alignment/index.ts +22 -12
- package/src/plugin/autosave/controller.ts +366 -0
- package/src/plugin/autosave/index.tsx +114 -0
- package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
- package/src/plugin/autosave/panel/index.tsx +1 -0
- package/src/plugin/autosave/panel/styles.module.css +56 -0
- package/src/plugin/autosave/settings.ts +65 -0
- package/src/plugin/autosave/storage.ts +147 -0
- package/src/plugin/docs/index.tsx +2 -4
- package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
- package/src/plugin/docs/panel/index.tsx +15 -194
- package/src/plugin/docs/panel/styles.module.css +8 -8
- package/src/plugin/graphrunner/actions.ts +258 -185
- package/src/plugin/graphrunner/buttons.tsx +34 -26
- package/src/plugin/graphrunner/client.ts +4 -1
- package/src/plugin/graphrunner/index.tsx +29 -100
- package/src/plugin/graphrunner/panel.tsx +2 -2
- package/src/plugin/graphrunner/runController.ts +283 -0
- package/src/plugin/graphrunner/runner.ts +21 -192
- package/src/plugin/graphrunner/store.ts +14 -24
- package/src/plugin/graphrunner/styles.module.css +17 -57
- package/src/plugin/graphrunner/transport.ts +26 -0
- package/src/plugin/graphrunner/types.ts +21 -0
- package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
- package/src/plugin/graphrunner-local/index.tsx +8 -2
- package/src/plugin/graphrunner-local/panel.tsx +131 -175
- package/src/plugin/graphrunner-local/styles.module.css +57 -76
- package/src/plugin/graphrunner-local/transport.ts +151 -184
- package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
- package/src/plugin/graphrunner-webworker/index.tsx +4 -10
- package/src/plugin/graphrunner-webworker/store.ts +9 -0
- package/src/plugin/kitchen-sink/index.ts +38 -0
- package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
- package/src/{layout → plugin/layout}/elk.ts +22 -6
- package/src/plugin/layout/index.ts +80 -0
- package/src/plugin/notes/FormatToolbar.tsx +200 -0
- package/src/plugin/notes/index.tsx +191 -0
- package/src/plugin/notes/nodeActions.ts +100 -0
- package/src/plugin/notes/note.tsx +20 -0
- package/src/plugin/notes/noteImpl.tsx +89 -0
- package/src/plugin/realtime/realtimeRunner.ts +58 -4
- package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
- package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
- package/src/specifics/VariableGetSpecific.tsx +2 -2
- package/src/specifics/VariableSetSpecific.tsx +2 -2
- package/src/store/actions.tsx +5 -5
- package/src/store/commands.ts +278 -0
- package/src/store/contextMenu.ts +192 -0
- package/src/store/conversions.ts +47 -0
- package/src/store/flow.tsx +23 -38
- package/src/store/graphMeta.ts +39 -0
- package/src/store/hotKeys.tsx +301 -260
- package/src/store/layers.ts +3 -3
- package/src/store/registry.ts +12 -4
- package/src/store/selection.ts +3 -3
- package/src/store/settings.ts +82 -82
- package/src/store/settingsSchema.ts +210 -0
- package/src/store/tabs.ts +5 -1
- package/src/store/traces.ts +3 -3
- package/src/system/graph.ts +11 -14
- package/src/system/graphSession.ts +172 -0
- package/src/system/index.ts +3 -0
- package/src/system/notifications.ts +13 -0
- package/src/system/persistence.ts +82 -0
- package/src/system/plugin.ts +28 -0
- package/src/system/provider.tsx +64 -0
- package/src/system/system.ts +518 -88
- package/src/system/tabLoader.tsx +70 -32
- package/src/system/undoRedo.ts +1 -1
- package/src/transformers/Uigraph.ts +5 -4
- package/src/transformers/contract.ts +87 -0
- package/src/transformers/flowToBehave.ts +13 -5
- package/src/types/nodes.ts +8 -3
- package/src/types.ts +2 -0
- package/src/util/autoConvert.ts +200 -0
- package/src/util/isValidConnection.ts +23 -2
- package/stories/defaults/defaultStoryProvider.tsx +17 -14
- package/stories/defaults/systemGenerator.ts +6 -1
- package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
- package/tests/autoConvert.test.ts +329 -0
- package/tests/autosavePlugin.test.ts +204 -0
- package/tests/callSubgraphSync.test.ts +148 -0
- package/tests/commandRegistry.test.ts +137 -0
- package/tests/contract.test.ts +51 -0
- package/tests/contractSerialize.test.ts +62 -0
- package/tests/deriveSpans.test.ts +71 -0
- package/tests/flowToBehave.test.ts +2 -1
- package/tests/hotkeys.test.ts +79 -0
- package/tests/keepAliveLifecycle.test.ts +167 -0
- package/tests/loadManifest.test.ts +113 -0
- package/tests/noteMarkdown.test.ts +65 -0
- package/tests/notesPlugin.test.ts +162 -0
- package/tests/persistence.test.ts +51 -0
- package/tests/saveLoad.test.ts +7 -6
- package/tests/settings.test.ts +178 -0
- package/tests/traceStore.test.ts +46 -0
- package/tests/visual/README.md +2 -2
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
- package/tests/visual/panels.visual.test.tsx +3 -3
- package/tests/wasdPan.test.ts +71 -0
- package/vitest.config.ts +1 -1
- package/vitest.visual.config.ts +7 -0
- package/.storybook/vscode.css +0 -814
- package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
- package/src/components/nodes/comment/comment.tsx +0 -103
- package/src/components/nodes/comment/styles.module.css +0 -150
- package/src/components/panels/conversation/index.module.css +0 -151
- package/src/components/panels/conversation/index.tsx +0 -162
- package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
- package/src/css/vscode.css +0 -13
- package/src/hooks/useDetachNodes.ts +0 -39
- package/src/plugin/graphrunner-webworker/types.ts +0 -17
- package/src/specifics/registerDefaultSpecifics.ts +0 -5
- package/src/store/chat.ts +0 -73
- package/src/store/graphRunnerClient.ts +0 -110
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo } from 'react';
|
|
2
|
+
import { useStore } from 'zustand';
|
|
3
|
+
import {
|
|
4
|
+
VscodeButton,
|
|
5
|
+
VscodeOption,
|
|
6
|
+
VscodeSingleSelect,
|
|
7
|
+
VscodeTextfield
|
|
8
|
+
} from '@vscode-elements/react-elements';
|
|
9
|
+
import { Trash } from 'iconoir-react';
|
|
10
|
+
import { useGraph } from '@/system/provider';
|
|
11
|
+
import type { SocketGeneratorRenderProps } from '@/store/socketGenerator';
|
|
12
|
+
import type { Socket } from '@/types';
|
|
13
|
+
import type { IBehaveNode } from '@/types/nodes.js';
|
|
14
|
+
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph/Graphs/IO/NodeSpecJSON';
|
|
15
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
16
|
+
import {
|
|
17
|
+
GRAPH_INPUT_TYPE,
|
|
18
|
+
GRAPH_OUTPUT_TYPE,
|
|
19
|
+
paramId,
|
|
20
|
+
type ContractParam
|
|
21
|
+
} from '@/transformers/contract';
|
|
22
|
+
import styles from './GraphBoundaryGenerator.module.css';
|
|
23
|
+
|
|
24
|
+
type BoundaryKind = 'input' | 'output';
|
|
25
|
+
|
|
26
|
+
export function getGraphInputGenerator() {
|
|
27
|
+
return {
|
|
28
|
+
name: `${GRAPH_INPUT_TYPE}.socketGenerator`,
|
|
29
|
+
check: (spec: NodeSpecJSON) => spec?.type === GRAPH_INPUT_TYPE,
|
|
30
|
+
render: (props: SocketGeneratorRenderProps) => (
|
|
31
|
+
<GraphBoundaryGenerator {...props} kind="input" />
|
|
32
|
+
)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getGraphOutputGenerator() {
|
|
37
|
+
return {
|
|
38
|
+
name: `${GRAPH_OUTPUT_TYPE}.socketGenerator`,
|
|
39
|
+
check: (spec: NodeSpecJSON) => spec?.type === GRAPH_OUTPUT_TYPE,
|
|
40
|
+
render: (props: SocketGeneratorRenderProps) => (
|
|
41
|
+
<GraphBoundaryGenerator {...props} kind="output" />
|
|
42
|
+
)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Properties-panel editor for a subgraph boundary node's contract: add / name /
|
|
48
|
+
* type the inputs (`graph/input`) or outputs (`graph/output`). The configured
|
|
49
|
+
* params are mirrored onto the node's dynamic ports , `graph/input` exposes them
|
|
50
|
+
* as outputs, `graph/output` as inputs (the `flow` socket is static on the core
|
|
51
|
+
* node).
|
|
52
|
+
*/
|
|
53
|
+
const GraphBoundaryGenerator: React.FC<
|
|
54
|
+
SocketGeneratorRenderProps & { kind: BoundaryKind }
|
|
55
|
+
> = ({ node, kind }) => {
|
|
56
|
+
const session = useGraph();
|
|
57
|
+
// Select the stable `values` object then derive , a freshly built array inside
|
|
58
|
+
// the selector would change identity every render and loop.
|
|
59
|
+
const values = useStore(session.editor.registry, (s) => s.values);
|
|
60
|
+
const valueTypes = useMemo(
|
|
61
|
+
() => Object.keys(values).filter((t) => t !== 'flow'),
|
|
62
|
+
[values]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const params: ContractParam[] = useMemo(
|
|
66
|
+
() =>
|
|
67
|
+
Array.isArray(node.data.configuration?.parameters)
|
|
68
|
+
? (node.data.configuration!.parameters as ContractParam[])
|
|
69
|
+
: [],
|
|
70
|
+
[node.data]
|
|
71
|
+
);
|
|
72
|
+
const paramsKey = JSON.stringify(params);
|
|
73
|
+
|
|
74
|
+
// Mirror params onto dynamic ports. The socket identity (name/key/handle id)
|
|
75
|
+
// is the stable param id; the display label is the editable name.
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const sockets: Socket[] = params.map((param) => {
|
|
78
|
+
const id = paramId(param);
|
|
79
|
+
return {
|
|
80
|
+
name: id,
|
|
81
|
+
key: id,
|
|
82
|
+
label: param.name || id,
|
|
83
|
+
valueType: param.valueTypeName || 'string'
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
session.nodeStore.getState().setNodes((prev) =>
|
|
87
|
+
prev.map((n) => {
|
|
88
|
+
if (n.id !== node.id) return n;
|
|
89
|
+
return {
|
|
90
|
+
...n,
|
|
91
|
+
data: {
|
|
92
|
+
...n.data,
|
|
93
|
+
dynamicPorts: {
|
|
94
|
+
...n.data?.dynamicPorts,
|
|
95
|
+
...(kind === 'input' ? { outputs: sockets } : { inputs: sockets })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} as IBehaveNode;
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
102
|
+
}, [paramsKey, kind, node.id, session.nodeStore]);
|
|
103
|
+
|
|
104
|
+
const update = useCallback(
|
|
105
|
+
(next: ContractParam[]) => {
|
|
106
|
+
session.nodeStore.getState().setNodes((prev) =>
|
|
107
|
+
prev.map((n) => {
|
|
108
|
+
if (n.id !== node.id) return n;
|
|
109
|
+
return {
|
|
110
|
+
...n,
|
|
111
|
+
data: {
|
|
112
|
+
...n.data,
|
|
113
|
+
configuration: { ...n.data?.configuration, parameters: next }
|
|
114
|
+
}
|
|
115
|
+
} as IBehaveNode;
|
|
116
|
+
})
|
|
117
|
+
);
|
|
118
|
+
},
|
|
119
|
+
[node.id, session]
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const addParam = useCallback(() => {
|
|
123
|
+
const base = kind === 'input' ? 'in' : 'out';
|
|
124
|
+
const existing = new Set(params.map((p) => p.name));
|
|
125
|
+
let i = params.length + 1;
|
|
126
|
+
let name = `${base}${i}`;
|
|
127
|
+
while (existing.has(name)) name = `${base}${++i}`;
|
|
128
|
+
update([
|
|
129
|
+
...params,
|
|
130
|
+
{ id: uuidv4(), name, valueTypeName: valueTypes[0] ?? 'string' }
|
|
131
|
+
]);
|
|
132
|
+
}, [kind, params, update, valueTypes]);
|
|
133
|
+
|
|
134
|
+
const setName = useCallback(
|
|
135
|
+
(index: number, name: string) =>
|
|
136
|
+
update(params.map((p, i) => (i === index ? { ...p, name } : p))),
|
|
137
|
+
[params, update]
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const setType = useCallback(
|
|
141
|
+
(index: number, valueTypeName: string) =>
|
|
142
|
+
update(params.map((p, i) => (i === index ? { ...p, valueTypeName } : p))),
|
|
143
|
+
[params, update]
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const remove = useCallback(
|
|
147
|
+
(index: number) => update(params.filter((_, i) => i !== index)),
|
|
148
|
+
[params, update]
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<div className={styles.list}>
|
|
153
|
+
{params.map((param, index) => (
|
|
154
|
+
<div key={param.id ?? index} className={styles.param}>
|
|
155
|
+
<div className={styles.topRow}>
|
|
156
|
+
<VscodeTextfield
|
|
157
|
+
className={styles.name}
|
|
158
|
+
value={param.name}
|
|
159
|
+
placeholder={`${kind} name`}
|
|
160
|
+
onChange={(e: any) =>
|
|
161
|
+
setName(index, String(e?.target?.value ?? ''))
|
|
162
|
+
}
|
|
163
|
+
/>
|
|
164
|
+
<VscodeButton
|
|
165
|
+
secondary
|
|
166
|
+
iconOnly
|
|
167
|
+
title={`Remove ${kind}`}
|
|
168
|
+
onClick={() => remove(index)}
|
|
169
|
+
>
|
|
170
|
+
<Trash />
|
|
171
|
+
</VscodeButton>
|
|
172
|
+
</div>
|
|
173
|
+
<VscodeSingleSelect
|
|
174
|
+
className={styles.type}
|
|
175
|
+
value={param.valueTypeName}
|
|
176
|
+
onChange={(e: any) =>
|
|
177
|
+
setType(index, String(e?.target?.value ?? 'string'))
|
|
178
|
+
}
|
|
179
|
+
>
|
|
180
|
+
{valueTypes.map((t) => (
|
|
181
|
+
<VscodeOption key={t} value={t}>
|
|
182
|
+
{t}
|
|
183
|
+
</VscodeOption>
|
|
184
|
+
))}
|
|
185
|
+
</VscodeSingleSelect>
|
|
186
|
+
</div>
|
|
187
|
+
))}
|
|
188
|
+
<VscodeButton secondary onClick={addParam}>
|
|
189
|
+
+ Add {kind}
|
|
190
|
+
</VscodeButton>
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
};
|
|
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
|
|
|
2
2
|
import { VscodeButton } from '@vscode-elements/react-elements';
|
|
3
3
|
import { Plus, Minus } from 'iconoir-react';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { useGraph } from '@/system/provider';
|
|
6
6
|
import type { SocketGeneratorRenderProps } from '@/store/socketGenerator';
|
|
7
7
|
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph/Graphs/IO/NodeSpecJSON';
|
|
8
8
|
|
|
@@ -18,7 +18,7 @@ export function getSequenceGenerator() {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const SequenceGenerator: React.FC<SocketGeneratorRenderProps> = ({ node }) => {
|
|
21
|
-
const system =
|
|
21
|
+
const system = useGraph();
|
|
22
22
|
|
|
23
23
|
const numOutputs = node.data.configuration?.numOutputs ?? 0;
|
|
24
24
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from '@vscode-elements/react-elements';
|
|
8
8
|
import { Plus, Minus } from 'iconoir-react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useGraph } from '@/system/provider';
|
|
11
11
|
import type { SocketGeneratorRenderProps } from '@/store/socketGenerator';
|
|
12
12
|
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph/Graphs/IO/NodeSpecJSON';
|
|
13
13
|
|
|
@@ -24,7 +24,7 @@ export function getSwitchOnIntegerGenerator() {
|
|
|
24
24
|
const SwitchOnIntegerGenerator: React.FC<SocketGeneratorRenderProps> = ({
|
|
25
25
|
node
|
|
26
26
|
}) => {
|
|
27
|
-
const system =
|
|
27
|
+
const system = useGraph();
|
|
28
28
|
|
|
29
29
|
const numCases = node.data.configuration?.numCases ?? 0;
|
|
30
30
|
const caseLabels = node.data.configuration?.caseLabels ?? {};
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from '@vscode-elements/react-elements';
|
|
8
8
|
import { Plus, Minus } from 'iconoir-react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useGraph } from '@/system/provider';
|
|
11
11
|
import type { SocketGeneratorRenderProps } from '@/store/socketGenerator';
|
|
12
12
|
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph/Graphs/IO/NodeSpecJSON';
|
|
13
13
|
|
|
@@ -24,7 +24,7 @@ export function getSwitchOnStringGenerator() {
|
|
|
24
24
|
const SwitchOnStringGenerator: React.FC<SocketGeneratorRenderProps> = ({
|
|
25
25
|
node
|
|
26
26
|
}) => {
|
|
27
|
-
const system =
|
|
27
|
+
const system = useGraph();
|
|
28
28
|
|
|
29
29
|
const numCases = node.data.configuration?.numCases ?? 0;
|
|
30
30
|
const caseLabels = node.data.configuration?.caseLabels ?? {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { System } from '@/system/system';
|
|
2
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
3
|
+
import type { IBehaveNode } from '@/types/nodes';
|
|
4
|
+
import {
|
|
5
|
+
CALL_SUBGRAPH_TYPE,
|
|
6
|
+
contractToParams,
|
|
7
|
+
deriveContract,
|
|
8
|
+
paramsToSockets,
|
|
9
|
+
type ContractParam
|
|
10
|
+
} from '@/transformers/contract';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Stable string key for a session's contract (its graph/input + graph/output
|
|
14
|
+
* params). Used to detect *contract* changes and ignore unrelated node edits
|
|
15
|
+
* (e.g. dragging), so we only repropagate when the boundary actually changes.
|
|
16
|
+
*/
|
|
17
|
+
const contractKey = (session: GraphSession): string =>
|
|
18
|
+
JSON.stringify(deriveContract(session.nodeStore.getState().nodes));
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Reconcile every Call Subgraph node in every open graph with the *current*
|
|
22
|
+
* contract of the subgraph it references. Idempotent: a node is only rewritten
|
|
23
|
+
* when its stored contract/ports actually differ, so this converges and never
|
|
24
|
+
* loops (rewriting a call node does not change its host graph's contract).
|
|
25
|
+
*/
|
|
26
|
+
const resyncAllCallNodes = (editor: System): void => {
|
|
27
|
+
const sessions = editor.activeGraph.getState().sessions;
|
|
28
|
+
|
|
29
|
+
for (const target of Object.values(sessions)) {
|
|
30
|
+
let mutated = false;
|
|
31
|
+
|
|
32
|
+
const nextNodes = target.nodeStore.getState().nodes.map((node) => {
|
|
33
|
+
if (node.data?.type !== CALL_SUBGRAPH_TYPE) return node;
|
|
34
|
+
|
|
35
|
+
const subgraphId = String(node.data?.configuration?.subgraphId ?? '');
|
|
36
|
+
const subgraph = subgraphId ? sessions[subgraphId] : undefined;
|
|
37
|
+
// Referenced graph not open (e.g. its tab was closed): leave the last
|
|
38
|
+
// known contract in place rather than wiping the node's ports.
|
|
39
|
+
if (!subgraph) return node;
|
|
40
|
+
|
|
41
|
+
const contract = deriveContract(subgraph.nodeStore.getState().nodes);
|
|
42
|
+
const inputs: ContractParam[] = contractToParams(contract.graphInputs);
|
|
43
|
+
const outputs: ContractParam[] = contractToParams(contract.graphOutputs);
|
|
44
|
+
const inputSockets = paramsToSockets(inputs);
|
|
45
|
+
const outputSockets = paramsToSockets(outputs);
|
|
46
|
+
|
|
47
|
+
const currentConfig = {
|
|
48
|
+
inputs: node.data?.configuration?.inputs ?? [],
|
|
49
|
+
outputs: node.data?.configuration?.outputs ?? []
|
|
50
|
+
};
|
|
51
|
+
const currentPorts = {
|
|
52
|
+
inputs: node.data?.dynamicPorts?.inputs ?? [],
|
|
53
|
+
outputs: node.data?.dynamicPorts?.outputs ?? []
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
JSON.stringify(currentConfig) === JSON.stringify({ inputs, outputs }) &&
|
|
58
|
+
JSON.stringify(currentPorts) ===
|
|
59
|
+
JSON.stringify({ inputs: inputSockets, outputs: outputSockets })
|
|
60
|
+
) {
|
|
61
|
+
return node;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
mutated = true;
|
|
65
|
+
return {
|
|
66
|
+
...node,
|
|
67
|
+
data: {
|
|
68
|
+
...node.data,
|
|
69
|
+
configuration: {
|
|
70
|
+
...node.data?.configuration,
|
|
71
|
+
inputs,
|
|
72
|
+
outputs
|
|
73
|
+
},
|
|
74
|
+
dynamicPorts: {
|
|
75
|
+
...node.data?.dynamicPorts,
|
|
76
|
+
inputs: inputSockets,
|
|
77
|
+
outputs: outputSockets
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} as IBehaveNode;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (mutated) target.nodeStore.getState().setNodes(() => nextNodes);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Keep Call Subgraph nodes live with the graphs they reference. Without this a
|
|
89
|
+
* call node only captures the subgraph's contract at selection time; editing the
|
|
90
|
+
* subgraph's inputs/outputs afterwards would leave callers stale.
|
|
91
|
+
*
|
|
92
|
+
* Implemented as an editor session extension: every open graph (existing and
|
|
93
|
+
* future) watches its own contract, and when it changes we repropagate to all
|
|
94
|
+
* call nodes referencing it across every graph. Returns a disposer.
|
|
95
|
+
*/
|
|
96
|
+
export function setupCallSubgraphSync(editor: System): () => void {
|
|
97
|
+
const unsubscribes = new Map<string, () => void>();
|
|
98
|
+
|
|
99
|
+
const watch = (session: GraphSession) => {
|
|
100
|
+
if (unsubscribes.has(session.id)) return;
|
|
101
|
+
|
|
102
|
+
let last = contractKey(session);
|
|
103
|
+
const unsub = session.nodeStore.subscribe(() => {
|
|
104
|
+
const next = contractKey(session);
|
|
105
|
+
if (next === last) return; // ignore non-contract edits (drags, etc.)
|
|
106
|
+
last = next;
|
|
107
|
+
resyncAllCallNodes(editor);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
unsubscribes.set(session.id, unsub);
|
|
111
|
+
session.onDispose(() => {
|
|
112
|
+
unsubscribes.get(session.id)?.();
|
|
113
|
+
unsubscribes.delete(session.id);
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const unregister = editor.registerSessionExtension(watch);
|
|
118
|
+
// Reconcile graphs already open (e.g. a project loaded from disk) once.
|
|
119
|
+
resyncAllCallNodes(editor);
|
|
120
|
+
|
|
121
|
+
return () => {
|
|
122
|
+
unregister();
|
|
123
|
+
for (const unsub of unsubscribes.values()) unsub();
|
|
124
|
+
unsubscribes.clear();
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -3,6 +3,11 @@ import { getSwitchOnStringGenerator } from '../generators/SwitchOnStringGenerato
|
|
|
3
3
|
import { getSwitchOnIntegerGenerator } from '../generators/SwitchOnIntegerGenerator';
|
|
4
4
|
import { getCustomEventOnTriggeredGenerator } from '../generators/CustomEventOnTriggeredGenerator';
|
|
5
5
|
import { getSequenceGenerator } from '../generators/SequenceGenerator';
|
|
6
|
+
import {
|
|
7
|
+
getGraphInputGenerator,
|
|
8
|
+
getGraphOutputGenerator
|
|
9
|
+
} from '../generators/GraphBoundaryGenerator';
|
|
10
|
+
import { getCallSubgraphGenerator } from '../generators/CallSubgraphGenerator';
|
|
6
11
|
|
|
7
12
|
export function registerDefaultSocketGenerators(system: System): () => void {
|
|
8
13
|
const store = system.socketGeneratorStore.getState();
|
|
@@ -19,6 +24,15 @@ export function registerDefaultSocketGenerators(system: System): () => void {
|
|
|
19
24
|
const sequence = getSequenceGenerator();
|
|
20
25
|
store.registerGenerator(sequence);
|
|
21
26
|
|
|
27
|
+
const graphInput = getGraphInputGenerator();
|
|
28
|
+
store.registerGenerator(graphInput);
|
|
29
|
+
|
|
30
|
+
const graphOutput = getGraphOutputGenerator();
|
|
31
|
+
store.registerGenerator(graphOutput);
|
|
32
|
+
|
|
33
|
+
const callSubgraph = getCallSubgraphGenerator();
|
|
34
|
+
store.registerGenerator(callSubgraph);
|
|
35
|
+
|
|
22
36
|
return () => {
|
|
23
37
|
system.socketGeneratorStore
|
|
24
38
|
.getState()
|
|
@@ -30,5 +44,12 @@ export function registerDefaultSocketGenerators(system: System): () => void {
|
|
|
30
44
|
.getState()
|
|
31
45
|
.unregisterGenerator(customEventOnTriggered.name);
|
|
32
46
|
system.socketGeneratorStore.getState().unregisterGenerator(sequence.name);
|
|
47
|
+
system.socketGeneratorStore.getState().unregisterGenerator(graphInput.name);
|
|
48
|
+
system.socketGeneratorStore
|
|
49
|
+
.getState()
|
|
50
|
+
.unregisterGenerator(graphOutput.name);
|
|
51
|
+
system.socketGeneratorStore
|
|
52
|
+
.getState()
|
|
53
|
+
.unregisterGenerator(callSubgraph.name);
|
|
33
54
|
};
|
|
34
55
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { System } from '@/system/system';
|
|
2
|
+
import { registerDefaultSocketGenerators } from './registerDefaultGenerators';
|
|
3
|
+
import { setupCallSubgraphSync } from './callSubgraphSync';
|
|
4
|
+
|
|
5
|
+
/** Editors that already had their built-in content registered. */
|
|
6
|
+
const initialized = new WeakSet<System>();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Register the editor's built-in content , the default socket generators and the
|
|
10
|
+
* call-subgraph contract sync , on an editor instance.
|
|
11
|
+
*
|
|
12
|
+
* Idempotent per editor: safe to call from every graph-canvas mount (multiple
|
|
13
|
+
* tabs) without double-registering. The default content is editor-lifetime; the
|
|
14
|
+
* subgraph sync's per-session subscriptions clean themselves up on session
|
|
15
|
+
* dispose.
|
|
16
|
+
*
|
|
17
|
+
* A host that wants a blank or fully custom editor can simply not rely on the
|
|
18
|
+
* canvas's auto-call and register its own content instead.
|
|
19
|
+
*/
|
|
20
|
+
export function registerDefaults(editor: System): void {
|
|
21
|
+
if (initialized.has(editor)) return;
|
|
22
|
+
initialized.add(editor);
|
|
23
|
+
|
|
24
|
+
registerDefaultSocketGenerators(editor);
|
|
25
|
+
setupCallSubgraphSync(editor);
|
|
26
|
+
}
|
|
@@ -4,7 +4,7 @@ import { behaveToFlow } from '../transformers/behaveToFlow.js';
|
|
|
4
4
|
import { flowToBehave } from '../transformers/flowToBehave.js';
|
|
5
5
|
import { autoLayout } from '../util/autoLayout.js';
|
|
6
6
|
import { hasPositionMetaData } from '../util/hasPositionMetaData.js';
|
|
7
|
-
import {
|
|
7
|
+
import { useGraph } from '@/system/provider.js';
|
|
8
8
|
import { useStore } from 'zustand';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -22,7 +22,7 @@ export const useBehaveGraphFlow = ({
|
|
|
22
22
|
specJson: NodeSpecJSON[] | undefined;
|
|
23
23
|
}) => {
|
|
24
24
|
const [graphJson, setStoredGraphJson] = useState<GraphJSON | undefined>();
|
|
25
|
-
const sys =
|
|
25
|
+
const sys = useGraph();
|
|
26
26
|
|
|
27
27
|
const {
|
|
28
28
|
nodes,
|
|
@@ -15,9 +15,10 @@ import type {
|
|
|
15
15
|
import { v4 as uuidv4 } from 'uuid';
|
|
16
16
|
|
|
17
17
|
import { calculateNewEdge } from '../util/calculateNewEdge.js';
|
|
18
|
+
import { buildConverterInsertion } from '../util/autoConvert.js';
|
|
18
19
|
import { getNodePickerFilters } from '../util/getPickerFilters.js';
|
|
19
20
|
import { useBehaveGraphFlow } from './useBehaveGraphFlow.js';
|
|
20
|
-
import {
|
|
21
|
+
import { useGraph } from '@/system/provider.js';
|
|
21
22
|
import type { ExtendedNodeSpecJSON } from '@/components/contextMenus/NodePicker.js';
|
|
22
23
|
import {
|
|
23
24
|
addFloatingTab,
|
|
@@ -56,7 +57,7 @@ export const useFlowHandlers = ({
|
|
|
56
57
|
nodes: Node[];
|
|
57
58
|
specJSON: NodeSpecJSON[] | undefined;
|
|
58
59
|
}) => {
|
|
59
|
-
const sys =
|
|
60
|
+
const sys = useGraph();
|
|
60
61
|
const [lastConnectStart, setLastConnectStart] =
|
|
61
62
|
useState<OnConnectStartParams>();
|
|
62
63
|
const [nodePickerVisibility, setNodePickerVisibility] =
|
|
@@ -66,6 +67,43 @@ export const useFlowHandlers = ({
|
|
|
66
67
|
if (connection.source === null) return;
|
|
67
68
|
if (connection.target === null) return;
|
|
68
69
|
|
|
70
|
+
// Auto-convert: if the value types differ but a converter node exists,
|
|
71
|
+
// splice the converter in between instead of a direct edge.
|
|
72
|
+
const autoConvert = sys.editor.systemSettings.getState().autoConvert;
|
|
73
|
+
if (autoConvert && specJSON) {
|
|
74
|
+
const insertion = buildConverterInsertion(
|
|
75
|
+
connection,
|
|
76
|
+
sys.nodeStore.getState().nodes,
|
|
77
|
+
specJSON,
|
|
78
|
+
sys.editor.conversionStore.getState().conversions
|
|
79
|
+
);
|
|
80
|
+
if (insertion) {
|
|
81
|
+
const { node, edges: convEdges } = insertion;
|
|
82
|
+
sys.undoManager.execute({
|
|
83
|
+
name: 'Auto-convert connection',
|
|
84
|
+
execute: () => {
|
|
85
|
+
sys.nodeStore.getState().addNode(node);
|
|
86
|
+
sys.edgeStore
|
|
87
|
+
.getState()
|
|
88
|
+
.setEdges([...sys.edgeStore.getState().edges, ...convEdges]);
|
|
89
|
+
convEdges.forEach((e) => sys.pubsub.publish('edge:added', e));
|
|
90
|
+
},
|
|
91
|
+
undo: () => {
|
|
92
|
+
const ids = new Set(convEdges.map((e) => e.id));
|
|
93
|
+
sys.nodeStore
|
|
94
|
+
.getState()
|
|
95
|
+
.setNodes((ns) => ns.filter((n) => n.id !== node.id));
|
|
96
|
+
sys.edgeStore
|
|
97
|
+
.getState()
|
|
98
|
+
.setEdges(
|
|
99
|
+
sys.edgeStore.getState().edges.filter((e) => !ids.has(e.id))
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
69
107
|
const newEdge = {
|
|
70
108
|
id: uuidv4(),
|
|
71
109
|
source: connection.source,
|
|
@@ -81,7 +119,7 @@ export const useFlowHandlers = ({
|
|
|
81
119
|
}
|
|
82
120
|
]);
|
|
83
121
|
},
|
|
84
|
-
[onEdgesChange]
|
|
122
|
+
[onEdgesChange, sys, specJSON]
|
|
85
123
|
);
|
|
86
124
|
|
|
87
125
|
const closeNodePicker = useCallback(() => {
|
|
@@ -89,9 +127,9 @@ export const useFlowHandlers = ({
|
|
|
89
127
|
setNodePickerVisibility(undefined);
|
|
90
128
|
|
|
91
129
|
// Close the nodepicker panel from rc-dock
|
|
92
|
-
const currentLayout = sys.tabStore.getState().layout;
|
|
130
|
+
const currentLayout = sys.editor.tabStore.getState().layout;
|
|
93
131
|
const newLayout = removeTabFromLayout(currentLayout, 'nodepicker');
|
|
94
|
-
sys.tabStore.getState().setLayout(newLayout);
|
|
132
|
+
sys.editor.tabStore.getState().setLayout(newLayout);
|
|
95
133
|
}, [sys]);
|
|
96
134
|
|
|
97
135
|
const handleAddNode = useCallback(
|
|
@@ -171,7 +209,7 @@ export const useFlowHandlers = ({
|
|
|
171
209
|
sys.refStore.getState().setRef('nodePickerPosition', screenPos);
|
|
172
210
|
|
|
173
211
|
// Open as floating rc-dock panel
|
|
174
|
-
const currentLayout = sys.tabStore.getState().layout;
|
|
212
|
+
const currentLayout = sys.editor.tabStore.getState().layout;
|
|
175
213
|
|
|
176
214
|
// Close existing nodepicker if open
|
|
177
215
|
const existingPanel = findTabInLayout(currentLayout, 'nodepicker');
|
|
@@ -194,7 +232,7 @@ export const useFlowHandlers = ({
|
|
|
194
232
|
height: 500
|
|
195
233
|
});
|
|
196
234
|
|
|
197
|
-
sys.tabStore.getState().setLayout(newLayout);
|
|
235
|
+
sys.editor.tabStore.getState().setLayout(newLayout);
|
|
198
236
|
} else {
|
|
199
237
|
setLastConnectStart(undefined);
|
|
200
238
|
}
|
|
@@ -217,7 +255,7 @@ export const useFlowHandlers = ({
|
|
|
217
255
|
sys.refStore.getState().setRef('nodePickerPosition', screenPos);
|
|
218
256
|
|
|
219
257
|
// Open as floating rc-dock panel
|
|
220
|
-
const currentLayout = sys.tabStore.getState().layout;
|
|
258
|
+
const currentLayout = sys.editor.tabStore.getState().layout;
|
|
221
259
|
|
|
222
260
|
// Close existing nodepicker if open
|
|
223
261
|
const existingPanel = findTabInLayout(currentLayout, 'nodepicker');
|
|
@@ -240,7 +278,7 @@ export const useFlowHandlers = ({
|
|
|
240
278
|
height: 500
|
|
241
279
|
});
|
|
242
280
|
|
|
243
|
-
sys.tabStore.getState().setLayout(newLayout);
|
|
281
|
+
sys.editor.tabStore.getState().setLayout(newLayout);
|
|
244
282
|
},
|
|
245
283
|
[sys]
|
|
246
284
|
);
|
package/src/hooks/useWasdPan.ts
CHANGED
|
@@ -9,11 +9,33 @@ export type UseWasdPanOptions = {
|
|
|
9
9
|
enabled?: boolean;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const isEditableElement = (element: HTMLElement): boolean => {
|
|
13
|
+
const tag = element.tagName?.toLowerCase();
|
|
14
|
+
// Contenteditable surfaces (e.g. the notes plugin's prosemirror editor) are
|
|
15
|
+
// divs, so checking the tag alone is not enough — WASD must type, not pan.
|
|
16
|
+
return (
|
|
17
|
+
tag === 'input' ||
|
|
18
|
+
tag === 'textarea' ||
|
|
19
|
+
tag === 'select' ||
|
|
20
|
+
element.isContentEditable
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const isEventFromEditable = (event: KeyboardEvent) => {
|
|
25
|
+
// Events from inside a web component are retargeted: at the window listener
|
|
26
|
+
// `event.target` is the custom-element host (e.g. the conversation panel's
|
|
27
|
+
// <vscode-textfield>), not the <input> in its shadow DOM. composedPath()
|
|
28
|
+
// exposes the real target chain, so walk it and check every element.
|
|
29
|
+
const path =
|
|
30
|
+
typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
31
|
+
if (path.length > 0) {
|
|
32
|
+
return path.some(
|
|
33
|
+
(node) => node instanceof HTMLElement && isEditableElement(node)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
13
36
|
const target = event.target as HTMLElement | null;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return tag !== 'div';
|
|
37
|
+
if (!target) return false;
|
|
38
|
+
return isEditableElement(target);
|
|
17
39
|
};
|
|
18
40
|
|
|
19
41
|
export const useWasdPan = ({
|
package/src/index.css
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
@import 'rc-menu/assets/index.css';
|
|
3
3
|
@import "rc-dock/dist/rc-dock-dark.css";
|
|
4
4
|
|
|
5
|
-
@import "./css/vscode.css";
|
|
6
5
|
@import "./css/vars.css";
|
|
6
|
+
@import "./css/themes/kiberon.css";
|
|
7
|
+
@import "./css/vscode-elements.css";
|
|
7
8
|
@import "./css/rc-dock.css";
|
|
8
9
|
@import "./css/rc-menu.css";
|
|
9
10
|
@import "./css/prosemirror.css";
|
|
11
|
+
@import "./css/notes.css";
|
|
10
12
|
|
|
11
13
|
*{
|
|
12
14
|
box-sizing: border-box;
|
|
@@ -61,21 +63,7 @@
|
|
|
61
63
|
color: var(--colors-fg);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
padding: 0.1em !important;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.rc-menu-item {
|
|
69
|
-
color: var(--colors-fg);
|
|
70
|
-
padding: 0 1em !important;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
.rc-menu-horizontal {
|
|
75
|
-
padding: 0.2em;
|
|
76
|
-
display: flex;
|
|
77
|
-
gap: 0.4em;
|
|
78
|
-
}
|
|
66
|
+
/* rc-menu styling lives in css/rc-menu.css */
|
|
79
67
|
|
|
80
68
|
|
|
81
69
|
.container {
|