@syntrologie/adapt-nav 2.13.0 → 2.15.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 (104) hide show
  1. package/dist/NavWidgetLit.d.ts +56 -0
  2. package/dist/NavWidgetLit.d.ts.map +1 -0
  3. package/dist/NavWidgetLit.js +495 -0
  4. package/dist/NavWidgetLit.test.d.ts +8 -0
  5. package/dist/NavWidgetLit.test.d.ts.map +1 -0
  6. package/dist/NavWidgetLit.test.js +199 -0
  7. package/dist/editor-lit.d.ts +49 -0
  8. package/dist/editor-lit.d.ts.map +1 -0
  9. package/dist/editor-lit.js +319 -0
  10. package/dist/editor.d.ts.map +1 -1
  11. package/dist/editor.js +3 -3
  12. package/dist/runtime-lit.d.ts +108 -0
  13. package/dist/runtime-lit.d.ts.map +1 -0
  14. package/dist/runtime-lit.js +241 -0
  15. package/dist/runtime.d.ts +15 -3
  16. package/dist/runtime.d.ts.map +1 -1
  17. package/dist/runtime.js +29 -0
  18. package/dist/schema.d.ts +216 -216
  19. package/dist/schema.d.ts.map +1 -1
  20. package/node_modules/@syntro/design-system/dist/tokens/index.d.ts +2 -0
  21. package/node_modules/@syntro/design-system/dist/tokens/index.d.ts.map +1 -1
  22. package/node_modules/@syntro/design-system/dist/tokens/index.js +2 -0
  23. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.d.ts +93 -0
  24. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.d.ts.map +1 -0
  25. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.js +72 -0
  26. package/node_modules/@syntrologie/sdk-contracts/dist/index.d.ts +1 -1
  27. package/node_modules/@syntrologie/sdk-contracts/dist/index.js +5 -3
  28. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.d.ts +150 -79
  29. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.js +266 -67
  30. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.d.ts.map +1 -1
  31. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +6 -3
  32. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.d.ts +84 -0
  33. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.d.ts.map +1 -0
  34. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.js +323 -0
  35. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.d.ts +25 -0
  36. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.d.ts.map +1 -0
  37. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.js +55 -0
  38. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.d.ts +33 -0
  39. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.d.ts.map +1 -0
  40. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.js +118 -0
  41. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.d.ts +32 -0
  42. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.d.ts.map +1 -0
  43. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.js +68 -0
  44. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.d.ts +34 -0
  45. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.d.ts.map +1 -0
  46. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.js +57 -0
  47. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.d.ts +13 -0
  48. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.d.ts.map +1 -0
  49. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.js +31 -0
  50. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.d.ts +7 -0
  51. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.d.ts.map +1 -0
  52. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.js +15 -0
  53. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.d.ts +36 -0
  54. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.d.ts.map +1 -0
  55. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.js +102 -0
  56. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.d.ts +20 -0
  57. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.d.ts.map +1 -0
  58. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.js +48 -0
  59. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.d.ts +16 -0
  60. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.d.ts.map +1 -0
  61. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.js +25 -0
  62. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.d.ts +66 -0
  63. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.d.ts.map +1 -0
  64. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.js +87 -0
  65. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.d.ts +7 -0
  66. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.d.ts.map +1 -0
  67. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.js +15 -0
  68. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +1 -1
  69. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +28 -17
  70. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.d.ts +66 -0
  71. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.d.ts.map +1 -0
  72. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.js +528 -0
  73. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.d.ts +41 -0
  74. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.d.ts.map +1 -0
  75. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.js +63 -0
  76. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.d.ts +55 -0
  77. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.d.ts.map +1 -0
  78. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.js +92 -0
  79. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.d.ts +90 -0
  80. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.d.ts.map +1 -0
  81. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.js +242 -0
  82. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.d.ts +12 -0
  83. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.d.ts.map +1 -0
  84. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.js +21 -0
  85. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.d.ts +21 -0
  86. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.d.ts.map +1 -0
  87. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.js +33 -0
  88. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.d.ts +28 -0
  89. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.d.ts.map +1 -0
  90. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.js +121 -0
  91. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.d.ts +110 -0
  92. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.d.ts.map +1 -0
  93. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.js +476 -0
  94. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +2 -0
  95. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +1 -1
  96. package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +1 -0
  97. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.d.ts +15 -0
  98. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.d.ts.map +1 -0
  99. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.js +14 -0
  100. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts +0 -4
  101. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts.map +1 -1
  102. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.js +17 -1
  103. package/node_modules/@syntrologie/shared-editor-ui/package.json +9 -1
  104. package/package.json +12 -1
