@xenolithengine/graph-render-pixi 0.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -0
  3. package/dist/bezier.d.ts +30 -0
  4. package/dist/bezier.d.ts.map +1 -0
  5. package/dist/bezier.js +70 -0
  6. package/dist/bezier.js.map +1 -0
  7. package/dist/comment-renderer.d.ts +35 -0
  8. package/dist/comment-renderer.d.ts.map +1 -0
  9. package/dist/comment-renderer.js +194 -0
  10. package/dist/comment-renderer.js.map +1 -0
  11. package/dist/edge-paths.d.ts +24 -0
  12. package/dist/edge-paths.d.ts.map +1 -0
  13. package/dist/edge-paths.js +123 -0
  14. package/dist/edge-paths.js.map +1 -0
  15. package/dist/edge-renderer.d.ts +29 -0
  16. package/dist/edge-renderer.d.ts.map +1 -0
  17. package/dist/edge-renderer.js +99 -0
  18. package/dist/edge-renderer.js.map +1 -0
  19. package/dist/geom.d.ts +46 -0
  20. package/dist/geom.d.ts.map +1 -0
  21. package/dist/geom.js +54 -0
  22. package/dist/geom.js.map +1 -0
  23. package/dist/grid.d.ts +12 -0
  24. package/dist/grid.d.ts.map +1 -0
  25. package/dist/grid.js +35 -0
  26. package/dist/grid.js.map +1 -0
  27. package/dist/icons.d.ts +14 -0
  28. package/dist/icons.d.ts.map +1 -0
  29. package/dist/icons.js +32 -0
  30. package/dist/icons.js.map +1 -0
  31. package/dist/index.d.ts +34 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +20 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/interaction.d.ts +69 -0
  36. package/dist/interaction.d.ts.map +1 -0
  37. package/dist/interaction.js +229 -0
  38. package/dist/interaction.js.map +1 -0
  39. package/dist/layout.d.ts +126 -0
  40. package/dist/layout.d.ts.map +1 -0
  41. package/dist/layout.js +360 -0
  42. package/dist/layout.js.map +1 -0
  43. package/dist/macro-frame.d.ts +29 -0
  44. package/dist/macro-frame.d.ts.map +1 -0
  45. package/dist/macro-frame.js +116 -0
  46. package/dist/macro-frame.js.map +1 -0
  47. package/dist/node-renderer.d.ts +102 -0
  48. package/dist/node-renderer.d.ts.map +1 -0
  49. package/dist/node-renderer.js +776 -0
  50. package/dist/node-renderer.js.map +1 -0
  51. package/dist/reroute-renderer.d.ts +25 -0
  52. package/dist/reroute-renderer.d.ts.map +1 -0
  53. package/dist/reroute-renderer.js +163 -0
  54. package/dist/reroute-renderer.js.map +1 -0
  55. package/dist/style.d.ts +56 -0
  56. package/dist/style.d.ts.map +1 -0
  57. package/dist/style.js +102 -0
  58. package/dist/style.js.map +1 -0
  59. package/dist/text-measure.d.ts +6 -0
  60. package/dist/text-measure.d.ts.map +1 -0
  61. package/dist/text-measure.js +21 -0
  62. package/dist/text-measure.js.map +1 -0
  63. package/dist/theme.d.ts +86 -0
  64. package/dist/theme.d.ts.map +1 -0
  65. package/dist/theme.js +2 -0
  66. package/dist/theme.js.map +1 -0
  67. package/dist/viewport-math.d.ts +68 -0
  68. package/dist/viewport-math.d.ts.map +1 -0
  69. package/dist/viewport-math.js +106 -0
  70. package/dist/viewport-math.js.map +1 -0
  71. package/dist/viewport.d.ts +28 -0
  72. package/dist/viewport.d.ts.map +1 -0
  73. package/dist/viewport.js +47 -0
  74. package/dist/viewport.js.map +1 -0
  75. package/dist/virtualize.d.ts +55 -0
  76. package/dist/virtualize.d.ts.map +1 -0
  77. package/dist/virtualize.js +96 -0
  78. package/dist/virtualize.js.map +1 -0
  79. package/dist/widget-renderer.d.ts +150 -0
  80. package/dist/widget-renderer.d.ts.map +1 -0
  81. package/dist/widget-renderer.js +399 -0
  82. package/dist/widget-renderer.js.map +1 -0
  83. package/dist/xen-theme.d.ts +8 -0
  84. package/dist/xen-theme.d.ts.map +1 -0
  85. package/dist/xen-theme.js +23 -0
  86. package/dist/xen-theme.js.map +1 -0
  87. package/package.json +63 -0
