@flowsterix/react 0.10.1 → 0.11.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 (47) hide show
  1. package/dist/chunk-AJZMUYBN.mjs +21 -0
  2. package/dist/context.d.ts.map +1 -1
  3. package/dist/devtools/DevToolsContext.d.ts +31 -0
  4. package/dist/devtools/DevToolsContext.d.ts.map +1 -0
  5. package/dist/devtools/DevToolsProvider.d.ts +9 -0
  6. package/dist/devtools/DevToolsProvider.d.ts.map +1 -0
  7. package/dist/devtools/components/FlowEditModal.d.ts +11 -0
  8. package/dist/devtools/components/FlowEditModal.d.ts.map +1 -0
  9. package/dist/devtools/components/FlowItem.d.ts +8 -0
  10. package/dist/devtools/components/FlowItem.d.ts.map +1 -0
  11. package/dist/devtools/components/FlowsTab.d.ts +5 -0
  12. package/dist/devtools/components/FlowsTab.d.ts.map +1 -0
  13. package/dist/devtools/components/GrabberOverlay.d.ts +8 -0
  14. package/dist/devtools/components/GrabberOverlay.d.ts.map +1 -0
  15. package/dist/devtools/components/ShadowRoot.d.ts +7 -0
  16. package/dist/devtools/components/ShadowRoot.d.ts.map +1 -0
  17. package/dist/devtools/components/StepItem.d.ts +16 -0
  18. package/dist/devtools/components/StepItem.d.ts.map +1 -0
  19. package/dist/devtools/components/StepList.d.ts +17 -0
  20. package/dist/devtools/components/StepList.d.ts.map +1 -0
  21. package/dist/devtools/components/TabNav.d.ts +9 -0
  22. package/dist/devtools/components/TabNav.d.ts.map +1 -0
  23. package/dist/devtools/components/Toolbar.d.ts +11 -0
  24. package/dist/devtools/components/Toolbar.d.ts.map +1 -0
  25. package/dist/devtools/hooks/useElementInfo.d.ts +7 -0
  26. package/dist/devtools/hooks/useElementInfo.d.ts.map +1 -0
  27. package/dist/devtools/hooks/useFlowsData.d.ts +16 -0
  28. package/dist/devtools/hooks/useFlowsData.d.ts.map +1 -0
  29. package/dist/devtools/hooks/useGrabMode.d.ts +16 -0
  30. package/dist/devtools/hooks/useGrabMode.d.ts.map +1 -0
  31. package/dist/devtools/hooks/useStepStore.d.ts +22 -0
  32. package/dist/devtools/hooks/useStepStore.d.ts.map +1 -0
  33. package/dist/devtools/index.cjs +2736 -0
  34. package/dist/devtools/index.d.ts +32 -0
  35. package/dist/devtools/index.d.ts.map +1 -0
  36. package/dist/devtools/index.mjs +2684 -0
  37. package/dist/devtools/types.d.ts +66 -0
  38. package/dist/devtools/types.d.ts.map +1 -0
  39. package/dist/devtools/utils/selectorGenerator.d.ts +11 -0
  40. package/dist/devtools/utils/selectorGenerator.d.ts.map +1 -0
  41. package/dist/devtools/utils/sourceExtractor.d.ts +45 -0
  42. package/dist/devtools/utils/sourceExtractor.d.ts.map +1 -0
  43. package/dist/devtools/utils/storage.d.ts +5 -0
  44. package/dist/devtools/utils/storage.d.ts.map +1 -0
  45. package/dist/index.cjs +287 -229
  46. package/dist/index.mjs +62 -7
  47. package/package.json +10 -1