@@ -0,0 +1,476 @@
1
+ /**
2
+ * PanelShellController — Lit ReactiveController for draggable/resizable panels.
3
+ *
4
+ * Owns geometry state (position, size, dock), pointer-event handlers for the
5
+ * drag FAB and 8 resize handles, localStorage persistence, and viewport
6
+ * clamping. A consuming LitElement calls `attachFab(el)` / `attachHandle(el, dir)`
7
+ * on its rendered DOM to hook up pointer events, and reads `panelStyles` /
8
+ * `fabStyles` to position the panel + FAB.
9
+ *
10
+ * Why a controller, not a wrapper element: `<slot>`-based wrapper elements
11
+ * don't compose well in light DOM (Lit wipes children on render), and shadow
12
+ * DOM breaks Playwright child selectors used by E2E tests. A ReactiveController
13
+ * is the Lit-idiomatic way to share stateful logic across elements.
14
+ *
15
+ * Emits one callback: `onToggle` when the FAB is pressed without dragging.
16
+ */
17
+ import { panelShell } from '@syntro/design-system';
18
+ // =============================================================================
19
+ // Constants
20
+ // =============================================================================
21
+ const DEFAULTS = {
22
+ minWidth: panelShell.behavior.minWidth,
23
+ minHeight: panelShell.behavior.minHeight,
24
+ dragThreshold: panelShell.behavior.dragThreshold,
25
+ snapThreshold: panelShell.behavior.snapThreshold,
26
+ fabSize: panelShell.fab.size,
27
+ fabInset: panelShell.fab.inset,
28
+ storageKey: 'syntro:editor-panel',
29
+ };
30
+ const HANDLE_SIZE = panelShell.behavior.handleSize;
31
+ // =============================================================================
32
+ // Helpers
33
+ // =============================================================================
34
+ export function makeResizeHandles() {
35
+ return [
36
+ {
37
+ dir: 'n',
38
+ style: {
39
+ top: '0',
40
+ left: `${HANDLE_SIZE}px`,
41
+ right: `${HANDLE_SIZE}px`,
42
+ height: `${HANDLE_SIZE}px`,
43
+ },
44
+ cursor: 'ns-resize',
45
+ },
46
+ {
47
+ dir: 's',
48
+ style: {
49
+ bottom: '0',
50
+ left: `${HANDLE_SIZE}px`,
51
+ right: `${HANDLE_SIZE}px`,
52
+ height: `${HANDLE_SIZE}px`,
53
+ },
54
+ cursor: 'ns-resize',
55
+ },
56
+ {
57
+ dir: 'e',
58
+ style: {
59
+ right: '0',
60
+ top: `${HANDLE_SIZE}px`,
61
+ bottom: `${HANDLE_SIZE}px`,
62
+ width: `${HANDLE_SIZE}px`,
63
+ },
64
+ cursor: 'ew-resize',
65
+ },
66
+ {
67
+ dir: 'w',
68
+ style: {
69
+ left: '0',
70
+ top: `${HANDLE_SIZE}px`,
71
+ bottom: `${HANDLE_SIZE}px`,
72
+ width: `${HANDLE_SIZE}px`,
73
+ },
74
+ cursor: 'ew-resize',
75
+ },
76
+ {
77
+ dir: 'ne',
78
+ style: {
79
+ top: '0',
80
+ right: '0',
81
+ width: `${HANDLE_SIZE * 2}px`,
82
+ height: `${HANDLE_SIZE * 2}px`,
83
+ },
84
+ cursor: 'nesw-resize',
85
+ },
86
+ {
87
+ dir: 'nw',
88
+ style: {
89
+ top: '0',
90
+ left: '0',
91
+ width: `${HANDLE_SIZE * 2}px`,
92
+ height: `${HANDLE_SIZE * 2}px`,
93
+ },
94
+ cursor: 'nwse-resize',
95
+ },
96
+ {
97
+ dir: 'se',
98
+ style: {
99
+ bottom: '0',
100
+ right: '0',
101
+ width: `${HANDLE_SIZE * 2}px`,
102
+ height: `${HANDLE_SIZE * 2}px`,
103
+ },
104
+ cursor: 'nwse-resize',
105
+ },
106
+ {
107
+ dir: 'sw',
108
+ style: {
109
+ bottom: '0',
110
+ left: '0',
111
+ width: `${HANDLE_SIZE * 2}px`,
112
+ height: `${HANDLE_SIZE * 2}px`,
113
+ },
114
+ cursor: 'nesw-resize',
115
+ },
116
+ ];
117
+ }
118
+ // =============================================================================
119
+ // Controller
120
+ // =============================================================================
121
+ export class PanelShellController {
122
+ constructor(host, options = {}) {
123
+ this._panelEl = null;
124
+ this._fabEl = null;
125
+ // Drag state
126
+ this._isDragging = false;
127
+ this._hasMoved = false;
128
+ this._dragOffset = { x: 0, y: 0 };
129
+ this._startPanelPos = { x: 0, y: 0 };
130
+ this._pendingGeo = null;
131
+ // Resize state
132
+ this._activeResize = null;
133
+ this._resizeStartMouse = { x: 0, y: 0 };
134
+ // ---- FAB pointer handlers ----
135
+ this.handleFabPointerDown = (e) => {
136
+ this._isDragging = true;
137
+ this._hasMoved = false;
138
+ const rect = this.rect;
139
+ this._startPanelPos = { x: rect.left, y: rect.top };
140
+ this._dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
141
+ try {
142
+ e.target.setPointerCapture(e.pointerId);
143
+ }
144
+ catch {
145
+ // best-effort
146
+ }
147
+ e.preventDefault();
148
+ };
149
+ this.handleFabPointerMove = (e) => {
150
+ if (!this._isDragging)
151
+ return;
152
+ const newX = e.clientX - this._dragOffset.x;
153
+ const newY = e.clientY - this._dragOffset.y;
154
+ if (!this._hasMoved) {
155
+ const dx = Math.abs(newX - this._startPanelPos.x);
156
+ const dy = Math.abs(newY - this._startPanelPos.y);
157
+ if (dx < this.opts.dragThreshold && dy < this.opts.dragThreshold)
158
+ return;
159
+ this._hasMoved = true;
160
+ }
161
+ const geo = this._geometry;
162
+ const height = geo.docked ? window.innerHeight : geo.height;
163
+ this._writeStylesDuringGesture({ x: newX, y: newY, width: geo.width, height });
164
+ this._pendingGeo = { x: newX, y: newY, width: geo.width, height, docked: null };
165
+ };
166
+ this.handleFabPointerUp = (e) => {
167
+ try {
168
+ e.target.releasePointerCapture(e.pointerId);
169
+ }
170
+ catch {
171
+ // best-effort
172
+ }
173
+ const wasDragging = this._hasMoved;
174
+ this._isDragging = false;
175
+ this._hasMoved = false;
176
+ if (!wasDragging) {
177
+ this.opts.onToggle?.();
178
+ return;
179
+ }
180
+ if (this._pendingGeo) {
181
+ const geo = this._pendingGeo;
182
+ if (geo.x <= this.opts.snapThreshold) {
183
+ this._commit({ ...geo, docked: 'left', x: 0, y: 0 });
184
+ }
185
+ else if (geo.x + geo.width >= window.innerWidth - this.opts.snapThreshold) {
186
+ this._commit({ ...geo, docked: 'right', x: 0, y: 0 });
187
+ }
188
+ else {
189
+ this._commit(geo);
190
+ }
191
+ this._pendingGeo = null;
192
+ }
193
+ };
194
+ // ---- Resize pointer handlers ----
195
+ this.handleResizePointerDown = (dir, e) => {
196
+ let geo = this._geometry;
197
+ if (geo.docked) {
198
+ geo = this._undockGeometry(geo);
199
+ this._commit(geo);
200
+ }
201
+ this._activeResize = dir;
202
+ this._resizeStartMouse = { x: e.clientX, y: e.clientY };
203
+ this._resizeStartGeo = { ...geo };
204
+ try {
205
+ e.target.setPointerCapture(e.pointerId);
206
+ }
207
+ catch {
208
+ // best-effort
209
+ }
210
+ e.preventDefault();
211
+ };
212
+ this.handleResizePointerMove = (e) => {
213
+ if (!this._activeResize)
214
+ return;
215
+ const dx = e.clientX - this._resizeStartMouse.x;
216
+ const dy = e.clientY - this._resizeStartMouse.y;
217
+ const dir = this._activeResize;
218
+ const start = this._resizeStartGeo;
219
+ let { x, y, width, height } = start;
220
+ if (dir.includes('e'))
221
+ width = Math.max(this.opts.minWidth, start.width + dx);
222
+ if (dir.includes('w')) {
223
+ const newW = Math.max(this.opts.minWidth, start.width - dx);
224
+ x = start.x + start.width - newW;
225
+ width = newW;
226
+ }
227
+ if (dir.includes('s'))
228
+ height = Math.max(this.opts.minHeight, start.height + dy);
229
+ if (dir.includes('n')) {
230
+ const newH = Math.max(this.opts.minHeight, start.height - dy);
231
+ y = start.y + start.height - newH;
232
+ height = newH;
233
+ }
234
+ this._writeStylesDuringGesture({ x, y, width, height });
235
+ this._pendingGeo = { x, y, width, height, docked: null };
236
+ };
237
+ this.handleResizePointerUp = (e) => {
238
+ try {
239
+ e.target.releasePointerCapture(e.pointerId);
240
+ }
241
+ catch {
242
+ // best-effort
243
+ }
244
+ this._activeResize = null;
245
+ if (this._pendingGeo) {
246
+ this._commit(this._pendingGeo);
247
+ this._pendingGeo = null;
248
+ }
249
+ };
250
+ this._onWindowResize = () => {
251
+ this._commit(this._clampToViewport(this._geometry));
252
+ };
253
+ this.host = host;
254
+ this.opts = {
255
+ storageKey: options.storageKey ?? DEFAULTS.storageKey,
256
+ minWidth: options.minWidth ?? DEFAULTS.minWidth,
257
+ minHeight: options.minHeight ?? DEFAULTS.minHeight,
258
+ dragThreshold: options.dragThreshold ?? DEFAULTS.dragThreshold,
259
+ snapThreshold: options.snapThreshold ?? DEFAULTS.snapThreshold,
260
+ fabSize: options.fabSize ?? DEFAULTS.fabSize,
261
+ fabInset: options.fabInset ?? DEFAULTS.fabInset,
262
+ onToggle: options.onToggle,
263
+ defaultGeometry: this._resolveDefaultGeometry(options.defaultGeometry),
264
+ };
265
+ this._geometry = this.opts.defaultGeometry;
266
+ this._resizeStartGeo = this._geometry;
267
+ host.addController(this);
268
+ }
269
+ // ---- Public API ----
270
+ /** Current geometry (read-only snapshot). */
271
+ get geometry() {
272
+ return this._geometry;
273
+ }
274
+ /** Pixel rect of the panel, resolving docked positions. */
275
+ get rect() {
276
+ return this._panelRect(this._geometry);
277
+ }
278
+ /** Pixel right edge of the panel (useful for positioning adjacent UI). */
279
+ get rightEdge() {
280
+ const r = this.rect;
281
+ return r.left + r.width;
282
+ }
283
+ /** Set geometry directly — useful for testing or external state sync. */
284
+ setGeometry(geo) {
285
+ this._geometry = geo;
286
+ this._saveGeometry(geo);
287
+ this.host.requestUpdate();
288
+ }
289
+ /** Reset geometry to default (and clear persisted state). */
290
+ reset() {
291
+ this._geometry = this.opts.defaultGeometry;
292
+ try {
293
+ localStorage.removeItem(this.opts.storageKey);
294
+ }
295
+ catch {
296
+ // ignore
297
+ }
298
+ this.host.requestUpdate();
299
+ }
300
+ /** Styles to apply to the panel element. */
301
+ panelStyles() {
302
+ const geo = this._geometry;
303
+ const blur = `blur(${panelShell.backdropBlur})`;
304
+ const shadow = geo.docked === 'right'
305
+ ? panelShell.shadows.dockedRight
306
+ : geo.docked === 'left'
307
+ ? panelShell.shadows.dockedLeft
308
+ : panelShell.shadows.floating;
309
+ const styles = {
310
+ position: 'fixed',
311
+ pointerEvents: 'auto',
312
+ background: panelShell.background,
313
+ backdropFilter: blur,
314
+ webkitBackdropFilter: blur,
315
+ boxShadow: shadow,
316
+ overflow: 'hidden',
317
+ };
318
+ if (geo.docked === 'left') {
319
+ styles.top = '0';
320
+ styles.left = '0';
321
+ styles.width = `${geo.width}px`;
322
+ styles.height = '100vh';
323
+ }
324
+ else if (geo.docked === 'right') {
325
+ styles.top = '0';
326
+ styles.right = '0';
327
+ styles.width = `${geo.width}px`;
328
+ styles.height = '100vh';
329
+ }
330
+ else {
331
+ styles.top = `${geo.y}px`;
332
+ styles.left = `${geo.x}px`;
333
+ styles.width = `${geo.width}px`;
334
+ styles.height = `${geo.height}px`;
335
+ }
336
+ return styles;
337
+ }
338
+ /** Styles to apply to the FAB button. `isOpen` adjusts the shadow. */
339
+ fabStyles(isOpen) {
340
+ const rect = this.rect;
341
+ return {
342
+ position: 'fixed',
343
+ left: `${rect.left + this.opts.fabInset}px`,
344
+ top: `${rect.top + this.opts.fabInset}px`,
345
+ pointerEvents: 'auto',
346
+ width: `${this.opts.fabSize}px`,
347
+ height: `${this.opts.fabSize}px`,
348
+ borderRadius: '50%',
349
+ border: panelShell.fab.border,
350
+ cursor: 'grab',
351
+ display: 'flex',
352
+ alignItems: 'center',
353
+ justifyContent: 'center',
354
+ background: panelShell.fab.background,
355
+ color: panelShell.fab.color,
356
+ boxShadow: isOpen ? panelShell.fab.shadowOpen : panelShell.fab.shadowClosed,
357
+ transition: 'box-shadow 150ms ease',
358
+ touchAction: 'none',
359
+ userSelect: 'none',
360
+ webkitUserSelect: 'none',
361
+ };
362
+ }
363
+ /** Direction descriptors for the 8 resize handles. */
364
+ get handles() {
365
+ return makeResizeHandles();
366
+ }
367
+ /** Bind the current panel element so the controller can direct-write styles during drag/resize. */
368
+ attachPanel(el) {
369
+ this._panelEl = el;
370
+ }
371
+ /** Bind the current FAB element. */
372
+ attachFab(el) {
373
+ this._fabEl = el;
374
+ }
375
+ // ---- ReactiveController lifecycle ----
376
+ hostConnected() {
377
+ this._geometry = this._loadGeometry();
378
+ this.host.requestUpdate();
379
+ if (typeof window !== 'undefined') {
380
+ window.addEventListener('resize', this._onWindowResize);
381
+ }
382
+ }
383
+ hostDisconnected() {
384
+ if (typeof window !== 'undefined') {
385
+ window.removeEventListener('resize', this._onWindowResize);
386
+ }
387
+ }
388
+ // ---- Internals ----
389
+ _commit(geo) {
390
+ this._geometry = geo;
391
+ this._saveGeometry(geo);
392
+ this.host.requestUpdate();
393
+ }
394
+ _writeStylesDuringGesture({ x, y, width, height, }) {
395
+ if (this._panelEl) {
396
+ this._panelEl.style.left = `${x}px`;
397
+ this._panelEl.style.top = `${y}px`;
398
+ this._panelEl.style.right = 'auto';
399
+ this._panelEl.style.width = `${width}px`;
400
+ this._panelEl.style.height = `${height}px`;
401
+ }
402
+ if (this._fabEl) {
403
+ this._fabEl.style.left = `${x + this.opts.fabInset}px`;
404
+ this._fabEl.style.top = `${y + this.opts.fabInset}px`;
405
+ }
406
+ }
407
+ _clampToViewport(geo) {
408
+ if (geo.docked)
409
+ return geo;
410
+ const vw = window.innerWidth;
411
+ const vh = window.innerHeight;
412
+ return {
413
+ ...geo,
414
+ x: Math.max(-(geo.width - this.opts.fabSize), Math.min(geo.x, vw - this.opts.fabSize)),
415
+ y: Math.max(-this.opts.fabInset, Math.min(geo.y, vh - this.opts.fabSize - this.opts.fabInset)),
416
+ };
417
+ }
418
+ _undockGeometry(geo) {
419
+ const r = this._panelRect(geo);
420
+ return { x: r.left, y: r.top, width: geo.width, height: r.height, docked: null };
421
+ }
422
+ _panelRect(geo) {
423
+ if (geo.docked === 'left') {
424
+ return { top: 0, left: 0, width: geo.width, height: window.innerHeight };
425
+ }
426
+ if (geo.docked === 'right') {
427
+ return {
428
+ top: 0,
429
+ left: window.innerWidth - geo.width,
430
+ width: geo.width,
431
+ height: window.innerHeight,
432
+ };
433
+ }
434
+ const { x: left, y: top, width, height } = geo;
435
+ return { top, left, width, height };
436
+ }
437
+ _loadGeometry() {
438
+ if (typeof window === 'undefined')
439
+ return this.opts.defaultGeometry;
440
+ try {
441
+ const raw = localStorage.getItem(this.opts.storageKey);
442
+ if (!raw)
443
+ return this.opts.defaultGeometry;
444
+ const p = JSON.parse(raw);
445
+ return {
446
+ x: typeof p.x === 'number' ? p.x : 0,
447
+ y: typeof p.y === 'number' ? p.y : 0,
448
+ width: Math.max(this.opts.minWidth, typeof p.width === 'number' ? p.width : this.opts.minWidth),
449
+ height: Math.max(this.opts.minHeight, typeof p.height === 'number' ? p.height : window.innerHeight),
450
+ docked: p.docked === 'left' || p.docked === 'right' ? p.docked : null,
451
+ };
452
+ }
453
+ catch {
454
+ return this.opts.defaultGeometry;
455
+ }
456
+ }
457
+ _saveGeometry(geo) {
458
+ try {
459
+ localStorage.setItem(this.opts.storageKey, JSON.stringify(geo));
460
+ }
461
+ catch {
462
+ // ignore
463
+ }
464
+ }
465
+ _resolveDefaultGeometry(partial) {
466
+ const w = typeof window !== 'undefined' ? window : null;
467
+ const base = {
468
+ x: 0,
469
+ y: 0,
470
+ width: DEFAULTS.minWidth,
471
+ height: w ? w.innerHeight : 800,
472
+ docked: 'right',
473
+ };
474
+ return { ...base, ...(partial ?? {}) };
475
+ }
476
+ }
@@ -23,6 +23,8 @@ export { EmptyState } from './components/EmptyState';
23
23
  export { GroupHeader } from './components/GroupHeader';
