vortx-gl 1.0.32 → 1.0.34

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.
@@ -1,6 +1,7 @@
1
1
  import { GraphEngine } from '../engine/renderer';
2
2
  import { NodeInput, EdgeInput, Stylesheet, RadialMenuItem } from '../engine/types';
3
3
  import { PartialGraphConfig } from '../engine/config';
4
+ import { RunLayoutOptions } from '../composables/useGraphLayout';
4
5
  interface GraphData {
5
6
  nodes: Array<{
6
7
  data: NodeInput;
@@ -25,10 +26,7 @@ type __VLS_Props = {
25
26
  };
26
27
  declare const _default: import('vue').DefineComponent<__VLS_Props, {
27
28
  engine: import('vue').ShallowRef<GraphEngine | null, GraphEngine | null>;
28
- runLayout: (id: string, opts?: {
29
- spacing?: number;
30
- nodeIds?: (string | number)[];
31
- }) => void;
29
+ runLayout: (id: string, opts?: RunLayoutOptions) => Promise<boolean>;
32
30
  runStressTest: (count: number) => void;
33
31
  toggleFlow: () => void;
34
32
  toggleTheme: () => void;
@@ -54,6 +54,10 @@ export declare const GraphConfig: {
54
54
  readonly nodeExpandButtonFill: "#000000";
55
55
  readonly nodeExpandButtonIcon: "#ffffff";
56
56
  readonly nodeExpandButtonIconPx: 12;
57
+ readonly nodeLockChipFill: "#475569";
58
+ readonly nodeLockChipIcon: "#ffffff";
59
+ readonly nodeDiscoverButtonFill: "#dc3545";
60
+ readonly nodeDiscoverButtonIcon: "#ffffff";
57
61
  readonly nodeShape: "circle";
58
62
  readonly edgeStyle: "bezier";
59
63
  readonly labelFontSize: 11;
@@ -9,6 +9,18 @@ export declare class NodeRenderer {
9
9
  private state;
10
10
  constructor(state: SharedOverlayState);
11
11
  private expandButtonRects;
12
+ private discoverButtonRects;
13
+ /**
14
+ * Hit-test the discover buttons rendered by drawStatusChips. Returns the
15
+ * node index plus the button centre and radius in CSS px (so the host can
16
+ * anchor a menu beside it), or null.
17
+ */
18
+ pickDiscoverButton(mouseX: number, mouseY: number): {
19
+ index: number;
20
+ x: number;
21
+ y: number;
22
+ r: number;
23
+ } | null;
12
24
  /**
13
25
  * Hit-test the corner expand/collapse buttons rendered by drawExpandButtons.
14
26
  * Returns the node index under the cursor, or null. `mouseX/mouseY` are CSS
@@ -58,5 +70,28 @@ export declare class NodeRenderer {
58
70
  */
59
71
  punchOutNodes(_count: number, metadata: Map<number, NodeMetadata>, pointSize: number): void;
60
72
  private drawNodeIcon;
61
- private drawLockIcon;
73
+ /**
74
+ * Lock and discover chips, placed with the same geometry as the degree
75
+ * badge (drawBadges): fixed-size circles tangent to the node's actual
76
+ * per-node-scaled edge, so they sit just outside the node instead of being
77
+ * swallowed by it. Corners are split so nothing collides with the degree
78
+ * badge / group +/− (top-right):
79
+ * - lock → bottom-right (was a 🔒 emoji drawn inside the node, whose
80
+ * look depended on the platform's emoji font)
81
+ * - discover → top-left, clickable.
82
+ * Never on a group node: that corner is the group count, and
83
+ * a collapsed group isn't a discoverable vertex.
84
+ *
85
+ * `show` false still clears the discover hit rects, so a button hidden by
86
+ * the zoom LOD can't be clicked at its last on-screen position.
87
+ */
88
+ drawStatusChips(metadata: Map<number, NodeMetadata>, lockedNodes: Set<number>, pointSize: number, dpr: number, show: boolean): void;
89
+ /** Filled circle with the 2px white border shared by every corner chip. */
90
+ private drawChip;
91
+ /** Padlock: rounded body + shackle arc. */
92
+ private drawLockGlyph;
93
+ /** Magic wand + sparkles, a vector take on the discoverable.svg icon. */
94
+ private drawDiscoverGlyph;
95
+ /** Four-point star with concave sides, half-extent `s`. */
96
+ private fillSparkle;
62
97
  }
@@ -33,6 +33,13 @@ export declare class OverlayManager {
33
33
  pickComboBorder(mouseX: number, mouseY: number): string | null;
34
34
  /** Hit-test the corner expand/collapse button of nodeGroup nodes (delegates to NodeRenderer). */
35
35
  pickExpandButton(mouseX: number, mouseY: number): number | null;
36
+ /** Hit-test the discover button of nodeDiscoverable nodes (delegates to NodeRenderer). */
37
+ pickDiscoverButton(mouseX: number, mouseY: number): {
38
+ index: number;
39
+ x: number;
40
+ y: number;
41
+ r: number;
42
+ } | null;
36
43
  render(params: OverlayRenderParams): void;
37
44
  /**
38
45
  * Walks every node, marking culled ones with NaN in `projectedCache` and
@@ -11,3 +11,7 @@ export declare const NODE_EXPAND_BUTTON_RADIUS_PX: 12;
11
11
  export declare const NODE_EXPAND_BUTTON_FILL: "#000000";
12
12
  export declare const NODE_EXPAND_BUTTON_ICON: "#ffffff";
13
13
  export declare const NODE_EXPAND_BUTTON_ICON_PX: 12;
14
+ export declare const NODE_LOCK_CHIP_FILL: "#475569";
15
+ export declare const NODE_LOCK_CHIP_ICON: "#ffffff";
16
+ export declare const NODE_DISCOVER_BUTTON_FILL: "#dc3545";
17
+ export declare const NODE_DISCOVER_BUTTON_ICON: "#ffffff";
@@ -222,6 +222,17 @@ export declare class GraphEngine {
222
222
  * relative to the canvas (no dpr multiply — applied internally).
223
223
  */
224
224
  pickNodeGroupButton(mouseX: number, mouseY: number): number | null;
225
+ /**
226
+ * Hit-test the discover button of a `nodeDiscoverable` node. Returns the
227
+ * node's internal index and the button centre + radius (CSS px relative to
228
+ * the canvas), or null.
229
+ */
230
+ pickDiscoverButton(mouseX: number, mouseY: number): {
231
+ index: number;
232
+ x: number;
233
+ y: number;
234
+ r: number;
235
+ } | null;
225
236
  deselectAll(): void;
226
237
  selectNode(id: number | null): void;
227
238
  lockNode(id: string | number): void;
@@ -644,6 +644,14 @@ export interface GraphEventPayloadMap {
644
644
  index: number;
645
645
  expanded: boolean;
646
646
  };
647
+ /** Fired when the discover button of a `nodeDiscoverable` node is clicked. `x`/`y` are the button centre and `r` its radius, in CSS px relative to the canvas. */
648
+ "node:discover": {
649
+ id: string | number;
650
+ index: number;
651
+ x: number;
652
+ y: number;
653
+ r: number;
654
+ };
647
655
  "edge:click": {
648
656
  id: string;
649
657
  };
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export { GraphConfig, resolveConfig } from './engine/config';
8
8
  export type { GraphConfigType, PartialGraphConfig, ResolvedGraphConfig, GraphOptions, } from './engine/config';
9
9
  export { resolveNodeStyle, resolveNodeSelectStyle, resolveEdgeStyle, resolveEdgeSelectStyle, resolveEdgeClass, resolveIconKey, } from './engine/utils/styleResolver';
10
10
  export type { ResolvedNodeStyle, ResolvedNodeSelectStyle, ResolvedEdgeStyle, ResolvedEdgeSelectStyle, EdgeStyleClass, NodeElement, EdgeElement, } from './engine/utils/styleResolver';
11
+ export type { RunLayoutOptions } from './composables/useGraphLayout';
11
12
  export declare const createGraphData: (nodes: NodeInput[], edges: EdgeInput[]) => {
12
13
  nodes: NodeInput[];
13
14
  edges: EdgeInput[];
package/dist/vortx-gl.css CHANGED
@@ -874,7 +874,7 @@ input[data-v-bf144eba] {
874
874
  transition: width 0.3s ease, background-color 0.3s ease;
875
875
  }
876
876
 
877
- .vortx-gl-container[data-v-6ba1469f] {
877
+ .vortx-gl-container[data-v-db1523d8] {
878
878
  position: relative;
879
879
  width: 100%;
880
880
  height: 100%;
@@ -886,13 +886,13 @@ input[data-v-bf144eba] {
886
886
  }
887
887
 
888
888
  /* Top Right Controls */
889
- .top-right-controls-container[data-v-6ba1469f] {
889
+ .top-right-controls-container[data-v-db1523d8] {
890
890
  position: absolute;
891
891
  top: var(--vortx-space-md);
892
892
  right: var(--vortx-space-md);
893
893
  z-index: 1100;
894
894
  }
895
- .bottom-right-controls-container[data-v-6ba1469f] {
895
+ .bottom-right-controls-container[data-v-db1523d8] {
896
896
  position: absolute;
897
897
  bottom: var(--vortx-space-md);
898
898
  right: var(--vortx-space-md);
@@ -902,21 +902,21 @@ input[data-v-bf144eba] {
902
902
  gap: var(--vortx-space-sm);
903
903
  z-index: 1100;
904
904
  }
905
- .bottom-right-controls-container[data-v-6ba1469f] .top-right-controls {
905
+ .bottom-right-controls-container[data-v-db1523d8] .top-right-controls {
906
906
  position: static;
907
907
  transform: none;
908
908
  }
909
- .controls-stack[data-v-6ba1469f] {
909
+ .controls-stack[data-v-db1523d8] {
910
910
  display: flex;
911
911
  gap: var(--vortx-space-sm);
912
912
  align-items: flex-start;
913
913
  }
914
- .controls-stack[data-v-6ba1469f] .top-right-controls {
914
+ .controls-stack[data-v-db1523d8] .top-right-controls {
915
915
  position: static;
916
916
  transform: none;
917
917
  }
918
- .main-canvas[data-v-6ba1469f],
919
- .overlay-canvas[data-v-6ba1469f] {
918
+ .main-canvas[data-v-db1523d8],
919
+ .overlay-canvas[data-v-db1523d8] {
920
920
  position: absolute;
921
921
  top: 0;
922
922
  left: 0;
@@ -924,12 +924,12 @@ input[data-v-bf144eba] {
924
924
  height: 100%;
925
925
  display: block;
926
926
  }
927
- .overlay-canvas[data-v-6ba1469f] {
927
+ .overlay-canvas[data-v-db1523d8] {
928
928
  pointer-events: none;
929
929
  }
930
930
 
931
931
  /* Mobile Menu */
932
- .mobile-menu[data-v-6ba1469f] {
932
+ .mobile-menu[data-v-db1523d8] {
933
933
  position: fixed;
934
934
  bottom: var(--vortx-space-md);
935
935
  left: 50%;
@@ -941,7 +941,7 @@ input[data-v-bf144eba] {
941
941
  z-index: 1000;
942
942
  gap: 4px;
943
943
  }
944
- .menu-btn[data-v-6ba1469f] {
944
+ .menu-btn[data-v-db1523d8] {
945
945
  background: transparent;
946
946
  border: none;
947
947
  color: var(--vortx-text-dim);
@@ -955,18 +955,18 @@ input[data-v-bf144eba] {
955
955
  transition: all 0.2s;
956
956
  min-width: 70px;
957
957
  }
958
- .menu-btn span[data-v-6ba1469f] {
958
+ .menu-btn span[data-v-db1523d8] {
959
959
  font-size: 10px;
960
960
  font-weight: 600;
961
961
  text-transform: uppercase;
962
962
  letter-spacing: 0.5px;
963
963
  }
964
- .menu-btn.active[data-v-6ba1469f] {
964
+ .menu-btn.active[data-v-db1523d8] {
965
965
  background: var(--vortx-primary);
966
966
  color: white;
967
967
  box-shadow: 0 4px 12px var(--vortx-primary-glow);
968
968
  }
969
- .menu-divider[data-v-6ba1469f] {
969
+ .menu-divider[data-v-db1523d8] {
970
970
  width: 1px;
971
971
  height: 24px;
972
972
  background: var(--vortx-border);
@@ -974,14 +974,14 @@ input[data-v-bf144eba] {
974
974
  }
975
975
 
976
976
  /* Mobile Drawers */
977
- .drawer-overlay[data-v-6ba1469f] {
977
+ .drawer-overlay[data-v-db1523d8] {
978
978
  position: fixed;
979
979
  inset: 0;
980
980
  background: rgba(0, 0, 0, 0.4);
981
981
  backdrop-filter: blur(4px);
982
982
  z-index: 1300;
983
983
  }
984
- .mobile-drawer[data-v-6ba1469f] {
984
+ .mobile-drawer[data-v-db1523d8] {
985
985
  position: absolute;
986
986
  bottom: 0;
987
987
  left: 0;
@@ -991,37 +991,37 @@ input[data-v-bf144eba] {
991
991
  padding-bottom: env(safe-area-inset-bottom, var(--vortx-space-lg));
992
992
  animation: vortxSlideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1);
993
993
  }
994
- .drawer-handle[data-v-6ba1469f] {
994
+ .drawer-handle[data-v-db1523d8] {
995
995
  width: 40px;
996
996
  height: 4px;
997
997
  background: var(--vortx-border);
998
998
  border-radius: 2px;
999
999
  margin: 0 auto var(--vortx-space-md);
1000
1000
  }
1001
- .drawer-header[data-v-6ba1469f] {
1001
+ .drawer-header[data-v-db1523d8] {
1002
1002
  display: flex;
1003
1003
  justify-content: space-between;
1004
1004
  align-items: center;
1005
1005
  margin-bottom: var(--vortx-space-md);
1006
1006
  }
1007
- .drawer-header h3[data-v-6ba1469f] {
1007
+ .drawer-header h3[data-v-db1523d8] {
1008
1008
  margin: 0;
1009
1009
  font-size: 16px;
1010
1010
  font-weight: 700;
1011
1011
  }
1012
- .drawer-close[data-v-6ba1469f] {
1012
+ .drawer-close[data-v-db1523d8] {
1013
1013
  background: transparent;
1014
1014
  border: none;
1015
1015
  color: var(--vortx-text-dim);
1016
1016
  cursor: pointer;
1017
1017
  }
1018
- .drawer-content[data-v-6ba1469f] {
1018
+ .drawer-content[data-v-db1523d8] {
1019
1019
  padding: var(--vortx-space-sm) 0;
1020
1020
  }
1021
1021
 
1022
1022
  /* Fix desktop components inside drawer */
1023
- .drawer-content[data-v-6ba1469f] .layout-controls,
1024
- .drawer-content[data-v-6ba1469f] .top-right-controls {
1023
+ .drawer-content[data-v-db1523d8] .layout-controls,
1024
+ .drawer-content[data-v-db1523d8] .top-right-controls {
1025
1025
  position: static;
1026
1026
  transform: none;
1027
1027
  width: 100%;
@@ -1034,12 +1034,12 @@ input[data-v-bf144eba] {
1034
1034
  flex-wrap: wrap;
1035
1035
  justify-content: center;
1036
1036
  }
1037
- .drawer-content[data-v-6ba1469f] .divider {
1037
+ .drawer-content[data-v-db1523d8] .divider {
1038
1038
  display: none;
1039
1039
  }
1040
1040
 
1041
1041
  /* Help Trigger */
1042
- .help-trigger[data-v-6ba1469f] {
1042
+ .help-trigger[data-v-db1523d8] {
1043
1043
  position: absolute;
1044
1044
  bottom: var(--vortx-space-md);
1045
1045
  right: var(--vortx-space-md);
@@ -1059,7 +1059,7 @@ input[data-v-bf144eba] {
1059
1059
  transition: all 0.2s;
1060
1060
  color: var(--vortx-text-dim);
1061
1061
  }
1062
- .help-trigger[data-v-6ba1469f]:hover {
1062
+ .help-trigger[data-v-db1523d8]:hover {
1063
1063
  background: var(--vortx-primary);
1064
1064
  color: white;
1065
1065
  border-color: white;
@@ -1067,7 +1067,7 @@ input[data-v-bf144eba] {
1067
1067
  }
1068
1068
 
1069
1069
  /* Help Modal */
1070
- .help-modal-overlay[data-v-6ba1469f] {
1070
+ .help-modal-overlay[data-v-db1523d8] {
1071
1071
  position: fixed;
1072
1072
  inset: 0;
1073
1073
  background: rgba(0, 0, 0, 0.4);
@@ -1077,45 +1077,45 @@ input[data-v-bf144eba] {
1077
1077
  align-items: center;
1078
1078
  justify-content: center;
1079
1079
  }
1080
- .help-modal[data-v-6ba1469f] {
1080
+ .help-modal[data-v-db1523d8] {
1081
1081
  width: 340px;
1082
1082
  border-radius: var(--vortx-radius-lg);
1083
1083
  overflow: hidden;
1084
1084
  animation: vortxScaleIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
1085
1085
  }
1086
- .help-header[data-v-6ba1469f] {
1086
+ .help-header[data-v-db1523d8] {
1087
1087
  padding: var(--vortx-space-md);
1088
1088
  border-bottom: 1px solid var(--vortx-border);
1089
1089
  display: flex;
1090
1090
  justify-content: space-between;
1091
1091
  align-items: center;
1092
1092
  }
1093
- .help-header h3[data-v-6ba1469f] {
1093
+ .help-header h3[data-v-db1523d8] {
1094
1094
  margin: 0;
1095
1095
  font-size: 16px;
1096
1096
  }
1097
- .shortcut-row[data-v-6ba1469f] {
1097
+ .shortcut-row[data-v-db1523d8] {
1098
1098
  display: flex;
1099
1099
  justify-content: space-between;
1100
1100
  align-items: center;
1101
1101
  padding: 12px var(--vortx-space-md);
1102
1102
  border-bottom: 1px solid var(--vortx-border);
1103
1103
  }
1104
- .shortcut-row[data-v-6ba1469f]:last-child {
1104
+ .shortcut-row[data-v-db1523d8]:last-child {
1105
1105
  border-bottom: none;
1106
1106
  }
1107
- .key-badge[data-v-6ba1469f] {
1107
+ .key-badge[data-v-db1523d8] {
1108
1108
  background: var(--vortx-border);
1109
1109
  padding: 4px 10px;
1110
1110
  border-radius: var(--vortx-radius-sm);
1111
1111
  font-family: monospace;
1112
1112
  font-size: 12px;
1113
1113
  }
1114
- .action-desc[data-v-6ba1469f] {
1114
+ .action-desc[data-v-db1523d8] {
1115
1115
  font-size: 13px;
1116
1116
  color: var(--vortx-text-dim);
1117
1117
  }
1118
- .close-btn[data-v-6ba1469f] {
1118
+ .close-btn[data-v-db1523d8] {
1119
1119
  background: transparent;
1120
1120
  border: none;
1121
1121
  color: var(--vortx-text-dim);
@@ -1123,13 +1123,13 @@ input[data-v-bf144eba] {
1123
1123
  cursor: pointer;
1124
1124
  }
1125
1125
  @media (max-width: 768px) {
1126
- .help-trigger[data-v-6ba1469f] {
1126
+ .help-trigger[data-v-db1523d8] {
1127
1127
  display: none;
1128
1128
  }
1129
1129
  }
1130
1130
 
1131
1131
  /* Connecting Toast */
1132
- .connecting-toast[data-v-6ba1469f] {
1132
+ .connecting-toast[data-v-db1523d8] {
1133
1133
  position: fixed;
1134
1134
  top: var(--vortx-space-lg);
1135
1135
  left: 50%;
@@ -1140,20 +1140,20 @@ input[data-v-bf144eba] {
1140
1140
  display: flex;
1141
1141
  align-items: center;
1142
1142
  gap: 16px;
1143
- animation: vortxSlideDown-6ba1469f 0.3s cubic-bezier(0.16, 1, 0.3, 1);
1143
+ animation: vortxSlideDown-db1523d8 0.3s cubic-bezier(0.16, 1, 0.3, 1);
1144
1144
  }
1145
- .toast-content[data-v-6ba1469f] {
1145
+ .toast-content[data-v-db1523d8] {
1146
1146
  display: flex;
1147
1147
  align-items: center;
1148
1148
  gap: 16px;
1149
1149
  flex: 1;
1150
1150
  }
1151
- .edge-config-group[data-v-6ba1469f] {
1151
+ .edge-config-group[data-v-db1523d8] {
1152
1152
  display: flex;
1153
1153
  align-items: center;
1154
1154
  gap: 12px;
1155
1155
  }
1156
- .vortx-input-sm[data-v-6ba1469f] {
1156
+ .vortx-input-sm[data-v-db1523d8] {
1157
1157
  background: rgba(255, 255, 255, 0.05);
1158
1158
  border: 1px solid var(--vortx-border);
1159
1159
  border-radius: var(--vortx-radius-sm);
@@ -1163,24 +1163,24 @@ input[data-v-bf144eba] {
1163
1163
  width: 140px;
1164
1164
  height: 32px;
1165
1165
  }
1166
- .vortx-input-sm.narrow[data-v-6ba1469f] {
1166
+ .vortx-input-sm.narrow[data-v-db1523d8] {
1167
1167
  width: 60px;
1168
1168
  }
1169
- .color-presets[data-v-6ba1469f] {
1169
+ .color-presets[data-v-db1523d8] {
1170
1170
  display: flex;
1171
1171
  gap: 6px;
1172
1172
  }
1173
- .color-dot[data-v-6ba1469f] {
1173
+ .color-dot[data-v-db1523d8] {
1174
1174
  width: 18px;
1175
1175
  height: 18px;
1176
1176
  border-radius: 50%;
1177
1177
  cursor: pointer;
1178
1178
  transition: transform 0.2s;
1179
1179
  }
1180
- .color-dot[data-v-6ba1469f]:hover {
1180
+ .color-dot[data-v-db1523d8]:hover {
1181
1181
  transform: scale(1.2);
1182
1182
  }
1183
- @keyframes vortxPulse-6ba1469f {
1183
+ @keyframes vortxPulse-db1523d8 {
1184
1184
  0% {
1185
1185
  transform: scale(1);
1186
1186
  opacity: 1;
@@ -1194,7 +1194,7 @@ input[data-v-bf144eba] {
1194
1194
  opacity: 1;
1195
1195
  }
1196
1196
  }
1197
- @keyframes vortxSlideDown-6ba1469f {
1197
+ @keyframes vortxSlideDown-db1523d8 {
1198
1198
  from {
1199
1199
  transform: translate(-50%, -20px);
1200
1200
  opacity: 0;