@@ -0,0 +1,2736 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/devtools/index.tsx
21
+ var devtools_exports = {};
22
+ __export(devtools_exports, {
23
+ DevToolsContext: () => DevToolsContext,
24
+ DevToolsProvider: () => DevToolsProvider,
25
+ FlowEditModal: () => FlowEditModal,
26
+ FlowItem: () => FlowItem,
27
+ FlowsTab: () => FlowsTab,
28
+ GrabberOverlay: () => GrabberOverlay,
29
+ SortableStepItem: () => SortableStepItem,
30
+ StepItem: () => SortableStepItem,
31
+ StepItemDragPreview: () => StepItemDragPreview,
32
+ StepList: () => StepList,
33
+ TabNav: () => TabNav,
34
+ Toolbar: () => Toolbar,
35
+ clearSteps: () => clearSteps,
36
+ extractComponentHierarchy: () => extractComponentHierarchy,
37
+ extractSource: () => extractSource,
38
+ formatSourcePath: () => formatSourcePath,
39
+ generateSelector: () => generateSelector,
40
+ getVSCodeLink: () => getVSCodeLink,
41
+ loadSteps: () => loadSteps,
42
+ saveSteps: () => saveSteps,
43
+ useDevToolsContext: () => useDevToolsContext,
44
+ useDevToolsContextRequired: () => useDevToolsContextRequired,
45
+ useElementInfo: () => useElementInfo,
46
+ useFlowsData: () => useFlowsData,
47
+ useGrabMode: () => useGrabMode,
48
+ useStepStore: () => useStepStore
49
+ });
50
+ module.exports = __toCommonJS(devtools_exports);
51
+
52
+ // src/devtools/DevToolsProvider.tsx
53
+ var import_react16 = require("react");
54
+ var import_react_dom3 = require("react-dom");
55
+ var import_react17 = require("motion/react");
56
+
57
+ // src/devtools/components/GrabberOverlay.tsx
58
+ var import_react_dom = require("react-dom");
59
+ var import_react = require("motion/react");
60
+
61
+ // src/devtools/utils/sourceExtractor.ts
62
+ function getReactFiber(element) {
63
+ const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
64
+ if (hook?.renderers) {
65
+ for (const renderer of hook.renderers.values()) {
66
+ if (renderer.findFiberByHostInstance) {
67
+ const fiber = renderer.findFiberByHostInstance(element);
68
+ if (fiber) return fiber;
69
+ }
70
+ }
71
+ }
72
+ const keys = Object.keys(element);
73
+ for (const key of keys) {
74
+ if (key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")) {
75
+ return element[key];
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ function getFiberName(fiber) {
81
+ const type = fiber.type || fiber.elementType;
82
+ if (!type) return null;
83
+ if (typeof type === "string") {
84
+ return type;
85
+ }
86
+ if (typeof type === "object") {
87
+ return type.displayName || type.name || null;
88
+ }
89
+ if (typeof type === "function") {
90
+ return type.displayName || type.name || null;
91
+ }
92
+ return null;
93
+ }
94
+ function findDebugSource(fiber) {
95
+ let current = fiber;
96
+ let depth = 0;
97
+ const maxDepth = 50;
98
+ while (current && depth < maxDepth) {
99
+ if (current._debugSource) {
100
+ const source = current._debugSource;
101
+ return {
102
+ fileName: source.fileName,
103
+ lineNumber: source.lineNumber,
104
+ columnNumber: source.columnNumber ?? 0
105
+ };
106
+ }
107
+ current = current.return ?? null;
108
+ depth++;
109
+ }
110
+ return null;
111
+ }
112
+ function extractSource(params) {
113
+ const { element } = params;
114
+ if (typeof window === "undefined") return null;
115
+ try {
116
+ const fiber = getReactFiber(element);
117
+ if (!fiber) return null;
118
+ return findDebugSource(fiber);
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+ function extractComponentHierarchy(params) {
124
+ const { element } = params;
125
+ const hierarchy = [];
126
+ if (typeof window === "undefined") return hierarchy;
127
+ try {
128
+ const fiber = getReactFiber(element);
129
+ if (!fiber) return hierarchy;
130
+ let current = fiber;
131
+ let depth = 0;
132
+ const maxDepth = 20;
133
+ while (current && depth < maxDepth) {
134
+ const name = getFiberName(current);
135
+ if (name && !hierarchy.includes(name)) {
136
+ hierarchy.push(name);
137
+ }
138
+ current = current.return ?? null;
139
+ depth++;
140
+ }
141
+ return hierarchy;
142
+ } catch {
143
+ return hierarchy;
144
+ }
145
+ }
146
+ function formatSourcePath(params) {
147
+ const { source } = params;
148
+ const fileName = source.fileName.replace(/^.*\/src\//, "src/");
149
+ return `${fileName}:${source.lineNumber}`;
150
+ }
151
+ function getVSCodeLink(params) {
152
+ const { source } = params;
153
+ return `vscode://file${source.fileName}:${source.lineNumber}:${source.columnNumber}`;
154
+ }
155
+
156
+ // src/devtools/components/GrabberOverlay.tsx
157
+ var import_jsx_runtime = require("react/jsx-runtime");
158
+ var styles = {
159
+ root: {
160
+ position: "fixed",
161
+ inset: 0,
162
+ pointerEvents: "none",
163
+ zIndex: 99999
164
+ },
165
+ highlight: {
166
+ position: "absolute",
167
+ border: "2px solid hsl(217 91% 60%)",
168
+ backgroundColor: "hsl(217 91% 60% / 0.08)",
169
+ borderRadius: 6,
170
+ pointerEvents: "none",
171
+ boxShadow: "0 0 0 4px hsl(217 91% 60% / 0.15), 0 4px 20px hsl(217 91% 60% / 0.2)"
172
+ },
173
+ label: {
174
+ position: "absolute",
175
+ bottom: "100%",
176
+ left: 0,
177
+ marginBottom: 6,
178
+ display: "flex",
179
+ flexDirection: "column",
180
+ gap: 4,
181
+ padding: "8px 10px",
182
+ backgroundColor: "hsl(222 47% 11%)",
183
+ border: "1px solid hsl(215 20% 22%)",
184
+ color: "hsl(215 20% 75%)",
185
+ fontSize: 11,
186
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
187
+ borderRadius: 8,
188
+ boxShadow: "0 8px 24px rgba(0, 0, 0, 0.4)",
189
+ maxWidth: 280
190
+ },
191
+ labelTop: {
192
+ display: "flex",
193
+ alignItems: "center",
194
+ gap: 6
195
+ },
196
+ tagBadge: {
197
+ display: "inline-flex",
198
+ alignItems: "center",
199
+ padding: "2px 6px",
200
+ backgroundColor: "hsl(215 20% 22%)",
201
+ color: "hsl(217 91% 70%)",
202
+ fontFamily: "ui-monospace, monospace",
203
+ fontSize: 10,
204
+ fontWeight: 500,
205
+ borderRadius: 4
206
+ },
207
+ selector: {
208
+ color: "hsl(265 83% 78%)",
209
+ fontFamily: "ui-monospace, monospace",
210
+ fontSize: 10,
211
+ overflow: "hidden",
212
+ textOverflow: "ellipsis",
213
+ whiteSpace: "nowrap",
214
+ padding: "4px 6px",
215
+ backgroundColor: "hsl(215 20% 15%)",
216
+ borderRadius: 4,
217
+ border: "1px solid hsl(215 20% 20%)"
218
+ },
219
+ source: {
220
+ display: "flex",
221
+ alignItems: "center",
222
+ gap: 4,
223
+ color: "hsl(142 71% 55%)",
224
+ fontFamily: "ui-monospace, monospace",
225
+ fontSize: 10
226
+ },
227
+ hint: {
228
+ position: "fixed",
229
+ bottom: 20,
230
+ left: "50%",
231
+ transform: "translateX(-50%)",
232
+ display: "flex",
233
+ alignItems: "center",
234
+ gap: 12,
235
+ padding: "10px 16px",
236
+ backgroundColor: "hsl(222 47% 11%)",
237
+ border: "1px solid hsl(215 20% 22%)",
238
+ color: "hsl(215 20% 70%)",
239
+ fontSize: 12,
240
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
241
+ borderRadius: 10,
242
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.5)"
243
+ },
244
+ hintItem: {
245
+ display: "flex",
246
+ alignItems: "center",
247
+ gap: 6,
248
+ color: "hsl(215 20% 65%)"
249
+ },
250
+ kbd: {
251
+ display: "inline-flex",
252
+ alignItems: "center",
253
+ padding: "2px 5px",
254
+ backgroundColor: "hsl(215 20% 15%)",
255
+ border: "1px solid hsl(215 20% 22%)",
256
+ borderRadius: 4,
257
+ fontSize: 10,
258
+ fontFamily: "ui-monospace, monospace",
259
+ color: "hsl(215 20% 60%)",
260
+ fontWeight: 500
261
+ },
262
+ divider: {
263
+ width: 1,
264
+ height: 16,
265
+ backgroundColor: "hsl(215 20% 25%)"
266
+ }
267
+ };
268
+ var springTransition = {
269
+ type: "spring",
270
+ damping: 30,
271
+ stiffness: 400,
272
+ mass: 0.8
273
+ };
274
+ function GrabberOverlay(props) {
275
+ const { isGrabbing, hoveredInfo, container } = props;
276
+ if (typeof window === "undefined") return null;
277
+ const portalContainer = container ?? document.body;
278
+ const labelStyle = {
279
+ ...styles.label
280
+ };
281
+ if (hoveredInfo && hoveredInfo.rect.top < 80) {
282
+ labelStyle.bottom = "auto";
283
+ labelStyle.top = "100%";
284
+ labelStyle.marginBottom = 0;
285
+ labelStyle.marginTop = 6;
286
+ }
287
+ if (hoveredInfo && hoveredInfo.rect.left > window.innerWidth - 300) {
288
+ labelStyle.left = "auto";
289
+ labelStyle.right = 0;
290
+ }
291
+ return (0, import_react_dom.createPortal)(
292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.root, "data-devtools-panel": "", children: [
293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.AnimatePresence, { children: isGrabbing && hoveredInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
294
+ import_react.motion.div,
295
+ {
296
+ style: styles.highlight,
297
+ initial: {
298
+ top: hoveredInfo.rect.top,
299
+ left: hoveredInfo.rect.left,
300
+ width: hoveredInfo.rect.width,
301
+ height: hoveredInfo.rect.height,
302
+ opacity: 0
303
+ },
304
+ animate: {
305
+ top: hoveredInfo.rect.top,
306
+ left: hoveredInfo.rect.left,
307
+ width: hoveredInfo.rect.width,
308
+ height: hoveredInfo.rect.height,
309
+ opacity: 1
310
+ },
311
+ exit: {
312
+ opacity: 0
313
+ },
314
+ transition: springTransition,
315
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
316
+ import_react.motion.div,
317
+ {
318
+ style: labelStyle,
319
+ initial: { opacity: 0, y: 4 },
320
+ animate: { opacity: 1, y: 0 },
321
+ transition: { delay: 0.03, duration: 0.12 },
322
+ children: [
323
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.labelTop, children: [
324
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: styles.tagBadge, children: [
325
+ "<",
326
+ hoveredInfo.tag,
327
+ ">"
328
+ ] }),
329
+ hoveredInfo.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
330
+ "span",
331
+ {
332
+ style: {
333
+ color: "hsl(215 20% 65%)",
334
+ overflow: "hidden",
335
+ textOverflow: "ellipsis",
336
+ whiteSpace: "nowrap",
337
+ maxWidth: 150,
338
+ fontSize: 11
339
+ },
340
+ children: hoveredInfo.text
341
+ }
342
+ )
343
+ ] }),
344
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.selector, children: hoveredInfo.selector }),
345
+ hoveredInfo.source && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.source, children: [
346
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5L14 4.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5h-2z" }) }),
347
+ formatSourcePath({ source: hoveredInfo.source })
348
+ ] })
349
+ ]
350
+ }
351
+ )
352
+ },
353
+ "grabber-highlight"
354
+ ) }),
355
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.AnimatePresence, { children: isGrabbing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
356
+ import_react.motion.div,
357
+ {
358
+ style: styles.hint,
359
+ initial: { opacity: 0, y: 10, scale: 0.95 },
360
+ animate: { opacity: 1, y: 0, scale: 1 },
361
+ exit: { opacity: 0, y: 10, scale: 0.95 },
362
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
363
+ children: [
364
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.hintItem, children: [
365
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.kbd, children: "Click" }),
366
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Add step" })
367
+ ] }),
368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.divider }),
369
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.hintItem, children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.kbd, children: "ESC" }),
371
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Cancel" })
372
+ ] }),
373
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.divider }),
374
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.hintItem, children: [
375
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.kbd, children: "Ctrl+Shift+G" }),
376
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Toggle" })
377
+ ] })
378
+ ]
379
+ },
380
+ "grabber-hint"
381
+ ) })
382
+ ] }),
383
+ portalContainer
384
+ );
385
+ }
386
+
387
+ // src/devtools/components/StepList.tsx
388
+ var import_react4 = require("react");
389
+ var import_core = require("@dnd-kit/core");
390
+ var import_sortable2 = require("@dnd-kit/sortable");
391
+
392
+ // src/devtools/components/StepItem.tsx
393
+ var import_sortable = require("@dnd-kit/sortable");
394
+ var import_utilities = require("@dnd-kit/utilities");
395
+ var import_jsx_runtime2 = require("react/jsx-runtime");
396
+ var styles2 = {
397
+ card: {
398
+ display: "flex",
399
+ alignItems: "stretch",
400
+ gap: 0,
401
+ backgroundColor: "hsl(215 20% 16%)",
402
+ borderRadius: 8,
403
+ border: "1px solid hsl(215 20% 22%)",
404
+ fontSize: 12,
405
+ fontFamily: "inherit",
406
+ overflow: "hidden"
407
+ },
408
+ cardGhost: {
409
+ opacity: 0.4,
410
+ border: "1px dashed hsl(217 91% 60%)",
411
+ backgroundColor: "hsl(217 91% 60% / 0.05)"
412
+ },
413
+ cardOverlay: {
414
+ boxShadow: "0 12px 24px rgba(0, 0, 0, 0.4)",
415
+ border: "1px solid hsl(217 91% 60%)"
416
+ },
417
+ dragHandle: {
418
+ display: "flex",
419
+ alignItems: "center",
420
+ justifyContent: "center",
421
+ width: 28,
422
+ cursor: "grab",
423
+ color: "hsl(215 20% 40%)",
424
+ flexShrink: 0,
425
+ backgroundColor: "hsl(215 20% 13%)",
426
+ borderRight: "1px solid hsl(215 20% 20%)",
427
+ transition: "color 0.15s ease, background-color 0.15s ease"
428
+ },
429
+ dragHandleActive: {
430
+ cursor: "grabbing",
431
+ backgroundColor: "hsl(217 91% 60% / 0.15)",
432
+ color: "hsl(217 91% 60%)"
433
+ },
434
+ content: {
435
+ flex: 1,
436
+ minWidth: 0,
437
+ display: "flex",
438
+ flexDirection: "column",
439
+ gap: 4,
440
+ padding: 10
441
+ },
442
+ header: {
443
+ display: "flex",
444
+ alignItems: "center",
445
+ gap: 6
446
+ },
447
+ order: {
448
+ display: "flex",
449
+ alignItems: "center",
450
+ justifyContent: "center",
451
+ width: 18,
452
+ height: 18,
453
+ backgroundColor: "hsl(217 91% 55% / 0.2)",
454
+ color: "hsl(217 91% 70%)",
455
+ fontSize: 10,
456
+ fontWeight: 600,
457
+ borderRadius: 5,
458
+ flexShrink: 0
459
+ },
460
+ tagBadge: {
461
+ display: "inline-flex",
462
+ alignItems: "center",
463
+ padding: "2px 6px",
464
+ backgroundColor: "hsl(215 20% 22%)",
465
+ color: "hsl(217 91% 70%)",
466
+ fontFamily: "ui-monospace, monospace",
467
+ fontSize: 10,
468
+ fontWeight: 500,
469
+ borderRadius: 4
470
+ },
471
+ text: {
472
+ color: "hsl(215 20% 65%)",
473
+ overflow: "hidden",
474
+ textOverflow: "ellipsis",
475
+ whiteSpace: "nowrap",
476
+ maxWidth: 140,
477
+ fontSize: 11
478
+ },
479
+ selector: {
480
+ display: "block",
481
+ color: "hsl(265 83% 75%)",
482
+ fontFamily: "ui-monospace, monospace",
483
+ fontSize: 10,
484
+ overflow: "hidden",
485
+ textOverflow: "ellipsis",
486
+ whiteSpace: "nowrap",
487
+ padding: "4px 6px",
488
+ backgroundColor: "hsl(215 20% 12%)",
489
+ borderRadius: 4,
490
+ border: "1px solid hsl(215 20% 18%)"
491
+ },
492
+ sourceRow: {
493
+ display: "flex",
494
+ alignItems: "center",
495
+ gap: 4,
496
+ marginTop: 2
497
+ },
498
+ sourceLink: {
499
+ display: "inline-flex",
500
+ alignItems: "center",
501
+ gap: 4,
502
+ color: "hsl(142 71% 55%)",
503
+ fontSize: 10,
504
+ fontFamily: "ui-monospace, monospace",
505
+ textDecoration: "none",
506
+ padding: "2px 0",
507
+ transition: "color 0.15s ease"
508
+ },
509
+ copyButton: {
510
+ display: "flex",
511
+ alignItems: "center",
512
+ justifyContent: "center",
513
+ width: 18,
514
+ height: 18,
515
+ backgroundColor: "transparent",
516
+ border: "none",
517
+ color: "hsl(215 20% 50%)",
518
+ cursor: "pointer",
519
+ padding: 0,
520
+ borderRadius: 4,
521
+ transition: "color 0.15s ease, background-color 0.15s ease",
522
+ outline: "none"
523
+ },
524
+ deleteButton: {
525
+ display: "flex",
526
+ alignItems: "center",
527
+ justifyContent: "center",
528
+ width: 22,
529
+ height: 22,
530
+ backgroundColor: "transparent",
531
+ border: "none",
532
+ color: "hsl(215 20% 45%)",
533
+ cursor: "pointer",
534
+ padding: 0,
535
+ borderRadius: 5,
536
+ flexShrink: 0,
537
+ alignSelf: "flex-start",
538
+ marginTop: 2,
539
+ transition: "color 0.15s ease, background-color 0.15s ease",
540
+ outline: "none"
541
+ }
542
+ };
543
+ function SortableStepItem(props) {
544
+ const { step, index, onDelete, isBeingDragged = false } = props;
545
+ const {
546
+ attributes,
547
+ listeners,
548
+ setNodeRef,
549
+ transform,
550
+ transition,
551
+ isDragging
552
+ } = (0, import_sortable.useSortable)({ id: step.id });
553
+ const handleCopySource = async () => {
554
+ if (step.source) {
555
+ const path = formatSourcePath({ source: step.source });
556
+ await navigator.clipboard.writeText(path);
557
+ }
558
+ };
559
+ const isGhost = isDragging || isBeingDragged;
560
+ const wrapperStyle = {
561
+ transform: import_utilities.CSS.Transform.toString(transform),
562
+ transition: transition ?? "transform 200ms ease"
563
+ };
564
+ const cardStyle = {
565
+ ...styles2.card,
566
+ ...isGhost && styles2.cardGhost
567
+ };
568
+ const handleStyle = {
569
+ ...styles2.dragHandle
570
+ };
571
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: setNodeRef, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
572
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: handleStyle, ...attributes, ...listeners, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "currentColor", children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "3", cy: "2", r: "1.5" }),
574
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7", cy: "2", r: "1.5" }),
575
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "3", cy: "8", r: "1.5" }),
576
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7", cy: "8", r: "1.5" }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "3", cy: "14", r: "1.5" }),
578
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7", cy: "14", r: "1.5" })
579
+ ] }) }),
580
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.content, children: [
581
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.header, children: [
582
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.order, children: index + 1 }),
583
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles2.tagBadge, children: [
584
+ "<",
585
+ step.elementTag,
586
+ ">"
587
+ ] }),
588
+ step.elementText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.text, children: step.elementText })
589
+ ] }),
590
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles2.selector, children: step.selector }),
591
+ step.source && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.sourceRow, children: [
592
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
593
+ "svg",
594
+ {
595
+ width: "10",
596
+ height: "10",
597
+ viewBox: "0 0 16 16",
598
+ fill: "hsl(142 71% 55%)",
599
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5L14 4.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5h-2z" })
600
+ }
601
+ ),
602
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
603
+ "a",
604
+ {
605
+ href: getVSCodeLink({ source: step.source }),
606
+ style: styles2.sourceLink,
607
+ title: "Open in VS Code",
608
+ children: formatSourcePath({ source: step.source })
609
+ }
610
+ ),
611
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
612
+ "button",
613
+ {
614
+ type: "button",
615
+ style: styles2.copyButton,
616
+ onClick: handleCopySource,
617
+ title: "Copy path",
618
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
619
+ "svg",
620
+ {
621
+ width: "10",
622
+ height: "10",
623
+ viewBox: "0 0 16 16",
624
+ fill: "currentColor",
625
+ children: [
626
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10 2H4a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM4 1h6a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3z" }),
627
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14 5a1 1 0 0 1 1 1v8a2 2 0 0 1-2 2H6a1 1 0 0 1 0-2h7V6a1 1 0 0 1 1-1z" })
628
+ ]
629
+ }
630
+ )
631
+ }
632
+ )
633
+ ] })
634
+ ] }),
635
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
636
+ "button",
637
+ {
638
+ type: "button",
639
+ style: styles2.deleteButton,
640
+ onClick: onDelete,
641
+ title: "Delete step",
642
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" }) })
643
+ }
644
+ )
645
+ ] }) });
646
+ }
647
+ function StepItemDragPreview(props) {
648
+ const { step, index } = props;
649
+ const cardStyle = {
650
+ ...styles2.card,
651
+ ...styles2.cardOverlay,
652
+ width: 298
653
+ // Fixed width for overlay
654
+ };
655
+ const handleStyle = {
656
+ ...styles2.dragHandle,
657
+ ...styles2.dragHandleActive
658
+ };
659
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: cardStyle, children: [
660
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: handleStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "currentColor", children: [
661
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "3", cy: "2", r: "1.5" }),
662
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7", cy: "2", r: "1.5" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "3", cy: "8", r: "1.5" }),
664
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7", cy: "8", r: "1.5" }),
665
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "3", cy: "14", r: "1.5" }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7", cy: "14", r: "1.5" })
667
+ ] }) }),
668
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.content, children: [
669
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.header, children: [
670
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.order, children: index + 1 }),
671
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles2.tagBadge, children: [
672
+ "<",
673
+ step.elementTag,
674
+ ">"
675
+ ] }),
676
+ step.elementText && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.text, children: step.elementText })
677
+ ] }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles2.selector, children: step.selector }),
679
+ step.source && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles2.sourceRow, children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
681
+ "svg",
682
+ {
683
+ width: "10",
684
+ height: "10",
685
+ viewBox: "0 0 16 16",
686
+ fill: "hsl(142 71% 55%)",
687
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5L14 4.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5h-2z" })
688
+ }
689
+ ),
690
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles2.sourceLink, children: formatSourcePath({ source: step.source }) })
691
+ ] })
692
+ ] }),
693
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { ...styles2.deleteButton, visibility: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" }) }) })
694
+ ] });
695
+ }
696
+
697
+ // src/devtools/components/Toolbar.tsx
698
+ var import_react2 = require("react");
699
+ var import_react3 = require("motion/react");
700
+ var import_jsx_runtime3 = require("react/jsx-runtime");
701
+ var styles3 = {
702
+ toolbar: {
703
+ display: "flex",
704
+ flexDirection: "column",
705
+ gap: 8,
706
+ padding: "10px 10px 0"
707
+ },
708
+ grabRow: {
709
+ display: "flex",
710
+ gap: 6
711
+ },
712
+ grabButton: {
713
+ flex: 1,
714
+ display: "flex",
715
+ alignItems: "center",
716
+ justifyContent: "center",
717
+ gap: 6,
718
+ padding: "8px 12px",
719
+ backgroundColor: "#252a35",
720
+ border: "1px solid #353d4a",
721
+ borderRadius: 8,
722
+ color: "#a3adc2",
723
+ fontSize: 12,
724
+ fontWeight: 500,
725
+ fontFamily: "inherit",
726
+ cursor: "pointer",
727
+ transition: "all 0.15s ease",
728
+ outline: "none"
729
+ },
730
+ grabButtonActive: {
731
+ backgroundColor: "rgba(59, 130, 246, 0.15)",
732
+ borderColor: "rgba(59, 130, 246, 0.4)",
733
+ color: "#60a5fa",
734
+ boxShadow: "0 0 0 2px rgba(59, 130, 246, 0.1)"
735
+ },
736
+ actionRow: {
737
+ display: "flex",
738
+ gap: 6
739
+ },
740
+ actionButton: {
741
+ flex: 1,
742
+ display: "flex",
743
+ alignItems: "center",
744
+ justifyContent: "center",
745
+ gap: 5,
746
+ padding: "7px 8px",
747
+ backgroundColor: "transparent",
748
+ border: "1px solid #2d3544",
749
+ borderRadius: 6,
750
+ color: "#8b96a9",
751
+ fontSize: 11,
752
+ fontWeight: 500,
753
+ fontFamily: "inherit",
754
+ cursor: "pointer",
755
+ transition: "all 0.15s ease",
756
+ whiteSpace: "nowrap",
757
+ position: "relative",
758
+ outline: "none"
759
+ },
760
+ actionButtonDisabled: {
761
+ opacity: 0.4,
762
+ cursor: "not-allowed"
763
+ },
764
+ actionButtonDanger: {
765
+ borderColor: "#7a2c2c",
766
+ color: "#e05555"
767
+ },
768
+ kbd: {
769
+ display: "inline-flex",
770
+ alignItems: "center",
771
+ padding: "1px 4px",
772
+ marginLeft: 6,
773
+ backgroundColor: "#1e232c",
774
+ border: "1px solid #2d3544",
775
+ borderRadius: 3,
776
+ fontSize: 10,
777
+ fontFamily: "ui-monospace, monospace",
778
+ color: "#6b7685"
779
+ },
780
+ copiedBadge: {
781
+ position: "absolute",
782
+ top: -6,
783
+ right: -6,
784
+ padding: "2px 5px",
785
+ backgroundColor: "#166534",
786
+ color: "#86efac",
787
+ fontSize: 9,
788
+ fontWeight: 600,
789
+ borderRadius: 4,
790
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)"
791
+ }
792
+ };
793
+ function Toolbar(props) {
794
+ const { mode, stepCount, onToggleGrab, onExport, onCopyForAI, onReset } = props;
795
+ const [copied, setCopied] = (0, import_react2.useState)(false);
796
+ const isGrabbing = mode === "grabbing";
797
+ const hasSteps = stepCount > 0;
798
+ const handleCopy = async () => {
799
+ await onCopyForAI();
800
+ setCopied(true);
801
+ setTimeout(() => setCopied(false), 1500);
802
+ };
803
+ const grabButtonStyle = {
804
+ ...styles3.grabButton,
805
+ ...isGrabbing && styles3.grabButtonActive
806
+ };
807
+ const exportButtonStyle = {
808
+ ...styles3.actionButton,
809
+ ...!hasSteps && styles3.actionButtonDisabled
810
+ };
811
+ const copyButtonStyle = {
812
+ ...styles3.actionButton,
813
+ ...!hasSteps && styles3.actionButtonDisabled
814
+ };
815
+ const resetButtonStyle = {
816
+ ...styles3.actionButton,
817
+ ...!hasSteps && styles3.actionButtonDisabled,
818
+ ...hasSteps && styles3.actionButtonDanger
819
+ };
820
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: styles3.toolbar, children: [
821
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles3.grabRow, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
822
+ import_react3.motion.button,
823
+ {
824
+ type: "button",
825
+ style: grabButtonStyle,
826
+ onClick: onToggleGrab,
827
+ whileHover: { scale: 1.01 },
828
+ whileTap: { scale: 0.98 },
829
+ children: isGrabbing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
830
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
831
+ "svg",
832
+ {
833
+ width: "14",
834
+ height: "14",
835
+ viewBox: "0 0 16 16",
836
+ fill: "currentColor",
837
+ children: [
838
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("circle", { cx: "8", cy: "8", r: "3", children: [
839
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
840
+ "animate",
841
+ {
842
+ attributeName: "r",
843
+ values: "3;4;3",
844
+ dur: "1s",
845
+ repeatCount: "indefinite"
846
+ }
847
+ ),
848
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
849
+ "animate",
850
+ {
851
+ attributeName: "opacity",
852
+ values: "1;0.5;1",
853
+ dur: "1s",
854
+ repeatCount: "indefinite"
855
+ }
856
+ )
857
+ ] }),
858
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
859
+ "circle",
860
+ {
861
+ cx: "8",
862
+ cy: "8",
863
+ r: "6",
864
+ fill: "none",
865
+ stroke: "currentColor",
866
+ strokeWidth: "1",
867
+ opacity: "0.3",
868
+ children: [
869
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
870
+ "animate",
871
+ {
872
+ attributeName: "r",
873
+ values: "4;7;4",
874
+ dur: "1.5s",
875
+ repeatCount: "indefinite"
876
+ }
877
+ ),
878
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
879
+ "animate",
880
+ {
881
+ attributeName: "opacity",
882
+ values: "0.3;0;0.3",
883
+ dur: "1.5s",
884
+ repeatCount: "indefinite"
885
+ }
886
+ )
887
+ ]
888
+ }
889
+ )
890
+ ]
891
+ }
892
+ ),
893
+ "Grabbing..."
894
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
895
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
896
+ "svg",
897
+ {
898
+ width: "14",
899
+ height: "14",
900
+ viewBox: "0 0 16 16",
901
+ fill: "currentColor",
902
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M14 0a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12zM5.904 10.803L10 6.707v2.768a.5.5 0 0 0 1 0V5.5a.5.5 0 0 0-.5-.5H6.525a.5.5 0 1 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 .707.707z" })
903
+ }
904
+ ),
905
+ "Grab Element",
906
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: styles3.kbd, children: "Ctrl+Shift+G" })
907
+ ] })
908
+ }
909
+ ) }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: styles3.actionRow, children: [
911
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
912
+ import_react3.motion.button,
913
+ {
914
+ type: "button",
915
+ style: exportButtonStyle,
916
+ onClick: onExport,
917
+ disabled: !hasSteps,
918
+ whileHover: hasSteps ? { scale: 1.02 } : {},
919
+ whileTap: hasSteps ? { scale: 0.98 } : {},
920
+ title: "Download JSON file",
921
+ children: [
922
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "11", height: "11", viewBox: "0 0 16 16", fill: "currentColor", children: [
923
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z" }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z" })
925
+ ] }),
926
+ "Export"
927
+ ]
928
+ }
929
+ ),
930
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
931
+ import_react3.motion.button,
932
+ {
933
+ type: "button",
934
+ style: copyButtonStyle,
935
+ onClick: handleCopy,
936
+ disabled: !hasSteps,
937
+ whileHover: hasSteps ? { scale: 1.02 } : {},
938
+ whileTap: hasSteps ? { scale: 0.98 } : {},
939
+ title: "Copy JSON to clipboard",
940
+ children: [
941
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "11", height: "11", viewBox: "0 0 16 16", fill: "currentColor", children: [
942
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M10 2H4a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zM4 1h6a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H4a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3z" }),
943
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M14 5a1 1 0 0 1 1 1v8a2 2 0 0 1-2 2H6a1 1 0 0 1 0-2h7V6a1 1 0 0 1 1-1z" })
944
+ ] }),
945
+ "Copy",
946
+ copied && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
947
+ import_react3.motion.span,
948
+ {
949
+ style: styles3.copiedBadge,
950
+ initial: { opacity: 0, scale: 0.8, y: 4 },
951
+ animate: { opacity: 1, scale: 1, y: 0 },
952
+ exit: { opacity: 0, scale: 0.8 },
953
+ children: "Copied!"
954
+ }
955
+ )
956
+ ]
957
+ }
958
+ ),
959
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
960
+ import_react3.motion.button,
961
+ {
962
+ type: "button",
963
+ style: resetButtonStyle,
964
+ onClick: onReset,
965
+ disabled: !hasSteps,
966
+ whileHover: hasSteps ? { scale: 1.02 } : {},
967
+ whileTap: hasSteps ? { scale: 0.98 } : {},
968
+ title: "Clear all steps",
969
+ children: [
970
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "11", height: "11", viewBox: "0 0 16 16", fill: "currentColor", children: [
971
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z" }),
972
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
973
+ "path",
974
+ {
975
+ fillRule: "evenodd",
976
+ d: "M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"
977
+ }
978
+ )
979
+ ] }),
980
+ "Reset"
981
+ ]
982
+ }
983
+ )
984
+ ] })
985
+ ] });
986
+ }
987
+
988
+ // src/devtools/components/StepList.tsx
989
+ var import_jsx_runtime4 = require("react/jsx-runtime");
990
+ var styles4 = {
991
+ scrollArea: {
992
+ flex: 1,
993
+ overflowY: "auto",
994
+ overflowX: "hidden",
995
+ padding: 10
996
+ },
997
+ stepList: {
998
+ display: "flex",
999
+ flexDirection: "column",
1000
+ gap: 6
1001
+ },
1002
+ empty: {
1003
+ display: "flex",
1004
+ flexDirection: "column",
1005
+ alignItems: "center",
1006
+ justifyContent: "center",
1007
+ gap: 8,
1008
+ padding: "32px 16px",
1009
+ textAlign: "center",
1010
+ color: "hsl(215 20% 55%)"
1011
+ },
1012
+ emptyIcon: {
1013
+ width: 40,
1014
+ height: 40,
1015
+ borderRadius: 10,
1016
+ backgroundColor: "hsl(215 20% 18%)",
1017
+ display: "flex",
1018
+ alignItems: "center",
1019
+ justifyContent: "center",
1020
+ marginBottom: 4
1021
+ },
1022
+ emptyText: {
1023
+ fontSize: 13,
1024
+ lineHeight: 1.5
1025
+ },
1026
+ kbd: {
1027
+ display: "inline-flex",
1028
+ alignItems: "center",
1029
+ padding: "2px 5px",
1030
+ backgroundColor: "hsl(215 20% 15%)",
1031
+ border: "1px solid hsl(215 20% 22%)",
1032
+ borderRadius: 4,
1033
+ fontSize: 11,
1034
+ fontFamily: "ui-monospace, monospace",
1035
+ color: "hsl(215 20% 55%)"
1036
+ }
1037
+ };
1038
+ function StepList(props) {
1039
+ const {
1040
+ steps,
1041
+ mode,
1042
+ onToggleGrab,
1043
+ onDeleteStep,
1044
+ onReorderSteps,
1045
+ onClearAll,
1046
+ onExport
1047
+ } = props;
1048
+ const [activeId, setActiveId] = (0, import_react4.useState)(null);
1049
+ const activeStep = activeId ? steps.find((s) => s.id === activeId) : null;
1050
+ const activeIndex = activeId ? steps.findIndex((s) => s.id === activeId) : -1;
1051
+ const sensors = (0, import_core.useSensors)(
1052
+ (0, import_core.useSensor)(import_core.PointerSensor, {
1053
+ activationConstraint: {
1054
+ distance: 4
1055
+ }
1056
+ }),
1057
+ (0, import_core.useSensor)(import_core.KeyboardSensor, {
1058
+ coordinateGetter: import_sortable2.sortableKeyboardCoordinates
1059
+ })
1060
+ );
1061
+ const handleDragStart = (0, import_react4.useCallback)((event) => {
1062
+ setActiveId(event.active.id);
1063
+ }, []);
1064
+ const handleDragEnd = (0, import_react4.useCallback)(
1065
+ (event) => {
1066
+ const { active, over } = event;
1067
+ setActiveId(null);
1068
+ if (over && active.id !== over.id) {
1069
+ const oldIndex = steps.findIndex((s) => s.id === active.id);
1070
+ const newIndex = steps.findIndex((s) => s.id === over.id);
1071
+ if (oldIndex !== -1 && newIndex !== -1) {
1072
+ onReorderSteps({ fromIndex: oldIndex, toIndex: newIndex });
1073
+ }
1074
+ }
1075
+ },
1076
+ [steps, onReorderSteps]
1077
+ );
1078
+ const handleDragCancel = (0, import_react4.useCallback)(() => {
1079
+ setActiveId(null);
1080
+ }, []);
1081
+ const handleExportClick = (0, import_react4.useCallback)(() => {
1082
+ const data = onExport();
1083
+ const blob = new Blob([JSON.stringify(data, null, 2)], {
1084
+ type: "application/json"
1085
+ });
1086
+ const url = URL.createObjectURL(blob);
1087
+ const a = document.createElement("a");
1088
+ a.href = url;
1089
+ a.download = `flowsterix-steps-${Date.now()}.json`;
1090
+ a.click();
1091
+ URL.revokeObjectURL(url);
1092
+ }, [onExport]);
1093
+ const handleCopyForAI = (0, import_react4.useCallback)(async () => {
1094
+ const data = onExport();
1095
+ await navigator.clipboard.writeText(JSON.stringify(data, null, 2));
1096
+ }, [onExport]);
1097
+ const handleReset = (0, import_react4.useCallback)(() => {
1098
+ if (confirm("Clear all steps? This cannot be undone.")) {
1099
+ onClearAll();
1100
+ }
1101
+ }, [onClearAll]);
1102
+ if (typeof window === "undefined") return null;
1103
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1104
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1105
+ Toolbar,
1106
+ {
1107
+ mode,
1108
+ stepCount: steps.length,
1109
+ onToggleGrab,
1110
+ onExport: handleExportClick,
1111
+ onCopyForAI: handleCopyForAI,
1112
+ onReset: handleReset
1113
+ }
1114
+ ),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles4.scrollArea, children: steps.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles4.empty, children: [
1116
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles4.emptyIcon, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1117
+ "svg",
1118
+ {
1119
+ width: "20",
1120
+ height: "20",
1121
+ viewBox: "0 0 16 16",
1122
+ fill: "hsl(215 20% 45%)",
1123
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 0a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12zM5.904 10.803L10 6.707v2.768a.5.5 0 0 0 1 0V5.5a.5.5 0 0 0-.5-.5H6.525a.5.5 0 1 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 .707.707z" })
1124
+ }
1125
+ ) }),
1126
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles4.emptyText, children: [
1127
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { children: "No steps captured yet." }),
1128
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { marginTop: 6 }, children: [
1129
+ "Press ",
1130
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: styles4.kbd, children: "Ctrl+Shift+G" }),
1131
+ " to grab"
1132
+ ] })
1133
+ ] })
1134
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1135
+ import_core.DndContext,
1136
+ {
1137
+ sensors,
1138
+ collisionDetection: import_core.closestCenter,
1139
+ onDragStart: handleDragStart,
1140
+ onDragEnd: handleDragEnd,
1141
+ onDragCancel: handleDragCancel,
1142
+ children: [
1143
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1144
+ import_sortable2.SortableContext,
1145
+ {
1146
+ items: steps.map((s) => s.id),
1147
+ strategy: import_sortable2.verticalListSortingStrategy,
1148
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles4.stepList, children: steps.map((step, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1149
+ SortableStepItem,
1150
+ {
1151
+ step,
1152
+ index,
1153
+ onDelete: () => onDeleteStep({ id: step.id }),
1154
+ isDragActive: activeId !== null,
1155
+ isBeingDragged: step.id === activeId
1156
+ },
1157
+ step.id
1158
+ )) })
1159
+ }
1160
+ ),
1161
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core.DragOverlay, { dropAnimation: null, children: activeStep && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(StepItemDragPreview, { step: activeStep, index: activeIndex }) })
1162
+ ]
1163
+ }
1164
+ ) })
1165
+ ] });
1166
+ }
1167
+
1168
+ // src/devtools/components/TabNav.tsx
1169
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1170
+ var styles5 = {
1171
+ container: {
1172
+ display: "flex",
1173
+ gap: 2,
1174
+ padding: "8px 10px 0",
1175
+ borderBottom: "1px solid hsl(215 20% 20%)"
1176
+ },
1177
+ tab: {
1178
+ flex: 1,
1179
+ display: "flex",
1180
+ alignItems: "center",
1181
+ justifyContent: "center",
1182
+ gap: 6,
1183
+ padding: "8px 12px",
1184
+ backgroundColor: "transparent",
1185
+ border: "none",
1186
+ borderBottom: "2px solid transparent",
1187
+ color: "hsl(215 20% 55%)",
1188
+ fontSize: 12,
1189
+ fontWeight: 500,
1190
+ fontFamily: "inherit",
1191
+ cursor: "pointer",
1192
+ transition: "all 0.15s ease",
1193
+ outline: "none",
1194
+ marginBottom: -1
1195
+ },
1196
+ tabActive: {
1197
+ color: "hsl(217 91% 70%)",
1198
+ borderBottomColor: "hsl(217 91% 60%)"
1199
+ },
1200
+ badge: {
1201
+ display: "inline-flex",
1202
+ alignItems: "center",
1203
+ justifyContent: "center",
1204
+ minWidth: 18,
1205
+ height: 18,
1206
+ padding: "0 5px",
1207
+ backgroundColor: "hsl(215 20% 22%)",
1208
+ color: "hsl(215 20% 60%)",
1209
+ fontSize: 10,
1210
+ fontWeight: 600,
1211
+ borderRadius: 9
1212
+ },
1213
+ badgeActive: {
1214
+ backgroundColor: "hsl(217 91% 55% / 0.2)",
1215
+ color: "hsl(217 91% 70%)"
1216
+ }
1217
+ };
1218
+ function TabNav(props) {
1219
+ const { activeTab, onTabChange, stepCount, flowCount } = props;
1220
+ const stepsTabStyle = {
1221
+ ...styles5.tab,
1222
+ ...activeTab === "steps" && styles5.tabActive
1223
+ };
1224
+ const flowsTabStyle = {
1225
+ ...styles5.tab,
1226
+ ...activeTab === "flows" && styles5.tabActive
1227
+ };
1228
+ const stepsBadgeStyle = {
1229
+ ...styles5.badge,
1230
+ ...activeTab === "steps" && styles5.badgeActive
1231
+ };
1232
+ const flowsBadgeStyle = {
1233
+ ...styles5.badge,
1234
+ ...activeTab === "flows" && styles5.badgeActive
1235
+ };
1236
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles5.container, children: [
1237
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1238
+ "button",
1239
+ {
1240
+ type: "button",
1241
+ style: stepsTabStyle,
1242
+ onClick: () => onTabChange("steps"),
1243
+ children: [
1244
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M14 0a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h12zM5.904 10.803L10 6.707v2.768a.5.5 0 0 0 1 0V5.5a.5.5 0 0 0-.5-.5H6.525a.5.5 0 1 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 .707.707z" }) }),
1245
+ "Steps",
1246
+ stepCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: stepsBadgeStyle, children: stepCount })
1247
+ ]
1248
+ }
1249
+ ),
1250
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1251
+ "button",
1252
+ {
1253
+ type: "button",
1254
+ style: flowsTabStyle,
1255
+ onClick: () => onTabChange("flows"),
1256
+ children: [
1257
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zm-3 8A1.5 1.5 0 0 1 4.5 10h1A1.5 1.5 0 0 1 7 11.5v1A1.5 1.5 0 0 1 5.5 14h-1A1.5 1.5 0 0 1 3 12.5v-1zm6 0a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1A1.5 1.5 0 0 1 9 12.5v-1z" }) }),
1258
+ "Flows",
1259
+ flowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: flowsBadgeStyle, children: flowCount })
1260
+ ]
1261
+ }
1262
+ )
1263
+ ] });
1264
+ }
1265
+
1266
+ // src/devtools/components/FlowsTab.tsx
1267
+ var import_react11 = require("react");
1268
+ var import_react12 = require("motion/react");
1269
+
1270
+ // src/devtools/hooks/useFlowsData.ts
1271
+ var import_react6 = require("react");
1272
+
1273
+ // src/devtools/DevToolsContext.tsx
1274
+ var import_react5 = require("react");
1275
+ var DevToolsContext = (0, import_react5.createContext)(null);
1276
+ function useDevToolsContext() {
1277
+ return (0, import_react5.useContext)(DevToolsContext);
1278
+ }
1279
+ function useDevToolsContextRequired() {
1280
+ const context = (0, import_react5.useContext)(DevToolsContext);
1281
+ if (!context) {
1282
+ throw new Error(
1283
+ "useDevToolsContext must be used within a TourProvider with devtools enabled"
1284
+ );
1285
+ }
1286
+ return context;
1287
+ }
1288
+
1289
+ // src/devtools/hooks/useFlowsData.ts
1290
+ function useFlowsData() {
1291
+ const devtools = useDevToolsContext();
1292
+ const [flowsData, setFlowsData] = (0, import_react6.useState)([]);
1293
+ const loadFlowStates = (0, import_react6.useCallback)(async () => {
1294
+ if (!devtools) {
1295
+ setFlowsData([]);
1296
+ return;
1297
+ }
1298
+ const { flows, activeFlowId, state: activeState, getFlowState } = devtools;
1299
+ const flowDataPromises = [];
1300
+ for (const [flowId, definition] of flows) {
1301
+ const isActive = flowId === activeFlowId;
1302
+ flowDataPromises.push(
1303
+ (async () => {
1304
+ const flowState = isActive ? activeState : await getFlowState(flowId);
1305
+ return {
1306
+ flowId,
1307
+ definition,
1308
+ state: flowState,
1309
+ isActive
1310
+ };
1311
+ })()
1312
+ );
1313
+ }
1314
+ const results = await Promise.all(flowDataPromises);
1315
+ setFlowsData(results);
1316
+ }, [devtools]);
1317
+ (0, import_react6.useEffect)(() => {
1318
+ void loadFlowStates();
1319
+ }, [loadFlowStates]);
1320
+ (0, import_react6.useEffect)(() => {
1321
+ if (!devtools?.activeFlowId || !devtools?.state) return;
1322
+ void loadFlowStates();
1323
+ }, [devtools?.activeFlowId, devtools?.state, loadFlowStates]);
1324
+ const deleteFlow = (0, import_react6.useCallback)(
1325
+ async (flowId) => {
1326
+ if (!devtools) return;
1327
+ devtools.cancelFlow(flowId);
1328
+ await devtools.deleteFlowStorage(flowId);
1329
+ await loadFlowStates();
1330
+ },
1331
+ [devtools, loadFlowStates]
1332
+ );
1333
+ const updateFlow = (0, import_react6.useCallback)(
1334
+ async (flowId, state) => {
1335
+ if (!devtools) return;
1336
+ await devtools.updateFlowStorage(flowId, state);
1337
+ await loadFlowStates();
1338
+ },
1339
+ [devtools, loadFlowStates]
1340
+ );
1341
+ return {
1342
+ flows: flowsData,
1343
+ refreshFlows: loadFlowStates,
1344
+ deleteFlow,
1345
+ updateFlow
1346
+ };
1347
+ }
1348
+
1349
+ // src/devtools/components/FlowItem.tsx
1350
+ var import_react7 = require("react");
1351
+ var import_react8 = require("motion/react");
1352
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1353
+ var styles6 = {
1354
+ card: {
1355
+ display: "flex",
1356
+ flexDirection: "column",
1357
+ gap: 8,
1358
+ padding: 12,
1359
+ backgroundColor: "hsl(215 20% 16%)",
1360
+ borderRadius: 8,
1361
+ border: "1px solid hsl(215 20% 22%)",
1362
+ fontSize: 12,
1363
+ fontFamily: "inherit"
1364
+ },
1365
+ cardActive: {
1366
+ borderColor: "hsl(217 91% 55% / 0.5)",
1367
+ backgroundColor: "hsl(217 91% 55% / 0.05)"
1368
+ },
1369
+ header: {
1370
+ display: "flex",
1371
+ alignItems: "center",
1372
+ justifyContent: "space-between",
1373
+ gap: 8
1374
+ },
1375
+ titleGroup: {
1376
+ display: "flex",
1377
+ alignItems: "center",
1378
+ gap: 8,
1379
+ minWidth: 0
1380
+ },
1381
+ flowId: {
1382
+ fontWeight: 600,
1383
+ color: "hsl(215 20% 85%)",
1384
+ overflow: "hidden",
1385
+ textOverflow: "ellipsis",
1386
+ whiteSpace: "nowrap"
1387
+ },
1388
+ statusBadge: {
1389
+ display: "inline-flex",
1390
+ alignItems: "center",
1391
+ padding: "2px 6px",
1392
+ fontSize: 10,
1393
+ fontWeight: 500,
1394
+ borderRadius: 4,
1395
+ flexShrink: 0
1396
+ },
1397
+ statusIdle: {
1398
+ backgroundColor: "hsl(215 20% 22%)",
1399
+ color: "hsl(215 20% 60%)"
1400
+ },
1401
+ statusRunning: {
1402
+ backgroundColor: "hsl(142 71% 45% / 0.2)",
1403
+ color: "hsl(142 71% 60%)"
1404
+ },
1405
+ statusPaused: {
1406
+ backgroundColor: "hsl(45 93% 47% / 0.2)",
1407
+ color: "hsl(45 93% 60%)"
1408
+ },
1409
+ statusCompleted: {
1410
+ backgroundColor: "hsl(217 91% 55% / 0.2)",
1411
+ color: "hsl(217 91% 70%)"
1412
+ },
1413
+ statusCancelled: {
1414
+ backgroundColor: "hsl(0 70% 50% / 0.2)",
1415
+ color: "hsl(0 70% 65%)"
1416
+ },
1417
+ activeBadge: {
1418
+ backgroundColor: "hsl(142 71% 45% / 0.2)",
1419
+ color: "hsl(142 71% 60%)"
1420
+ },
1421
+ infoRow: {
1422
+ display: "flex",
1423
+ alignItems: "center",
1424
+ gap: 12,
1425
+ color: "hsl(215 20% 55%)",
1426
+ fontSize: 11
1427
+ },
1428
+ infoItem: {
1429
+ display: "flex",
1430
+ alignItems: "center",
1431
+ gap: 4
1432
+ },
1433
+ label: {
1434
+ color: "hsl(215 20% 45%)"
1435
+ },
1436
+ value: {
1437
+ fontFamily: "ui-monospace, monospace",
1438
+ color: "hsl(215 20% 65%)"
1439
+ },
1440
+ actions: {
1441
+ display: "flex",
1442
+ gap: 6,
1443
+ marginTop: 4
1444
+ },
1445
+ actionButton: {
1446
+ display: "flex",
1447
+ alignItems: "center",
1448
+ justifyContent: "center",
1449
+ gap: 4,
1450
+ padding: "6px 10px",
1451
+ backgroundColor: "transparent",
1452
+ border: "1px solid hsl(215 20% 25%)",
1453
+ borderRadius: 5,
1454
+ color: "hsl(215 20% 60%)",
1455
+ fontSize: 10,
1456
+ fontWeight: 500,
1457
+ fontFamily: "inherit",
1458
+ cursor: "pointer",
1459
+ transition: "all 0.15s ease",
1460
+ outline: "none"
1461
+ },
1462
+ actionButtonDanger: {
1463
+ borderColor: "hsl(0 70% 40%)",
1464
+ color: "hsl(0 70% 60%)"
1465
+ },
1466
+ noState: {
1467
+ padding: "8px 0",
1468
+ color: "hsl(215 20% 45%)",
1469
+ fontSize: 11,
1470
+ fontStyle: "italic"
1471
+ }
1472
+ };
1473
+ var statusStyles = {
1474
+ idle: styles6.statusIdle,
1475
+ running: styles6.statusRunning,
1476
+ paused: styles6.statusPaused,
1477
+ completed: styles6.statusCompleted,
1478
+ cancelled: styles6.statusCancelled
1479
+ };
1480
+ function FlowItem(props) {
1481
+ const { flow, onEdit, onDelete } = props;
1482
+ const { flowId, definition, state, isActive } = flow;
1483
+ const [confirmDelete, setConfirmDelete] = (0, import_react7.useState)(false);
1484
+ const handleDelete = () => {
1485
+ if (confirmDelete) {
1486
+ onDelete();
1487
+ setConfirmDelete(false);
1488
+ } else {
1489
+ setConfirmDelete(true);
1490
+ setTimeout(() => setConfirmDelete(false), 3e3);
1491
+ }
1492
+ };
1493
+ const cardStyle = {
1494
+ ...styles6.card,
1495
+ ...isActive && styles6.cardActive
1496
+ };
1497
+ const statusBadgeStyle = {
1498
+ ...styles6.statusBadge,
1499
+ ...state ? statusStyles[state.status] || styles6.statusIdle : styles6.statusIdle
1500
+ };
1501
+ const deleteButtonStyle = {
1502
+ ...styles6.actionButton,
1503
+ ...confirmDelete && styles6.actionButtonDanger
1504
+ };
1505
+ const stepInfo = state ? `Step ${state.stepIndex + 1}/${definition.steps.length}` : null;
1506
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: cardStyle, children: [
1507
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.header, children: [
1508
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.titleGroup, children: [
1509
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.flowId, children: flowId }),
1510
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { ...styles6.statusBadge, ...styles6.activeBadge }, children: "Active" })
1511
+ ] }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: statusBadgeStyle, children: state?.status ?? "no state" })
1513
+ ] }),
1514
+ state ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.infoRow, children: [
1515
+ stepInfo && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.infoItem, children: [
1516
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.label, children: "Step:" }),
1517
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.value, children: stepInfo })
1518
+ ] }),
1519
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.infoItem, children: [
1520
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.label, children: "Version:" }),
1521
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.value, children: state.version })
1522
+ ] }),
1523
+ state.stepId && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.infoItem, children: [
1524
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.label, children: "ID:" }),
1525
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: styles6.value, children: state.stepId })
1526
+ ] })
1527
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: styles6.noState, children: "No stored state" }),
1528
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: styles6.actions, children: [
1529
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1530
+ import_react8.motion.button,
1531
+ {
1532
+ type: "button",
1533
+ style: styles6.actionButton,
1534
+ onClick: onEdit,
1535
+ disabled: !state,
1536
+ whileHover: state ? { scale: 1.02 } : {},
1537
+ whileTap: state ? { scale: 0.98 } : {},
1538
+ title: state ? "Edit flow state" : "No state to edit",
1539
+ children: [
1540
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5L13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175l-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z" }) }),
1541
+ "Edit"
1542
+ ]
1543
+ }
1544
+ ),
1545
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1546
+ import_react8.motion.button,
1547
+ {
1548
+ type: "button",
1549
+ style: deleteButtonStyle,
1550
+ onClick: handleDelete,
1551
+ disabled: !state,
1552
+ whileHover: state ? { scale: 1.02 } : {},
1553
+ whileTap: state ? { scale: 0.98 } : {},
1554
+ title: confirmDelete ? "Click again to confirm deletion" : state ? "Delete flow state" : "No state to delete",
1555
+ children: [
1556
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: [
1557
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z" }),
1558
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1559
+ "path",
1560
+ {
1561
+ fillRule: "evenodd",
1562
+ d: "M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4L4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"
1563
+ }
1564
+ )
1565
+ ] }),
1566
+ confirmDelete ? "Confirm?" : "Delete"
1567
+ ]
1568
+ }
1569
+ )
1570
+ ] })
1571
+ ] });
1572
+ }
1573
+
1574
+ // src/devtools/components/FlowEditModal.tsx
1575
+ var import_react9 = require("react");
1576
+ var import_react_dom2 = require("react-dom");
1577
+ var import_react10 = require("motion/react");
1578
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1579
+ var styles7 = {
1580
+ overlay: {
1581
+ position: "fixed",
1582
+ inset: 0,
1583
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
1584
+ display: "flex",
1585
+ alignItems: "center",
1586
+ justifyContent: "center",
1587
+ zIndex: 1e5,
1588
+ padding: 20
1589
+ },
1590
+ modal: {
1591
+ width: "100%",
1592
+ maxWidth: 500,
1593
+ maxHeight: "calc(100vh - 40px)",
1594
+ backgroundColor: "hsl(222 47% 11%)",
1595
+ borderRadius: 12,
1596
+ border: "1px solid hsl(215 20% 25%)",
1597
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)",
1598
+ display: "flex",
1599
+ flexDirection: "column",
1600
+ overflow: "hidden",
1601
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"
1602
+ },
1603
+ header: {
1604
+ display: "flex",
1605
+ alignItems: "center",
1606
+ justifyContent: "space-between",
1607
+ padding: "14px 16px",
1608
+ borderBottom: "1px solid hsl(215 20% 20%)"
1609
+ },
1610
+ title: {
1611
+ fontSize: 14,
1612
+ fontWeight: 600,
1613
+ color: "hsl(215 20% 85%)"
1614
+ },
1615
+ closeButton: {
1616
+ display: "flex",
1617
+ alignItems: "center",
1618
+ justifyContent: "center",
1619
+ width: 28,
1620
+ height: 28,
1621
+ backgroundColor: "transparent",
1622
+ border: "none",
1623
+ color: "hsl(215 20% 55%)",
1624
+ cursor: "pointer",
1625
+ borderRadius: 6,
1626
+ transition: "all 0.15s ease",
1627
+ outline: "none"
1628
+ },
1629
+ body: {
1630
+ flex: 1,
1631
+ padding: 16,
1632
+ overflowY: "auto"
1633
+ },
1634
+ textarea: {
1635
+ width: "100%",
1636
+ minHeight: 300,
1637
+ padding: 12,
1638
+ backgroundColor: "hsl(215 20% 8%)",
1639
+ border: "1px solid hsl(215 20% 20%)",
1640
+ borderRadius: 8,
1641
+ color: "hsl(215 20% 85%)",
1642
+ fontSize: 12,
1643
+ fontFamily: "ui-monospace, monospace",
1644
+ resize: "vertical",
1645
+ outline: "none",
1646
+ lineHeight: 1.5
1647
+ },
1648
+ textareaError: {
1649
+ borderColor: "hsl(0 70% 50%)"
1650
+ },
1651
+ error: {
1652
+ marginTop: 8,
1653
+ padding: "8px 10px",
1654
+ backgroundColor: "hsl(0 70% 50% / 0.15)",
1655
+ border: "1px solid hsl(0 70% 50% / 0.3)",
1656
+ borderRadius: 6,
1657
+ color: "hsl(0 70% 70%)",
1658
+ fontSize: 11,
1659
+ fontFamily: "ui-monospace, monospace"
1660
+ },
1661
+ footer: {
1662
+ display: "flex",
1663
+ alignItems: "center",
1664
+ justifyContent: "flex-end",
1665
+ gap: 8,
1666
+ padding: "12px 16px",
1667
+ borderTop: "1px solid hsl(215 20% 20%)"
1668
+ },
1669
+ button: {
1670
+ display: "flex",
1671
+ alignItems: "center",
1672
+ justifyContent: "center",
1673
+ gap: 6,
1674
+ padding: "8px 16px",
1675
+ backgroundColor: "hsl(215 20% 20%)",
1676
+ border: "1px solid hsl(215 20% 28%)",
1677
+ borderRadius: 6,
1678
+ color: "hsl(215 20% 75%)",
1679
+ fontSize: 12,
1680
+ fontWeight: 500,
1681
+ fontFamily: "inherit",
1682
+ cursor: "pointer",
1683
+ transition: "all 0.15s ease",
1684
+ outline: "none"
1685
+ },
1686
+ buttonPrimary: {
1687
+ backgroundColor: "hsl(217 91% 55%)",
1688
+ borderColor: "hsl(217 91% 60%)",
1689
+ color: "white"
1690
+ },
1691
+ buttonDisabled: {
1692
+ opacity: 0.5,
1693
+ cursor: "not-allowed"
1694
+ }
1695
+ };
1696
+ function FlowEditModal(props) {
1697
+ const { isOpen, flowId, initialState, onClose, onSave, container } = props;
1698
+ const [jsonValue, setJsonValue] = (0, import_react9.useState)("");
1699
+ const [error, setError] = (0, import_react9.useState)(null);
1700
+ (0, import_react9.useEffect)(() => {
1701
+ if (isOpen && initialState) {
1702
+ setJsonValue(JSON.stringify(initialState, null, 2));
1703
+ setError(null);
1704
+ }
1705
+ }, [isOpen, initialState]);
1706
+ const handleSave = (0, import_react9.useCallback)(() => {
1707
+ try {
1708
+ const parsed = JSON.parse(jsonValue);
1709
+ if (typeof parsed.status !== "string") {
1710
+ throw new Error('Missing or invalid "status" field');
1711
+ }
1712
+ if (typeof parsed.stepIndex !== "number") {
1713
+ throw new Error('Missing or invalid "stepIndex" field');
1714
+ }
1715
+ if (typeof parsed.version !== "string") {
1716
+ throw new Error('Missing or invalid "version" field');
1717
+ }
1718
+ onSave(parsed);
1719
+ onClose();
1720
+ } catch (err) {
1721
+ setError(err instanceof Error ? err.message : "Invalid JSON");
1722
+ }
1723
+ }, [jsonValue, onSave, onClose]);
1724
+ const handleKeyDown = (0, import_react9.useCallback)(
1725
+ (e) => {
1726
+ if (e.key === "Escape") {
1727
+ onClose();
1728
+ }
1729
+ if (e.key === "s" && (e.metaKey || e.ctrlKey)) {
1730
+ e.preventDefault();
1731
+ handleSave();
1732
+ }
1733
+ },
1734
+ [onClose, handleSave]
1735
+ );
1736
+ if (typeof window === "undefined") return null;
1737
+ const portalContainer = container ?? document.body;
1738
+ const textareaStyle = {
1739
+ ...styles7.textarea,
1740
+ ...error && styles7.textareaError
1741
+ };
1742
+ const saveButtonStyle = {
1743
+ ...styles7.button,
1744
+ ...styles7.buttonPrimary,
1745
+ ...error && styles7.buttonDisabled
1746
+ };
1747
+ return (0, import_react_dom2.createPortal)(
1748
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react10.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1749
+ import_react10.motion.div,
1750
+ {
1751
+ style: styles7.overlay,
1752
+ initial: { opacity: 0 },
1753
+ animate: { opacity: 1 },
1754
+ exit: { opacity: 0 },
1755
+ transition: { duration: 0.15 },
1756
+ onClick: (e) => {
1757
+ if (e.target === e.currentTarget) onClose();
1758
+ },
1759
+ onKeyDown: handleKeyDown,
1760
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1761
+ import_react10.motion.div,
1762
+ {
1763
+ style: styles7.modal,
1764
+ initial: { opacity: 0, scale: 0.95, y: 10 },
1765
+ animate: { opacity: 1, scale: 1, y: 0 },
1766
+ exit: { opacity: 0, scale: 0.95, y: 10 },
1767
+ transition: { duration: 0.15, ease: [0.16, 1, 0.3, 1] },
1768
+ onClick: (e) => e.stopPropagation(),
1769
+ children: [
1770
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles7.header, children: [
1771
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: styles7.title, children: [
1772
+ "Edit Flow: ",
1773
+ flowId
1774
+ ] }),
1775
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1776
+ "button",
1777
+ {
1778
+ type: "button",
1779
+ style: styles7.closeButton,
1780
+ onClick: onClose,
1781
+ title: "Close",
1782
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" }) })
1783
+ }
1784
+ )
1785
+ ] }),
1786
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles7.body, children: [
1787
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1788
+ "textarea",
1789
+ {
1790
+ style: textareaStyle,
1791
+ value: jsonValue,
1792
+ onChange: (e) => {
1793
+ setJsonValue(e.target.value);
1794
+ setError(null);
1795
+ },
1796
+ spellCheck: false,
1797
+ autoFocus: true
1798
+ }
1799
+ ),
1800
+ error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles7.error, children: error })
1801
+ ] }),
1802
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles7.footer, children: [
1803
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1804
+ "button",
1805
+ {
1806
+ type: "button",
1807
+ style: styles7.button,
1808
+ onClick: onClose,
1809
+ children: "Cancel"
1810
+ }
1811
+ ),
1812
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1813
+ import_react10.motion.button,
1814
+ {
1815
+ type: "button",
1816
+ style: saveButtonStyle,
1817
+ onClick: handleSave,
1818
+ disabled: !!error,
1819
+ whileHover: !error ? { scale: 1.02 } : {},
1820
+ whileTap: !error ? { scale: 0.98 } : {},
1821
+ children: "Save"
1822
+ }
1823
+ )
1824
+ ] })
1825
+ ]
1826
+ }
1827
+ )
1828
+ }
1829
+ ) }),
1830
+ portalContainer
1831
+ );
1832
+ }
1833
+
1834
+ // src/devtools/components/FlowsTab.tsx
1835
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1836
+ var styles8 = {
1837
+ container: {
1838
+ display: "flex",
1839
+ flexDirection: "column",
1840
+ gap: 10,
1841
+ padding: 10,
1842
+ flex: 1,
1843
+ overflowY: "auto"
1844
+ },
1845
+ toolbar: {
1846
+ display: "flex",
1847
+ alignItems: "center",
1848
+ justifyContent: "space-between",
1849
+ gap: 8,
1850
+ marginBottom: 4
1851
+ },
1852
+ refreshButton: {
1853
+ display: "flex",
1854
+ alignItems: "center",
1855
+ justifyContent: "center",
1856
+ gap: 6,
1857
+ padding: "6px 10px",
1858
+ backgroundColor: "transparent",
1859
+ border: "1px solid hsl(215 20% 25%)",
1860
+ borderRadius: 5,
1861
+ color: "hsl(215 20% 60%)",
1862
+ fontSize: 11,
1863
+ fontWeight: 500,
1864
+ fontFamily: "inherit",
1865
+ cursor: "pointer",
1866
+ transition: "all 0.15s ease",
1867
+ outline: "none"
1868
+ },
1869
+ flowList: {
1870
+ display: "flex",
1871
+ flexDirection: "column",
1872
+ gap: 8
1873
+ },
1874
+ empty: {
1875
+ display: "flex",
1876
+ flexDirection: "column",
1877
+ alignItems: "center",
1878
+ justifyContent: "center",
1879
+ gap: 8,
1880
+ padding: "32px 16px",
1881
+ textAlign: "center",
1882
+ color: "hsl(215 20% 55%)"
1883
+ },
1884
+ emptyIcon: {
1885
+ width: 40,
1886
+ height: 40,
1887
+ borderRadius: 10,
1888
+ backgroundColor: "hsl(215 20% 18%)",
1889
+ display: "flex",
1890
+ alignItems: "center",
1891
+ justifyContent: "center",
1892
+ marginBottom: 4
1893
+ },
1894
+ emptyText: {
1895
+ fontSize: 13,
1896
+ lineHeight: 1.5
1897
+ },
1898
+ noContext: {
1899
+ padding: "20px 16px",
1900
+ textAlign: "center",
1901
+ color: "hsl(215 20% 50%)",
1902
+ fontSize: 12
1903
+ }
1904
+ };
1905
+ function FlowsTab(props) {
1906
+ const { container } = props;
1907
+ const { flows, refreshFlows, deleteFlow, updateFlow } = useFlowsData();
1908
+ const [editModal, setEditModal] = (0, import_react11.useState)({
1909
+ isOpen: false,
1910
+ flowId: "",
1911
+ state: null
1912
+ });
1913
+ const handleEdit = (0, import_react11.useCallback)((flowId, state) => {
1914
+ if (!state) return;
1915
+ setEditModal({
1916
+ isOpen: true,
1917
+ flowId,
1918
+ state
1919
+ });
1920
+ }, []);
1921
+ const handleCloseModal = (0, import_react11.useCallback)(() => {
1922
+ setEditModal((prev) => ({ ...prev, isOpen: false }));
1923
+ }, []);
1924
+ const handleSave = (0, import_react11.useCallback)(
1925
+ async (newState) => {
1926
+ await updateFlow(editModal.flowId, newState);
1927
+ },
1928
+ [editModal.flowId, updateFlow]
1929
+ );
1930
+ const handleDelete = (0, import_react11.useCallback)(
1931
+ async (flowId) => {
1932
+ await deleteFlow(flowId);
1933
+ },
1934
+ [deleteFlow]
1935
+ );
1936
+ if (flows.length === 0) {
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles8.container, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles8.empty, children: [
1938
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles8.emptyIcon, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1939
+ "svg",
1940
+ {
1941
+ width: "20",
1942
+ height: "20",
1943
+ viewBox: "0 0 16 16",
1944
+ fill: "hsl(215 20% 45%)",
1945
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zm-3 8A1.5 1.5 0 0 1 4.5 10h1A1.5 1.5 0 0 1 7 11.5v1A1.5 1.5 0 0 1 5.5 14h-1A1.5 1.5 0 0 1 3 12.5v-1zm6 0a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1A1.5 1.5 0 0 1 9 12.5v-1z" })
1946
+ }
1947
+ ) }),
1948
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles8.emptyText, children: [
1949
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { children: "No flows registered." }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { marginTop: 6, fontSize: 11, color: "hsl(215 20% 45%)" }, children: "Add flows to TourProvider to see them here." })
1951
+ ] })
1952
+ ] }) });
1953
+ }
1954
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles8.container, children: [
1955
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles8.toolbar, children: [
1956
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: { fontSize: 11, color: "hsl(215 20% 50%)" }, children: [
1957
+ flows.length,
1958
+ " flow",
1959
+ flows.length !== 1 ? "s" : "",
1960
+ " registered"
1961
+ ] }),
1962
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1963
+ import_react12.motion.button,
1964
+ {
1965
+ type: "button",
1966
+ style: styles8.refreshButton,
1967
+ onClick: () => void refreshFlows(),
1968
+ whileHover: { scale: 1.02 },
1969
+ whileTap: { scale: 0.98 },
1970
+ title: "Refresh flow states",
1971
+ children: [
1972
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1974
+ "path",
1975
+ {
1976
+ fillRule: "evenodd",
1977
+ d: "M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"
1978
+ }
1979
+ ),
1980
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" })
1981
+ ] }),
1982
+ "Refresh"
1983
+ ]
1984
+ }
1985
+ )
1986
+ ] }),
1987
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles8.flowList, children: flows.map((flow) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1988
+ FlowItem,
1989
+ {
1990
+ flow,
1991
+ onEdit: () => handleEdit(flow.flowId, flow.state),
1992
+ onDelete: () => void handleDelete(flow.flowId)
1993
+ },
1994
+ flow.flowId
1995
+ )) }),
1996
+ editModal.state && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1997
+ FlowEditModal,
1998
+ {
1999
+ isOpen: editModal.isOpen,
2000
+ flowId: editModal.flowId,
2001
+ initialState: editModal.state,
2002
+ onClose: handleCloseModal,
2003
+ onSave: handleSave,
2004
+ container
2005
+ }
2006
+ )
2007
+ ] });
2008
+ }
2009
+
2010
+ // src/devtools/hooks/useGrabMode.ts
2011
+ var import_react14 = require("react");
2012
+
2013
+ // src/devtools/hooks/useElementInfo.ts
2014
+ var import_react13 = require("react");
2015
+
2016
+ // src/devtools/utils/selectorGenerator.ts
2017
+ function generateSemanticName(element) {
2018
+ const tag = element.tagName.toLowerCase();
2019
+ const text = element.textContent?.trim().slice(0, 20).toLowerCase() || "";
2020
+ const className = element.className;
2021
+ const id = element.id;
2022
+ if (text) {
2023
+ const words = text.replace(/[^a-z0-9\s]/gi, "").split(/\s+/).filter(Boolean).slice(0, 3);
2024
+ if (words.length > 0) {
2025
+ return `${tag}-${words.join("-")}`;
2026
+ }
2027
+ }
2028
+ if (id) {
2029
+ return id;
2030
+ }
2031
+ if (typeof className === "string" && className) {
2032
+ const firstClass = className.split(/\s+/)[0];
2033
+ if (firstClass && !firstClass.startsWith("_") && firstClass.length < 30) {
2034
+ return `${tag}-${firstClass}`;
2035
+ }
2036
+ }
2037
+ return `${tag}-${Math.random().toString(36).slice(2, 6)}`;
2038
+ }
2039
+ function getExistingDataAttrs(element) {
2040
+ const attrs = [];
2041
+ for (const attr of element.attributes) {
2042
+ if (attr.name.startsWith("data-")) {
2043
+ attrs.push(attr.name);
2044
+ }
2045
+ }
2046
+ return attrs;
2047
+ }
2048
+ function isUnique(params) {
2049
+ try {
2050
+ return document.querySelectorAll(params.selector).length === 1;
2051
+ } catch {
2052
+ return false;
2053
+ }
2054
+ }
2055
+ function generateSelector(params) {
2056
+ const { element } = params;
2057
+ const existingAttrs = getExistingDataAttrs(element);
2058
+ const tourTarget = element.getAttribute("data-tour-target");
2059
+ if (tourTarget) {
2060
+ return {
2061
+ selector: `[data-tour-target="${tourTarget}"]`,
2062
+ selectorType: "data-attr",
2063
+ suggestedAttrName: tourTarget,
2064
+ existingAttrs
2065
+ };
2066
+ }
2067
+ if (element.id && isUnique({ selector: `#${CSS.escape(element.id)}` })) {
2068
+ return {
2069
+ selector: `#${CSS.escape(element.id)}`,
2070
+ selectorType: "auto",
2071
+ suggestedAttrName: element.id,
2072
+ existingAttrs
2073
+ };
2074
+ }
2075
+ const testId = element.getAttribute("data-testid");
2076
+ if (testId && isUnique({ selector: `[data-testid="${testId}"]` })) {
2077
+ return {
2078
+ selector: `[data-testid="${testId}"]`,
2079
+ selectorType: "data-attr",
2080
+ suggestedAttrName: testId,
2081
+ existingAttrs
2082
+ };
2083
+ }
2084
+ for (const attr of existingAttrs) {
2085
+ if (attr === "data-tour-target" || attr === "data-testid") continue;
2086
+ const value = element.getAttribute(attr);
2087
+ if (value) {
2088
+ const selector = `[${attr}="${value}"]`;
2089
+ if (isUnique({ selector })) {
2090
+ return {
2091
+ selector,
2092
+ selectorType: "data-attr",
2093
+ suggestedAttrName: value,
2094
+ existingAttrs
2095
+ };
2096
+ }
2097
+ }
2098
+ }
2099
+ const suggestedName = generateSemanticName(element);
2100
+ return {
2101
+ selector: `[data-tour-target="${suggestedName}"]`,
2102
+ selectorType: "auto",
2103
+ suggestedAttrName: suggestedName,
2104
+ existingAttrs
2105
+ };
2106
+ }
2107
+
2108
+ // src/devtools/hooks/useElementInfo.ts
2109
+ function useElementInfo() {
2110
+ const getElementInfo = (0, import_react13.useCallback)((params) => {
2111
+ const { element } = params;
2112
+ const selectorResult = generateSelector({ element });
2113
+ const source = extractSource({ element });
2114
+ const componentHierarchy = extractComponentHierarchy({ element });
2115
+ const rect = element.getBoundingClientRect();
2116
+ const htmlElement = element;
2117
+ const styleAttr = htmlElement.getAttribute?.("style") || void 0;
2118
+ return {
2119
+ element,
2120
+ selector: selectorResult.selector,
2121
+ selectorType: selectorResult.selectorType,
2122
+ suggestedAttrName: selectorResult.suggestedAttrName,
2123
+ tag: element.tagName.toLowerCase(),
2124
+ text: element.textContent?.trim().slice(0, 50) || void 0,
2125
+ className: typeof element.className === "string" ? element.className : void 0,
2126
+ style: styleAttr,
2127
+ existingAttrs: selectorResult.existingAttrs,
2128
+ componentHierarchy,
2129
+ rect,
2130
+ source: source ?? void 0
2131
+ };
2132
+ }, []);
2133
+ return { getElementInfo };
2134
+ }
2135
+
2136
+ // src/devtools/hooks/useGrabMode.ts
2137
+ function isDevToolsElement(element) {
2138
+ if (element.closest("[data-devtools-panel]")) return true;
2139
+ if (element.closest("[data-devtools-host]")) return true;
2140
+ const root = element.getRootNode();
2141
+ if (root instanceof ShadowRoot) {
2142
+ const host = root.host;
2143
+ if (host?.hasAttribute("data-devtools-host")) return true;
2144
+ }
2145
+ return false;
2146
+ }
2147
+ function useGrabMode() {
2148
+ const [mode, setMode] = (0, import_react14.useState)("idle");
2149
+ const [hoveredElement, setHoveredElement] = (0, import_react14.useState)(null);
2150
+ const { getElementInfo } = useElementInfo();
2151
+ const startGrabbing = (0, import_react14.useCallback)(() => {
2152
+ setMode("grabbing");
2153
+ setHoveredElement(null);
2154
+ }, []);
2155
+ const stopGrabbing = (0, import_react14.useCallback)(() => {
2156
+ setMode("idle");
2157
+ setHoveredElement(null);
2158
+ }, []);
2159
+ const toggleGrabbing = (0, import_react14.useCallback)(() => {
2160
+ setMode((prev) => prev === "grabbing" ? "idle" : "grabbing");
2161
+ setHoveredElement(null);
2162
+ }, []);
2163
+ const selectCurrent = (0, import_react14.useCallback)(() => {
2164
+ if (!hoveredElement) return null;
2165
+ return hoveredElement.info;
2166
+ }, [hoveredElement]);
2167
+ (0, import_react14.useEffect)(() => {
2168
+ if (mode !== "grabbing") return;
2169
+ const handleMouseMove = (e) => {
2170
+ const target = document.elementFromPoint(e.clientX, e.clientY);
2171
+ if (!target) {
2172
+ setHoveredElement(null);
2173
+ return;
2174
+ }
2175
+ if (isDevToolsElement(target)) {
2176
+ setHoveredElement(null);
2177
+ return;
2178
+ }
2179
+ if (target.tagName === "HTML" || target.tagName === "BODY") {
2180
+ setHoveredElement(null);
2181
+ return;
2182
+ }
2183
+ setHoveredElement({
2184
+ element: target,
2185
+ info: getElementInfo({ element: target })
2186
+ });
2187
+ };
2188
+ document.addEventListener("mousemove", handleMouseMove, { passive: true });
2189
+ return () => document.removeEventListener("mousemove", handleMouseMove);
2190
+ }, [mode, getElementInfo]);
2191
+ (0, import_react14.useEffect)(() => {
2192
+ const handleKeyDown = (e) => {
2193
+ if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "g") {
2194
+ e.preventDefault();
2195
+ toggleGrabbing();
2196
+ return;
2197
+ }
2198
+ if (mode !== "grabbing") return;
2199
+ if (e.key === "Escape") {
2200
+ e.preventDefault();
2201
+ stopGrabbing();
2202
+ }
2203
+ };
2204
+ document.addEventListener("keydown", handleKeyDown);
2205
+ return () => document.removeEventListener("keydown", handleKeyDown);
2206
+ }, [mode, toggleGrabbing, stopGrabbing]);
2207
+ return {
2208
+ mode,
2209
+ hoveredElement,
2210
+ startGrabbing,
2211
+ stopGrabbing,
2212
+ toggleGrabbing,
2213
+ selectCurrent
2214
+ };
2215
+ }
2216
+
2217
+ // src/devtools/hooks/useStepStore.ts
2218
+ var import_react15 = require("react");
2219
+
2220
+ // src/devtools/utils/storage.ts
2221
+ var STORAGE_KEY = "flowsterix-devtools-steps";
2222
+ function migrateStep(step) {
2223
+ return {
2224
+ ...step,
2225
+ componentHierarchy: step.componentHierarchy ?? [],
2226
+ existingAttrs: step.existingAttrs ?? []
2227
+ };
2228
+ }
2229
+ function loadSteps() {
2230
+ if (typeof window === "undefined") return [];
2231
+ try {
2232
+ const data = localStorage.getItem(STORAGE_KEY);
2233
+ if (!data) return [];
2234
+ const parsed = JSON.parse(data);
2235
+ if (!Array.isArray(parsed)) return [];
2236
+ return parsed.map(migrateStep);
2237
+ } catch {
2238
+ return [];
2239
+ }
2240
+ }
2241
+ function saveSteps(steps) {
2242
+ if (typeof window === "undefined") return;
2243
+ try {
2244
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(steps));
2245
+ } catch {
2246
+ }
2247
+ }
2248
+ function clearSteps() {
2249
+ if (typeof window === "undefined") return;
2250
+ try {
2251
+ localStorage.removeItem(STORAGE_KEY);
2252
+ } catch {
2253
+ }
2254
+ }
2255
+
2256
+ // src/devtools/hooks/useStepStore.ts
2257
+ var store = {
2258
+ steps: [],
2259
+ listeners: /* @__PURE__ */ new Set()
2260
+ };
2261
+ function notifyListeners() {
2262
+ for (const listener of store.listeners) {
2263
+ listener();
2264
+ }
2265
+ }
2266
+ function subscribe(listener) {
2267
+ store.listeners.add(listener);
2268
+ return () => store.listeners.delete(listener);
2269
+ }
2270
+ function getSnapshot() {
2271
+ return store.steps;
2272
+ }
2273
+ function getServerSnapshot() {
2274
+ return [];
2275
+ }
2276
+ function generateId() {
2277
+ return `step-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
2278
+ }
2279
+ function useStepStore() {
2280
+ const steps = (0, import_react15.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
2281
+ (0, import_react15.useEffect)(() => {
2282
+ const saved = loadSteps();
2283
+ if (saved.length > 0) {
2284
+ store.steps = saved;
2285
+ notifyListeners();
2286
+ }
2287
+ }, []);
2288
+ (0, import_react15.useEffect)(() => {
2289
+ saveSteps(steps);
2290
+ }, [steps]);
2291
+ const addStep = (0, import_react15.useCallback)((params) => {
2292
+ const { info } = params;
2293
+ const newStep = {
2294
+ id: generateId(),
2295
+ order: store.steps.length,
2296
+ selector: info.selector,
2297
+ selectorType: info.selectorType,
2298
+ elementTag: info.tag,
2299
+ elementText: info.text,
2300
+ elementClassName: info.className,
2301
+ elementStyle: info.style,
2302
+ existingAttrs: info.existingAttrs,
2303
+ suggestedAttrName: info.suggestedAttrName,
2304
+ componentHierarchy: info.componentHierarchy,
2305
+ rect: {
2306
+ top: info.rect.top,
2307
+ left: info.rect.left,
2308
+ width: info.rect.width,
2309
+ height: info.rect.height
2310
+ },
2311
+ source: info.source,
2312
+ createdAt: Date.now()
2313
+ };
2314
+ store.steps = [...store.steps, newStep];
2315
+ notifyListeners();
2316
+ return newStep;
2317
+ }, []);
2318
+ const removeStep = (0, import_react15.useCallback)((params) => {
2319
+ const { id } = params;
2320
+ store.steps = store.steps.filter((s) => s.id !== id).map((s, i) => ({ ...s, order: i }));
2321
+ notifyListeners();
2322
+ }, []);
2323
+ const updateStep = (0, import_react15.useCallback)(
2324
+ (params) => {
2325
+ const { id, updates } = params;
2326
+ store.steps = store.steps.map(
2327
+ (s) => s.id === id ? { ...s, ...updates } : s
2328
+ );
2329
+ notifyListeners();
2330
+ },
2331
+ []
2332
+ );
2333
+ const reorderSteps = (0, import_react15.useCallback)(
2334
+ (params) => {
2335
+ const { fromIndex, toIndex } = params;
2336
+ const newSteps = [...store.steps];
2337
+ const [removed] = newSteps.splice(fromIndex, 1);
2338
+ newSteps.splice(toIndex, 0, removed);
2339
+ store.steps = newSteps.map((s, i) => ({ ...s, order: i }));
2340
+ notifyListeners();
2341
+ },
2342
+ []
2343
+ );
2344
+ const clearAllSteps = (0, import_react15.useCallback)(() => {
2345
+ store.steps = [];
2346
+ clearSteps();
2347
+ notifyListeners();
2348
+ }, []);
2349
+ const exportSteps = (0, import_react15.useCallback)(() => {
2350
+ return {
2351
+ version: "1.0",
2352
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2353
+ steps: store.steps.map((step) => {
2354
+ let elementStr = `<${step.elementTag}`;
2355
+ if (step.elementClassName) {
2356
+ elementStr += ` class="${step.elementClassName.slice(0, 60)}${step.elementClassName.length > 60 ? "..." : ""}"`;
2357
+ }
2358
+ if (step.elementStyle) {
2359
+ elementStr += ` style="${step.elementStyle.slice(0, 40)}${step.elementStyle.length > 40 ? "..." : ""}"`;
2360
+ }
2361
+ for (const attr of step.existingAttrs) {
2362
+ if (attr !== "class" && attr !== "style") {
2363
+ elementStr += ` ${attr}`;
2364
+ }
2365
+ }
2366
+ elementStr += ">";
2367
+ if (step.elementText) {
2368
+ elementStr += `${step.elementText.slice(0, 30)}${step.elementText.length > 30 ? "..." : ""}`;
2369
+ }
2370
+ elementStr += `</${step.elementTag}>`;
2371
+ const sourceStr = step.source ? `${step.source.fileName.replace(/^.*\/src\//, "src/")}:${step.source.lineNumber}` : void 0;
2372
+ return {
2373
+ order: step.order,
2374
+ element: elementStr,
2375
+ componentTree: step.componentHierarchy,
2376
+ source: sourceStr
2377
+ };
2378
+ })
2379
+ };
2380
+ }, []);
2381
+ return {
2382
+ steps,
2383
+ addStep,
2384
+ removeStep,
2385
+ updateStep,
2386
+ reorderSteps,
2387
+ clearAllSteps,
2388
+ exportSteps
2389
+ };
2390
+ }
2391
+
2392
+ // src/devtools/DevToolsProvider.tsx
2393
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2394
+ var styles9 = {
2395
+ panel: {
2396
+ position: "fixed",
2397
+ width: 320,
2398
+ maxWidth: "calc(100vw - 32px)",
2399
+ maxHeight: "calc(100vh - 32px)",
2400
+ display: "flex",
2401
+ flexDirection: "column",
2402
+ zIndex: 99998,
2403
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
2404
+ fontSize: 13,
2405
+ backgroundColor: "hsl(222 47% 11%)",
2406
+ borderRadius: 12,
2407
+ border: "1px solid hsl(215 20% 25%)",
2408
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05)",
2409
+ overflow: "hidden"
2410
+ },
2411
+ header: {
2412
+ display: "flex",
2413
+ alignItems: "center",
2414
+ justifyContent: "space-between",
2415
+ padding: "10px 12px",
2416
+ borderBottom: "1px solid hsl(215 20% 20%)",
2417
+ backgroundColor: "hsl(222 47% 9%)",
2418
+ cursor: "grab",
2419
+ userSelect: "none",
2420
+ touchAction: "none"
2421
+ },
2422
+ headerDragging: {
2423
+ cursor: "grabbing"
2424
+ },
2425
+ titleGroup: {
2426
+ display: "flex",
2427
+ alignItems: "center",
2428
+ gap: 8
2429
+ },
2430
+ logo: {
2431
+ display: "flex",
2432
+ alignItems: "center",
2433
+ justifyContent: "center",
2434
+ width: 24,
2435
+ height: 24,
2436
+ borderRadius: 6,
2437
+ backgroundColor: "hsl(217 91% 55% / 0.2)"
2438
+ },
2439
+ title: {
2440
+ fontSize: 13,
2441
+ fontWeight: 600,
2442
+ color: "hsl(215 20% 75%)",
2443
+ letterSpacing: "-0.01em"
2444
+ },
2445
+ headerButtons: {
2446
+ display: "flex",
2447
+ alignItems: "center",
2448
+ gap: 2
2449
+ },
2450
+ iconButton: {
2451
+ display: "flex",
2452
+ alignItems: "center",
2453
+ justifyContent: "center",
2454
+ width: 26,
2455
+ height: 26,
2456
+ backgroundColor: "transparent",
2457
+ border: "none",
2458
+ color: "hsl(215 20% 55%)",
2459
+ cursor: "pointer",
2460
+ padding: 0,
2461
+ borderRadius: 6,
2462
+ transition: "all 0.15s ease",
2463
+ outline: "none"
2464
+ },
2465
+ body: {
2466
+ flex: 1,
2467
+ minHeight: 0,
2468
+ display: "flex",
2469
+ flexDirection: "column",
2470
+ overflow: "hidden"
2471
+ }
2472
+ };
2473
+ function DevToolsProvider(props) {
2474
+ const { children, enabled = true, defaultTab = "steps" } = props;
2475
+ const [mounted, setMounted] = (0, import_react16.useState)(false);
2476
+ const [shadowRoot, setShadowRoot] = (0, import_react16.useState)(null);
2477
+ const [activeTab, setActiveTab] = (0, import_react16.useState)(defaultTab);
2478
+ (0, import_react16.useEffect)(() => {
2479
+ setMounted(true);
2480
+ const host = document.createElement("div");
2481
+ host.setAttribute("data-devtools-host", "");
2482
+ host.style.cssText = "position: fixed; top: 0; left: 0; z-index: 99999; pointer-events: none;";
2483
+ document.body.appendChild(host);
2484
+ const shadow = host.attachShadow({ mode: "open" });
2485
+ const style = document.createElement("style");
2486
+ style.textContent = `
2487
+ :host { all: initial; }
2488
+ *, *::before, *::after { box-sizing: border-box; }
2489
+ `;
2490
+ shadow.appendChild(style);
2491
+ const container = document.createElement("div");
2492
+ container.style.cssText = "pointer-events: auto;";
2493
+ shadow.appendChild(container);
2494
+ setShadowRoot(shadow);
2495
+ return () => {
2496
+ document.body.removeChild(host);
2497
+ };
2498
+ }, []);
2499
+ const { mode, hoveredElement, toggleGrabbing, selectCurrent } = useGrabMode();
2500
+ const {
2501
+ steps,
2502
+ addStep,
2503
+ removeStep,
2504
+ reorderSteps,
2505
+ clearAllSteps,
2506
+ exportSteps
2507
+ } = useStepStore();
2508
+ const { flows } = useFlowsData();
2509
+ const [collapsed, setCollapsed] = (0, import_react16.useState)(false);
2510
+ const [position, setPosition] = (0, import_react16.useState)({ x: 16, y: 16 });
2511
+ const [isPanelDragging, setIsPanelDragging] = (0, import_react16.useState)(false);
2512
+ const dragStartRef = { current: null };
2513
+ const handleClick = (0, import_react16.useCallback)(
2514
+ (e) => {
2515
+ if (mode !== "grabbing") return;
2516
+ const target = e.target;
2517
+ if (target.closest("[data-devtools-panel]")) return;
2518
+ if (target.closest("[data-devtools-host]")) return;
2519
+ const root = target.getRootNode();
2520
+ if (root instanceof ShadowRoot) {
2521
+ const host = root.host;
2522
+ if (host?.hasAttribute("data-devtools-host")) return;
2523
+ }
2524
+ e.preventDefault();
2525
+ e.stopPropagation();
2526
+ const info = selectCurrent();
2527
+ if (info) {
2528
+ addStep({ info });
2529
+ }
2530
+ },
2531
+ [mode, selectCurrent, addStep]
2532
+ );
2533
+ (0, import_react16.useEffect)(() => {
2534
+ if (mode !== "grabbing") return;
2535
+ document.addEventListener("click", handleClick, { capture: true });
2536
+ return () => document.removeEventListener("click", handleClick, { capture: true });
2537
+ }, [mode, handleClick]);
2538
+ (0, import_react16.useEffect)(() => {
2539
+ if (mode !== "grabbing") return;
2540
+ const preventDefault = (e) => {
2541
+ const target = e.target;
2542
+ if (target.closest("[data-devtools-panel]")) return;
2543
+ e.preventDefault();
2544
+ };
2545
+ document.addEventListener("submit", preventDefault, { capture: true });
2546
+ return () => {
2547
+ document.removeEventListener("submit", preventDefault, { capture: true });
2548
+ };
2549
+ }, [mode]);
2550
+ (0, import_react16.useEffect)(() => {
2551
+ const handleKeyDown = (e) => {
2552
+ if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "m") {
2553
+ e.preventDefault();
2554
+ setCollapsed((c) => !c);
2555
+ }
2556
+ };
2557
+ document.addEventListener("keydown", handleKeyDown);
2558
+ return () => document.removeEventListener("keydown", handleKeyDown);
2559
+ }, []);
2560
+ const handlePointerDown = (0, import_react16.useCallback)(
2561
+ (e) => {
2562
+ const target = e.target;
2563
+ if (target.closest("button")) return;
2564
+ e.preventDefault();
2565
+ setIsPanelDragging(true);
2566
+ dragStartRef.current = {
2567
+ x: e.clientX,
2568
+ y: e.clientY,
2569
+ posX: position.x,
2570
+ posY: position.y
2571
+ };
2572
+ e.target.setPointerCapture(e.pointerId);
2573
+ },
2574
+ [position]
2575
+ );
2576
+ const handlePointerMove = (0, import_react16.useCallback)(
2577
+ (e) => {
2578
+ if (!dragStartRef.current || !isPanelDragging) return;
2579
+ const dx = e.clientX - dragStartRef.current.x;
2580
+ const dy = e.clientY - dragStartRef.current.y;
2581
+ const newX = Math.max(8, dragStartRef.current.posX - dx);
2582
+ const newY = Math.max(8, dragStartRef.current.posY + dy);
2583
+ setPosition({ x: newX, y: newY });
2584
+ },
2585
+ [isPanelDragging]
2586
+ );
2587
+ const handlePointerUp = (0, import_react16.useCallback)((e) => {
2588
+ setIsPanelDragging(false);
2589
+ dragStartRef.current = null;
2590
+ e.target.releasePointerCapture(e.pointerId);
2591
+ }, []);
2592
+ if (!enabled || !mounted) {
2593
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
2594
+ }
2595
+ const shadowContainer = shadowRoot?.lastElementChild ?? null;
2596
+ const panelStyle = {
2597
+ ...styles9.panel,
2598
+ right: position.x,
2599
+ top: position.y
2600
+ };
2601
+ const headerStyle = {
2602
+ ...styles9.header,
2603
+ ...isPanelDragging && styles9.headerDragging
2604
+ };
2605
+ const portalContainer = shadowContainer ?? document.body;
2606
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2607
+ children,
2608
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2609
+ GrabberOverlay,
2610
+ {
2611
+ isGrabbing: mode === "grabbing",
2612
+ hoveredInfo: hoveredElement?.info ?? null,
2613
+ container: shadowContainer
2614
+ }
2615
+ ),
2616
+ (0, import_react_dom3.createPortal)(
2617
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2618
+ import_react17.motion.div,
2619
+ {
2620
+ style: panelStyle,
2621
+ initial: { opacity: 0, x: 20, scale: 0.95 },
2622
+ animate: { opacity: 1, x: 0, scale: 1 },
2623
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
2624
+ "data-devtools-panel": "",
2625
+ children: [
2626
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2627
+ "div",
2628
+ {
2629
+ style: headerStyle,
2630
+ onPointerDown: handlePointerDown,
2631
+ onPointerMove: handlePointerMove,
2632
+ onPointerUp: handlePointerUp,
2633
+ onPointerCancel: handlePointerUp,
2634
+ children: [
2635
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles9.titleGroup, children: [
2636
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles9.logo, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "hsl(217 91% 70%)", children: [
2637
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M8 0L14.9 4v8L8 16 1.1 12V4L8 0zm0 2.3L3.1 5.2v5.6L8 13.7l4.9-2.9V5.2L8 2.3z" }),
2638
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M8 5l3 1.7v3.4L8 11.8 5 10.1V6.7L8 5z" })
2639
+ ] }) }),
2640
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles9.title, children: "DevTools" })
2641
+ ] }),
2642
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles9.headerButtons, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2643
+ "button",
2644
+ {
2645
+ type: "button",
2646
+ style: styles9.iconButton,
2647
+ onClick: () => setCollapsed(!collapsed),
2648
+ title: collapsed ? "Expand (Ctrl+Shift+M)" : "Collapse (Ctrl+Shift+M)",
2649
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2650
+ "svg",
2651
+ {
2652
+ width: "14",
2653
+ height: "14",
2654
+ viewBox: "0 0 16 16",
2655
+ fill: "currentColor",
2656
+ style: {
2657
+ transform: collapsed ? "rotate(180deg)" : "none",
2658
+ transition: "transform 0.2s ease"
2659
+ },
2660
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z" })
2661
+ }
2662
+ )
2663
+ }
2664
+ ) })
2665
+ ]
2666
+ }
2667
+ ),
2668
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react17.AnimatePresence, { initial: false, children: !collapsed && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2669
+ import_react17.motion.div,
2670
+ {
2671
+ style: styles9.body,
2672
+ initial: { height: 0, opacity: 0 },
2673
+ animate: { height: "auto", opacity: 1 },
2674
+ exit: { height: 0, opacity: 0 },
2675
+ transition: { duration: 0.2, ease: [0.16, 1, 0.3, 1] },
2676
+ children: [
2677
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2678
+ TabNav,
2679
+ {
2680
+ activeTab,
2681
+ onTabChange: setActiveTab,
2682
+ stepCount: steps.length,
2683
+ flowCount: flows.length
2684
+ }
2685
+ ),
2686
+ activeTab === "steps" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2687
+ StepList,
2688
+ {
2689
+ steps,
2690
+ mode,
2691
+ onToggleGrab: toggleGrabbing,
2692
+ onDeleteStep: removeStep,
2693
+ onReorderSteps: reorderSteps,
2694
+ onClearAll: clearAllSteps,
2695
+ onExport: exportSteps
2696
+ }
2697
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FlowsTab, { container: shadowContainer })
2698
+ ]
2699
+ }
2700
+ ) })
2701
+ ]
2702
+ }
2703
+ ),
2704
+ portalContainer
2705
+ )
2706
+ ] });
2707
+ }
2708
+ // Annotate the CommonJS export names for ESM import in node:
2709
+ 0 && (module.exports = {
2710
+ DevToolsContext,
2711
+ DevToolsProvider,
2712
+ FlowEditModal,
2713
+ FlowItem,
2714
+ FlowsTab,
2715
+ GrabberOverlay,
2716
+ SortableStepItem,
2717
+ StepItem,
2718
+ StepItemDragPreview,
2719
+ StepList,
2720
+ TabNav,
2721
+ Toolbar,
2722
+ clearSteps,
2723
+ extractComponentHierarchy,
2724
+ extractSource,
2725
+ formatSourcePath,
2726
+ generateSelector,
2727
+ getVSCodeLink,
2728
+ loadSteps,
2729
+ saveSteps,
2730
+ useDevToolsContext,
2731
+ useDevToolsContextRequired,
2732
+ useElementInfo,
2733
+ useFlowsData,
2734
+ useGrabMode,
2735
+ useStepStore
2736
+ });