24
24
  export type { TriggerJourneyProps } from './components/TriggerJourney';
25
25
  export { TriggerJourney } from './components/TriggerJourney';
26
+ export type { PanelGeometry, PanelShellControllerOptions, ResizeDir, ResizeHandleDef, } from './controllers/PanelShellController';
27
+ export { makeResizeHandles, PanelShellController } from './controllers/PanelShellController';
26
28
  export type { ConditionProgress, FormattedCondition } from './formatConditionLabel';
27
29
  export { formatConditionLabel } from './formatConditionLabel';
28
30
  export { useElementRect } from './hooks/useElementRect';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EACL,KAAK,UAAU,EACf,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,cAAc,GACpB,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,YAAY,EACV,aAAa,EACb,2BAA2B,EAC3B,SAAS,EACT,eAAe,GAChB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC7F,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,YAAY,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EACL,KAAK,UAAU,EACf,0BAA0B,EAC1B,oBAAoB,EACpB,KAAK,cAAc,GACpB,MAAM,iCAAiC,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,2BAA2B,CAAC"}
@@ -18,6 +18,7 @@ export { ElementHighlight } from './components/ElementHighlight';
18
18
  export { EmptyState } from './components/EmptyState';
19
19
  export { GroupHeader } from './components/GroupHeader';