@@ -0,0 +1,229 @@
1
+ import { EventEmitter } from '@xenolithengine/graph-core';
2
+ /**
3
+ * Convert a `WheelEvent.deltaY` to a multiplicative zoom factor. Positive delta (scroll down)
4
+ * zooms out (factor < 1), negative zooms in (factor > 1). Uses an exponential curve so the same
5
+ * notch always changes zoom by the same proportion, regardless of current zoom level.
6
+ *
7
+ * One default OS scroll click produces deltaY ≈ ±100; we map that to ~0.82× / 1.22× zoom step.
8
+ */
9
+ export function wheelDeltaToZoomFactor(deltaY) {
10
+ return Math.exp(-deltaY / 500);
11
+ }
12
+ /**
13
+ * Native trackpad pinch on macOS arrives as a wheel event with `ctrlKey` set and small deltaY
14
+ * (typically ±1–10). We want a gentler curve here than scroll wheel — pinch should feel buttery,
15
+ * not catapulty. Same exponential shape, larger divisor.
16
+ */
17
+ export function pinchDeltaToZoomFactor(deltaY) {
18
+ return Math.exp(-deltaY / 100);
19
+ }
20
+ export class InteractionManager {
21
+ #target;
22
+ #events = new EventEmitter();
23
+ #panButtons;
24
+ #panActiveButton = null;
25
+ #lastPanX = 0;
26
+ #lastPanY = 0;
27
+ #touches = new Map();
28
+ #gestureActive = false;
29
+ #lastGestureDist = 0;
30
+ #lastGestureMid = { x: 0, y: 0 };
31
+ #longPressMs;
32
+ #longPressSlop;
33
+ #longPressTimer = null;
34
+ #longPressStart = null;
35
+ constructor(target, opts = {}) {
36
+ this.#target = target;
37
+ this.#panButtons = new Set(opts.panButtons ?? [1, 2]);
38
+ this.#longPressMs = opts.longPressMs ?? 500;
39
+ this.#longPressSlop = opts.longPressSlop ?? 8;
40
+ }
41
+ attach() {
42
+ this.#target.style.touchAction = 'none';
43
+ // Suppress iOS text-selection / "image options" callout on long-press over the canvas — the
44
+ // editor opens its OWN context menu via onLongPress, the browser must stay out of the way.
45
+ this.#target.style.userSelect = 'none';
46
+ const ts = this.#target.style;
47
+ ts.webkitUserSelect = 'none';
48
+ ts.webkitTouchCallout = 'none';
49
+ this.#target.addEventListener('wheel', this.#onWheel, { passive: false });
50
+ this.#target.addEventListener('pointerdown', this.#onPointerDown);
51
+ this.#target.addEventListener('pointermove', this.#onPointerMove);
52
+ this.#target.addEventListener('pointerup', this.#onPointerUp);
53
+ this.#target.addEventListener('pointercancel', this.#onPointerUp);
54
+ this.#target.addEventListener('contextmenu', this.#onContextMenu);
55
+ }
56
+ detach() {
57
+ this.#target.removeEventListener('wheel', this.#onWheel);
58
+ this.#target.removeEventListener('pointerdown', this.#onPointerDown);
59
+ this.#target.removeEventListener('pointermove', this.#onPointerMove);
60
+ this.#target.removeEventListener('pointerup', this.#onPointerUp);
61
+ this.#target.removeEventListener('pointercancel', this.#onPointerUp);
62
+ this.#target.removeEventListener('contextmenu', this.#onContextMenu);
63
+ }
64
+ onZoom(handler) {
65
+ return this.#events.on('intent:zoom', handler);
66
+ }
67
+ onPan(handler) {
68
+ return this.#events.on('intent:pan', handler);
69
+ }
70
+ /**
71
+ * Fires the moment a second touch arrives. The editor uses this to cancel any in-flight
72
+ * single-pointer drag (node move, edge drag, marquee) so the gesture takes over cleanly
73
+ * instead of half a node being dragged while we also pan + zoom.
74
+ */
75
+ onGestureBegin(handler) {
76
+ return this.#events.on('intent:gesture-begin', handler);
77
+ }
78
+ /** Fires when the active touch count drops back below 2. */
79
+ onGestureEnd(handler) {
80
+ return this.#events.on('intent:gesture-end', handler);
81
+ }
82
+ /** Fires after a stationary single touch holds for `longPressMs` — mobile equivalent of right-click. */
83
+ onLongPress(handler) {
84
+ return this.#events.on('intent:long-press', handler);
85
+ }
86
+ /** Fires the moment a single touch lands, with the local point and the duration the user must
87
+ * hold for the long-press to fire. Editors paint a growing ring at the point so the user gets
88
+ * feedback during the hold. Paired with onLongPressCancel; followed by onLongPress on success. */
89
+ onLongPressStart(handler) {
90
+ return this.#events.on('intent:long-press-start', handler);
91
+ }
92
+ /** Fires when the in-progress long-press is aborted (move past slop, lift early, second touch). */
93
+ onLongPressCancel(handler) {
94
+ return this.#events.on('intent:long-press-cancel', handler);
95
+ }
96
+ #localPoint(clientX, clientY) {
97
+ const rect = this.#target.getBoundingClientRect();
98
+ return { x: clientX - rect.left, y: clientY - rect.top };
99
+ }
100
+ #onWheel = (e) => {
101
+ e.preventDefault();
102
+ const focal = this.#localPoint(e.clientX, e.clientY);
103
+ const factor = e.ctrlKey ? pinchDeltaToZoomFactor(e.deltaY) : wheelDeltaToZoomFactor(e.deltaY);
104
+ this.#events.emit('intent:zoom', { focal, factor });
105
+ };
106
+ #onPointerDown = (e) => {
107
+ if (e.pointerType === 'touch') {
108
+ this.#touches.set(e.pointerId, { x: e.clientX, y: e.clientY });
109
+ this.#target.setPointerCapture(e.pointerId);
110
+ if (this.#touches.size === 1)
111
+ this.#armLongPress(e.pointerId, e.clientX, e.clientY);
112
+ if (this.#touches.size === 2 && !this.#gestureActive) {
113
+ this.#cancelLongPress();
114
+ this.#beginGesture();
115
+ }
116
+ return;
117
+ }
118
+ if (!this.#panButtons.has(e.button))
119
+ return;
120
+ this.#panActiveButton = e.button;
121
+ this.#lastPanX = e.clientX;
122
+ this.#lastPanY = e.clientY;
123
+ this.#target.setPointerCapture(e.pointerId);
124
+ e.preventDefault();
125
+ };
126
+ #onPointerMove = (e) => {
127
+ if (e.pointerType === 'touch') {
128
+ if (!this.#touches.has(e.pointerId))
129
+ return;
130
+ this.#touches.set(e.pointerId, { x: e.clientX, y: e.clientY });
131
+ if (this.#longPressStart && e.pointerId === this.#longPressStart.id) {
132
+ const dx = e.clientX - this.#longPressStart.x;
133
+ const dy = e.clientY - this.#longPressStart.y;
134
+ if (Math.hypot(dx, dy) > this.#longPressSlop)
135
+ this.#cancelLongPress();
136
+ }
137
+ if (this.#gestureActive && this.#touches.size >= 2)
138
+ this.#updateGesture();
139
+ return;
140
+ }
141
+ if (this.#panActiveButton === null)
142
+ return;
143
+ const dx = e.clientX - this.#lastPanX;
144
+ const dy = e.clientY - this.#lastPanY;
145
+ this.#lastPanX = e.clientX;
146
+ this.#lastPanY = e.clientY;
147
+ if (dx !== 0 || dy !== 0) {
148
+ this.#events.emit('intent:pan', { dx, dy });
149
+ }
150
+ };
151
+ #onPointerUp = (e) => {
152
+ if (e.pointerType === 'touch') {
153
+ if (this.#longPressStart && e.pointerId === this.#longPressStart.id)
154
+ this.#cancelLongPress();
155
+ if (this.#touches.delete(e.pointerId) && this.#gestureActive && this.#touches.size < 2) {
156
+ this.#endGesture();
157
+ }
158
+ if (this.#target.hasPointerCapture(e.pointerId)) {
159
+ this.#target.releasePointerCapture(e.pointerId);
160
+ }
161
+ return;
162
+ }
163
+ if (this.#panActiveButton === null)
164
+ return;
165
+ if (this.#target.hasPointerCapture(e.pointerId)) {
166
+ this.#target.releasePointerCapture(e.pointerId);
167
+ }
168
+ this.#panActiveButton = null;
169
+ };
170
+ #onContextMenu = (e) => {
171
+ // Right-click is a pan gesture for us — suppress the browser context menu.
172
+ e.preventDefault();
173
+ };
174
+ #beginGesture() {
175
+ const [a, b] = this.#twoTouches();
176
+ this.#lastGestureDist = Math.hypot(b.x - a.x, b.y - a.y);
177
+ this.#lastGestureMid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
178
+ this.#gestureActive = true;
179
+ this.#events.emit('intent:gesture-begin', {});
180
+ }
181
+ #updateGesture() {
182
+ const [a, b] = this.#twoTouches();
183
+ const dist = Math.hypot(b.x - a.x, b.y - a.y);
184
+ const midClient = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
185
+ const dx = midClient.x - this.#lastGestureMid.x;
186
+ const dy = midClient.y - this.#lastGestureMid.y;
187
+ if (dx !== 0 || dy !== 0)
188
+ this.#events.emit('intent:pan', { dx, dy });
189
+ if (dist > 0 && this.#lastGestureDist > 0 && dist !== this.#lastGestureDist) {
190
+ const factor = dist / this.#lastGestureDist;
191
+ const focal = this.#localPoint(midClient.x, midClient.y);
192
+ this.#events.emit('intent:zoom', { focal, factor });
193
+ }
194
+ this.#lastGestureMid = midClient;
195
+ this.#lastGestureDist = dist;
196
+ }
197
+ #endGesture() {
198
+ this.#gestureActive = false;
199
+ this.#events.emit('intent:gesture-end', {});
200
+ }
201
+ #armLongPress(id, clientX, clientY) {
202
+ this.#cancelLongPress();
203
+ this.#longPressStart = { id, x: clientX, y: clientY };
204
+ const local = this.#localPoint(clientX, clientY);
205
+ this.#events.emit('intent:long-press-start', { x: local.x, y: local.y, ms: this.#longPressMs });
206
+ this.#longPressTimer = setTimeout(() => {
207
+ this.#longPressTimer = null;
208
+ this.#longPressStart = null;
209
+ this.#events.emit('intent:long-press', this.#localPoint(clientX, clientY));
210
+ }, this.#longPressMs);
211
+ }
212
+ #cancelLongPress() {
213
+ const wasArmed = this.#longPressStart !== null || this.#longPressTimer !== null;
214
+ if (this.#longPressTimer !== null) {
215
+ clearTimeout(this.#longPressTimer);
216
+ this.#longPressTimer = null;
217
+ }
218
+ this.#longPressStart = null;
219
+ if (wasArmed)
220
+ this.#events.emit('intent:long-press-cancel', {});
221
+ }
222
+ #twoTouches() {
223
+ const it = this.#touches.values();
224
+ const a = it.next().value;
225
+ const b = it.next().value;
226
+ return [a, b];
227
+ }
228
+ }
229
+ //# sourceMappingURL=interaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../src/interaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ import type { Node, Pin, PinId, WidgetSpec } from '@xenolithengine/graph-core';
2
+ export interface WidgetGeometry {
3
+ rowHeight: number;
4
+ gap: number;
5
+ /** Min width reserved for a widget's control (slider track, value field) beside its label. */
6
+ controlMinWidth: number;
7
+ }
8
+ /** A widget is "free-floating" (rides in the body band, not a pin row) in two cases:
9
+ * 1. `custom` widget whose declared bind key doesn't resolve to any pin — these are node-level
10
+ * editors (schema editor, color palette, multi-field panel) that legitimately don't belong
11
+ * to one specific pin.
12
+ * 2. Any widget with explicit `freeFloating: true` — n8n-style config fields (HTTP body, auth
13
+ * token, etc.) that aren't connectable from outside but still need rendering. Bypasses the
14
+ * usual "non-custom widget needs a pin to render" rule.
15
+ * Standard non-custom widgets without a pin or the explicit flag are still silently dropped. */
16
+ export declare function isFreeFloating(node: Node, w: WidgetSpec): boolean;
17
+ /** Vertical footprint a free-floating widget takes in the body band — covers `text` widgets that
18
+ * need an extra row for their label above the field, and multiline text fields that want 3 rows
19
+ * for the editor box. Custom widgets honour their declared height. Everyone else fits one row. */
20
+ export declare function freeFloatingHeight(w: WidgetSpec, rowHeight: number): number;
21
+ export interface Rect {
22
+ x: number;
23
+ y: number;
24
+ width: number;
25
+ height: number;
26
+ }
27
+ export interface PinLayout {
28
+ id: PinId;
29
+ x: number;
30
+ y: number;
31
+ side: 'left' | 'right';
32
+ }
33
+ export interface NodeLayout {
34
+ body: Rect;
35
+ header: Rect;
36
+ pins: PinLayout[];
37
+ }
38
+ export interface LayoutTokens {
39
+ node: {
40
+ minWidth: number;
41
+ headerHeight: number;
42
+ headerPadding: number;
43
+ innerPaddingX: number;
44
+ innerPaddingY: number;
45
+ };
46
+ pin: {
47
+ diameter: number;
48
+ rowSpacing: number;
49
+ rowHeight: number;
50
+ };
51
+ header: {
52
+ toPinsGap: number;
53
+ };
54
+ widget?: WidgetGeometry;
55
+ }
56
+ /** Partition pins into the UE-Blueprint sections: exec pins occupy a row band at the TOP (exec-in
57
+ * left, exec-out right), data pins fill rows below — regardless of declaration order. */
58
+ export declare function sectionPins(pins: ReadonlyArray<Pin>): {
59
+ execIn: Pin[];
60
+ execOut: Pin[];
61
+ dataIn: Pin[];
62
+ dataOut: Pin[];
63
+ };
64
+ /** Body pin rows: the exec band (only NON-hoisted exec pins) plus the data band. Hoisted exec pins
65
+ * ride the header line and don't take a body row. */
66
+ export declare function pinRowCount(pins: ReadonlyArray<Pin>): number;
67
+ /** Effective height of each pin row — HYBRID rhythm:
68
+ * - All rows share a UNIFORM base = max(pin.rowHeight, widget.rowHeight if any standard bound
69
+ * widget is visible). Keeps the vertical rhythm consistent across the pin band so labels and
70
+ * standard controls align row-by-row.
71
+ * - A row whose visible bound widget is a CUSTOM widget with its own declared height (curve, XY
72
+ * pad, image preview…) grows ONLY that row to fit. Other rows stay at the base — so a single
73
+ * tall preview doesn't balloon the whole node into mostly-empty space.
74
+ * Drives `naturalHeight`, `computeNodeLayout`, and `computeWidgetRects`. */
75
+ export declare function pinRowHeights(node: Node, pinRowHeight: number, widgetRowHeight: number, isPinConnected?: (pinKey: string) => boolean): number[];
76
+ /** Sum of all pin row heights + the spacings between them. */
77
+ export declare function pinBandHeight(rowHeights: ReadonlyArray<number>, rowSpacing: number): number;
78
+ /** Y of a pin row's centre relative to the node's TOP edge (i.e. local-space y). */
79
+ export declare function pinRowCenterY(rowHeights: ReadonlyArray<number>, rowIdx: number, rowSpacing: number, headerHeight: number, headerToPinsGap: number): number;
80
+ /** Per-node uniform effective row height — backward-compat shim. Equals the max of per-row
81
+ * heights. New code should call `pinRowHeights` for accuracy. */
82
+ export declare function effectivePinRowHeight(node: Node, pinRowHeight: number, widgetRowHeight: number, isPinConnected?: (pinKey: string) => boolean): number;
83
+ /** Find the pin on a node whose label (or id) matches `pinKey`. Used to resolve a widget's
84
+ * declared binding to a concrete pin. */
85
+ export declare function findPinByKey(node: Node, pinKey: string): Pin | undefined;
86
+ /** Find a pin's row index inside the body band (header-relative). Used to position a pin-bound
87
+ * widget inside the row that contains its pin. Returns undefined when the pin is hoisted onto
88
+ * the header line (no body row to place the widget in). */
89
+ export declare function pinRowIndexFor(node: Node, pinKey: string): number | undefined;
90
+ /** Measures a single line of text in CSS pixels. The editor binds this to PIXI's
91
+ * `CanvasTextMetrics`; unit tests inject a deterministic fake. */
92
+ export type TextMeasurer = (text: string, fontSize: number, fontWeight: number) => number;
93
+ export interface NodeSizeTokens {
94
+ node: {
95
+ minWidth: number;
96
+ headerHeight: number;
97
+ headerPadding: number;
98
+ };
99
+ pin: {
100
+ diameter: number;
101
+ rowSpacing: number;
102
+ rowHeight: number;
103
+ labelGap: number;
104
+ };
105
+ header: {
106
+ toPinsGap: number;
107
+ chevronSize: number;
108
+ titleGap: number;
109
+ };
110
+ typography: {
111
+ titleSize: number;
112
+ titleWeight: number;
113
+ labelSize: number;
114
+ labelWeight: number;
115
+ };
116
+ widget?: WidgetGeometry;
117
+ }
118
+ /** Resolved render size for a node lacking an explicit `size`. Single source of truth: the editor
119
+ * backfills `node.size` with this so renderer, geom bounds, edge endpoints and the backdrop all
120
+ * agree on dimensions. */
121
+ export declare function measureNodeSize(node: Node, title: string, tokens: NodeSizeTokens, measure: TextMeasurer, isPinConnected?: (pinKey: string) => boolean): {
122
+ x: number;
123
+ y: number;
124
+ };
125
+ export declare function computeNodeLayout(node: Node, tokens: LayoutTokens, isPinConnected?: (k: string) => boolean): NodeLayout;
126
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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"}