20
20
  export { TriggerJourney } from './components/TriggerJourney';
21
+ export { makeResizeHandles, PanelShellController } from './controllers/PanelShellController';
21
22
  export { formatConditionLabel } from './formatConditionLabel';
22
23
  export { useElementRect } from './hooks/useElementRect';
23
24
  export { useTriggerWhenStatus } from './hooks/useTriggerWhenStatus';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Side-effect-only imports that register all Lit custom elements
3
+ * from shared-editor-ui. Import this file to ensure se-editor-card,
4
+ * se-group-header, etc. are available in the custom element registry.
5
+ *
6
+ * Does NOT pull in any React dependencies.
7
+ */
8
+ import './components/AnchorPickerLit';
9
+ import './components/EditorCardLit';
10
+ import './components/EditorPanelShellLit';
11
+ import './components/EditorTextareaLit';
12
+ import './components/ElementHighlightLit';
13
+ import './components/EmptyStateLit';
14
+ import './components/GroupHeaderLit';
15
+ //# sourceMappingURL=lit-elements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lit-elements.d.ts","sourceRoot":"","sources":["../src/lit-elements.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,8BAA8B,CAAC;AACtC,OAAO,4BAA4B,CAAC;AACpC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AACxC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,4BAA4B,CAAC;AACpC,OAAO,6BAA6B,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Side-effect-only imports that register all Lit custom elements
3
+ * from shared-editor-ui. Import this file to ensure se-editor-card,
4
+ * se-group-header, etc. are available in the custom element registry.
5
+ *
6
+ * Does NOT pull in any React dependencies.
7
+ */
8
+ import './components/AnchorPickerLit';
9
+ import './components/EditorCardLit';
10
+ import './components/EditorPanelShellLit';
11
+ import './components/EditorTextareaLit';
12
+ import './components/ElementHighlightLit';
13
+ import './components/EmptyStateLit';
14
+ import './components/GroupHeaderLit';
@@ -29,9 +29,5 @@ export interface BuildActionStepOptions {
29
29
  /** If true, infer $pageview for <a> elements with internal href */
30
30
  inferPageview?: boolean;
31
31
  }
32
- /**
33
- * Build a PostHog action step from a selected element in the chain.
34
- * Does NOT include `selector` — it's not supported in Athena.
35
- */
36
32
  export declare function buildActionStepFromElement(element: PostHogElement, pageUrl: string, options?: BuildActionStepOptions): ActionStep;
37
33
  //# sourceMappingURL=elementChainRecommender.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"elementChainRecommender.d.ts","sourceRoot":"","sources":["../../src/utils/elementChainRecommender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAYvE;AAED,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,sBAA2B,GACnC,UAAU,CAmBZ"}
1
+ {"version":3,"file":"elementChainRecommender.d.ts","sourceRoot":"","sources":["../../src/utils/elementChainRecommender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,CAYvE;AAED,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAsBD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,sBAA2B,GACnC,UAAU,CAmBZ"}
@@ -34,7 +34,23 @@ export function findRecommendedIndex(elements) {
34
34
  /**
35
35
  * Build a PostHog action step from a selected element in the chain.
36
36
  * Does NOT include `selector` — it's not supported in Athena.
37
+ *
38
+ * The `url` field stores the PATHNAME of the page where the user clicked,
39
+ * not the full URL. This matches how the backend generates SQL:
40
+ * step.url → `pathname LIKE '%<url>%'`
41
+ * Storing the full URL (including the editor token / query string) makes
42
+ * the stored KPI data ugly, leaks editor tokens into saved configs, and
43
+ * forces the backend to re-parse on every query. Strip at the boundary.
37
44
  */
45
+ function pageUrlToPathname(pageUrl) {
46
+ try {
47
+ const u = new URL(pageUrl);
48
+ return u.pathname || pageUrl;
49
+ }
50
+ catch {
51
+ return pageUrl;
52
+ }
53
+ }
38
54
  export function buildActionStepFromElement(element, pageUrl, options = {}) {
39
55
  const { inferPageview = false } = options;
40
56
  const href = element.attr__href;
@@ -42,7 +58,7 @@ export function buildActionStepFromElement(element, pageUrl, options = {}) {
42
58
  const step = {
43
59
  event: inferPageview && isInternalLink ? '$pageview' : '$autocapture',
44
60
  tag_name: element.tag_name,
45
- url: pageUrl,
61
+ url: pageUrlToPathname(pageUrl),
46
62
  };
47
63
  const text = (element.$el_text || '').trim();
48
64
  if (text) {
@@ -12,6 +12,10 @@
12
12
  "types": "./src/index.ts",
13
13
  "import": "./dist/index.js",
14
14
  "default": "./dist/index.js"
15
+ },
16
+ "./lit-elements": {
17
+ "types": "./src/lit-elements.ts",
18
+ "import": "./src/lit-elements.ts"
15
19
  }
16
20
  },
17
21
  "files": [
@@ -25,7 +29,9 @@
25
29
  "test:watch": "vitest"
26
30
  },
27
31
  "dependencies": {
28
- "css-selector-generator": "3.8.0"
32
+ "@syntro/design-system": "*",
33
+ "css-selector-generator": "3.8.0",
34
+ "lit": "3.3.2"
29
35
  },
30
36
  "peerDependencies": {
31
37
  "lucide-react": ">=0.400.0",
@@ -33,6 +39,8 @@
33
39
  "react-dom": ">=18.0.0"
34
40
  },
35
41
  "devDependencies": {
42
+ "@open-wc/testing": "4.0.0",
43
+ "@open-wc/testing-helpers": "3.0.1",
36
44
  "@testing-library/dom": "10.4.1",
37
45
  "@testing-library/react": "16.3.2",
38
46
  "@types/react": "19.2.14",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/adapt-nav",
3
- "version": "2.13.0",
3
+ "version": "2.15.0",
4
4
  "description": "Adaptive Navigation - Nav link widget, scroll-to and page navigation actions",
5
5
  "license": "Proprietary",
6
6
  "private": false,
@@ -19,6 +19,10 @@
19
19
  "types": "./dist/runtime.d.ts",
20
20
  "import": "./dist/runtime.js"
21
21
  },
22
+ "./runtime-lit": {
23
+ "types": "./src/runtime-lit.ts",
24
+ "import": "./src/runtime-lit.ts"
25
+ },
22
26
  "./schema": {
23
27
  "types": "./dist/schema.d.ts",
24
28
  "import": "./dist/schema.js"
@@ -26,6 +30,10 @@
26
30
  "./editor": {
27
31
  "types": "./dist/editor.d.ts",
28
32
  "import": "./dist/editor.js"
33
+ },
34
+ "./editor-lit": {
35
+ "types": "./src/editor-lit.ts",
36
+ "import": "./src/editor-lit.ts"
29
37
  }
30
38
  },
31
39
  "files": [
@@ -55,7 +63,10 @@
55
63
  "@syntro/design-system": "*"
56
64
  },
57
65
  "devDependencies": {
66
+ "@open-wc/testing": "4.0.0",
67
+ "@open-wc/testing-helpers": "3.0.1",
58
68
  "@types/react": "19.2.14",
69
+ "lit": "3.3.2",
59
70
  "typescript": "5.9.3",
60
71
  "zod": "3.25.76",
61
72
  "@testing-library/react": "16.3.2",