ontheway-sdk 0.1.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 (44) hide show
  1. package/README.md +110 -0
  2. package/dist/checklist.cjs +319 -0
  3. package/dist/checklist.cjs.map +1 -0
  4. package/dist/checklist.d.cts +58 -0
  5. package/dist/checklist.d.ts +58 -0
  6. package/dist/checklist.js +314 -0
  7. package/dist/checklist.js.map +1 -0
  8. package/dist/chunk-254YHUN3.cjs +26 -0
  9. package/dist/chunk-254YHUN3.cjs.map +1 -0
  10. package/dist/chunk-DDAAVRWG.js +23 -0
  11. package/dist/chunk-DDAAVRWG.js.map +1 -0
  12. package/dist/chunk-NRUQU5AR.cjs +94 -0
  13. package/dist/chunk-NRUQU5AR.cjs.map +1 -0
  14. package/dist/chunk-OKJ5GEH3.js +358 -0
  15. package/dist/chunk-OKJ5GEH3.js.map +1 -0
  16. package/dist/chunk-RNQLNLNI.js +91 -0
  17. package/dist/chunk-RNQLNLNI.js.map +1 -0
  18. package/dist/chunk-UE3T6TSM.cjs +361 -0
  19. package/dist/chunk-UE3T6TSM.cjs.map +1 -0
  20. package/dist/components.cjs +211 -0
  21. package/dist/components.cjs.map +1 -0
  22. package/dist/components.d.cts +51 -0
  23. package/dist/components.d.ts +51 -0
  24. package/dist/components.js +205 -0
  25. package/dist/components.js.map +1 -0
  26. package/dist/devtools.cjs +733 -0
  27. package/dist/devtools.cjs.map +1 -0
  28. package/dist/devtools.d.cts +18 -0
  29. package/dist/devtools.d.ts +18 -0
  30. package/dist/devtools.js +727 -0
  31. package/dist/devtools.js.map +1 -0
  32. package/dist/index.cjs +19 -0
  33. package/dist/index.cjs.map +1 -0
  34. package/dist/index.d.cts +163 -0
  35. package/dist/index.d.ts +163 -0
  36. package/dist/index.js +4 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/react.cjs +18 -0
  39. package/dist/react.cjs.map +1 -0
  40. package/dist/react.d.cts +68 -0
  41. package/dist/react.d.ts +68 -0
  42. package/dist/react.js +5 -0
  43. package/dist/react.js.map +1 -0
  44. package/package.json +93 -0
@@ -0,0 +1,727 @@
1
+ import { __spreadValues, __spreadProps } from './chunk-DDAAVRWG.js';
2
+ import { useState, useRef, useCallback, useEffect } from 'react';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+
5
+ function genSelector(el) {
6
+ const ds = el.dataset;
7
+ if (ds == null ? void 0 : ds.onthewayId) return `[data-ontheway-id="${ds.onthewayId}"]`;
8
+ if (el.id && !/^[\d:]/.test(el.id)) {
9
+ try {
10
+ if (document.querySelectorAll("#" + CSS.escape(el.id)).length === 1) return "#" + CSS.escape(el.id);
11
+ } catch (e) {
12
+ }
13
+ }
14
+ const parts = [];
15
+ let cur = el;
16
+ while (cur && cur !== document.body && cur !== document.documentElement && parts.length < 4) {
17
+ let p = cur.tagName.toLowerCase();
18
+ if (cur.id && !/^[\d:]/.test(cur.id)) {
19
+ parts.unshift("#" + CSS.escape(cur.id));
20
+ break;
21
+ }
22
+ const cls = Array.from(cur.classList || []).filter((c) => !/^(w-|h-|p-|m-|text-|bg-|flex|grid|border|rounded|hover:|focus:|sm:|md:|lg:|xl:)/.test(c)).slice(0, 2);
23
+ if (cls.length) p += "." + cls.map((c) => CSS.escape(c)).join(".");
24
+ const parent = cur.parentElement;
25
+ if (parent) {
26
+ const sibs = Array.from(parent.children).filter((s) => s.tagName === cur.tagName);
27
+ if (sibs.length > 1) p += `:nth-child(${sibs.indexOf(cur) + 1})`;
28
+ }
29
+ parts.unshift(p);
30
+ cur = cur.parentElement;
31
+ }
32
+ const sel = parts.join(" > ");
33
+ try {
34
+ if (document.querySelector(sel) === el) return sel;
35
+ } catch (e) {
36
+ }
37
+ parts.length = 0;
38
+ cur = el;
39
+ while (cur && cur !== document.body) {
40
+ const parentEl = cur.parentElement;
41
+ if (!parentEl) break;
42
+ parts.unshift(cur.tagName.toLowerCase() + ":nth-child(" + (Array.from(parentEl.children).indexOf(cur) + 1) + ")");
43
+ cur = parentEl;
44
+ }
45
+ return "body > " + parts.join(" > ");
46
+ }
47
+ function OnTheWayDevToolsPanel({ projectId, apiKey, serverUrl }) {
48
+ const [minimized, setMinimized] = useState(true);
49
+ const [tab, setTab] = useState("record");
50
+ const [recording, setRecording] = useState(false);
51
+ const [steps, setSteps] = useState([]);
52
+ const [editingStep, setEditingStep] = useState(null);
53
+ const [taskName, setTaskName] = useState("");
54
+ const [taskSlug, setTaskSlug] = useState("");
55
+ const [trigger, setTrigger] = useState("manual");
56
+ const [saving, setSaving] = useState(false);
57
+ const [saveMsg, setSaveMsg] = useState("");
58
+ const [aiIntent, setAiIntent] = useState("");
59
+ const [aiGenerating, setAiGenerating] = useState(false);
60
+ const [tasks, setTasks] = useState([]);
61
+ const [loadingTasks, setLoadingTasks] = useState(false);
62
+ const highlightRef = useRef(null);
63
+ const hoveredRef = useRef(null);
64
+ const panelRef = useRef(null);
65
+ const baseUrl = serverUrl || (typeof window !== "undefined" ? window.location.origin : "");
66
+ const fetchTasks = useCallback(async () => {
67
+ setLoadingTasks(true);
68
+ try {
69
+ const res = await fetch(`${baseUrl}/api/sdk/${projectId}/config`);
70
+ const data = await res.json();
71
+ setTasks((data.tasks || []).map((t) => ({
72
+ id: t.id,
73
+ name: t.slug.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
74
+ slug: t.slug,
75
+ steps: t.steps,
76
+ enabled: true
77
+ })));
78
+ } catch (e) {
79
+ setTasks([]);
80
+ }
81
+ setLoadingTasks(false);
82
+ }, [baseUrl, projectId]);
83
+ useEffect(() => {
84
+ if (tab === "tasks" && !minimized) fetchTasks();
85
+ }, [tab, minimized, fetchTasks]);
86
+ const isOurElement = useCallback((el) => {
87
+ var _a, _b;
88
+ return ((_a = panelRef.current) == null ? void 0 : _a.contains(el)) || ((_b = highlightRef.current) == null ? void 0 : _b.contains(el)) || el.id === "otw-devtools-highlight";
89
+ }, []);
90
+ const onMouseMove = useCallback((e) => {
91
+ const el = document.elementFromPoint(e.clientX, e.clientY);
92
+ if (!el || el === hoveredRef.current || isOurElement(el)) return;
93
+ hoveredRef.current = el;
94
+ if (!highlightRef.current) {
95
+ const div = document.createElement("div");
96
+ div.id = "otw-devtools-highlight";
97
+ div.style.cssText = "position:fixed;pointer-events:none;z-index:2147483645;border:2px solid #3b82f6;background:rgba(59,130,246,0.15);border-radius:3px;transition:all .08s ease";
98
+ document.documentElement.appendChild(div);
99
+ highlightRef.current = div;
100
+ }
101
+ const r = el.getBoundingClientRect();
102
+ const h = highlightRef.current;
103
+ h.style.display = "block";
104
+ h.style.top = r.top + "px";
105
+ h.style.left = r.left + "px";
106
+ h.style.width = r.width + "px";
107
+ h.style.height = r.height + "px";
108
+ }, [isOurElement]);
109
+ const onMouseLeave = useCallback(() => {
110
+ if (highlightRef.current) highlightRef.current.style.display = "none";
111
+ hoveredRef.current = null;
112
+ }, []);
113
+ const onClick = useCallback((e) => {
114
+ var _a;
115
+ const el = e.target;
116
+ if (isOurElement(el)) return;
117
+ e.preventDefault();
118
+ e.stopPropagation();
119
+ el.getBoundingClientRect();
120
+ const text = ((_a = el.innerText) == null ? void 0 : _a.trim().substring(0, 60)) || "";
121
+ const step = {
122
+ id: "step_" + Date.now(),
123
+ selector: genSelector(el),
124
+ tagName: el.tagName.toLowerCase(),
125
+ innerText: text,
126
+ title: `Step ${steps.length + 1}`,
127
+ description: "Click here to continue",
128
+ position: "auto",
129
+ spotlight: true,
130
+ url: location.href
131
+ };
132
+ setSteps((prev) => [...prev, step]);
133
+ setEditingStep(step.id);
134
+ const orig = el.style.outline;
135
+ el.style.outline = "3px solid #22c55e";
136
+ setTimeout(() => {
137
+ el.style.outline = orig;
138
+ }, 400);
139
+ }, [isOurElement, steps.length]);
140
+ const startRecording = useCallback(() => {
141
+ setRecording(true);
142
+ document.addEventListener("mousemove", onMouseMove, true);
143
+ document.addEventListener("mouseleave", onMouseLeave, true);
144
+ document.addEventListener("click", onClick, true);
145
+ }, [onMouseMove, onMouseLeave, onClick]);
146
+ const stopRecording = useCallback(() => {
147
+ setRecording(false);
148
+ document.removeEventListener("mousemove", onMouseMove, true);
149
+ document.removeEventListener("mouseleave", onMouseLeave, true);
150
+ document.removeEventListener("click", onClick, true);
151
+ if (highlightRef.current) {
152
+ highlightRef.current.remove();
153
+ highlightRef.current = null;
154
+ }
155
+ hoveredRef.current = null;
156
+ }, [onMouseMove, onMouseLeave, onClick]);
157
+ useEffect(() => {
158
+ return () => {
159
+ var _a;
160
+ document.removeEventListener("mousemove", onMouseMove, true);
161
+ document.removeEventListener("mouseleave", onMouseLeave, true);
162
+ document.removeEventListener("click", onClick, true);
163
+ (_a = highlightRef.current) == null ? void 0 : _a.remove();
164
+ };
165
+ }, [onMouseMove, onMouseLeave, onClick]);
166
+ useEffect(() => {
167
+ if (taskName) {
168
+ setTaskSlug(taskName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, ""));
169
+ }
170
+ }, [taskName]);
171
+ const updateStep = (id, updates) => {
172
+ setSteps((prev) => prev.map((s) => s.id === id ? __spreadValues(__spreadValues({}, s), updates) : s));
173
+ };
174
+ const deleteStep = (id) => {
175
+ setSteps((prev) => prev.filter((s) => s.id !== id));
176
+ if (editingStep === id) setEditingStep(null);
177
+ };
178
+ const moveStep = (id, dir) => {
179
+ setSteps((prev) => {
180
+ const i = prev.findIndex((s) => s.id === id);
181
+ if (i === -1) return prev;
182
+ if (dir === "up" && i === 0) return prev;
183
+ if (dir === "down" && i === prev.length - 1) return prev;
184
+ const next = [...prev];
185
+ const j = dir === "up" ? i - 1 : i + 1;
186
+ [next[i], next[j]] = [next[j], next[i]];
187
+ return next;
188
+ });
189
+ };
190
+ const extractDOM = useCallback(() => {
191
+ const walk = (el, depth) => {
192
+ var _a;
193
+ if (depth > 6) return "";
194
+ const tag = el.tagName.toLowerCase();
195
+ if (["script", "style", "noscript", "svg", "path"].includes(tag)) return "";
196
+ if ((_a = el.id) == null ? void 0 : _a.startsWith("otw-")) return "";
197
+ if (el.offsetParent === null && tag !== "body" && tag !== "html") return "";
198
+ const attrs = [];
199
+ if (el.id) attrs.push(`id="${el.id}"`);
200
+ if (el.className && typeof el.className === "string") {
201
+ const cls = el.className.split(/\s+/).filter(
202
+ (c) => !/^(w-|h-|p-|m-|text-|bg-|flex|grid|border|rounded|shadow|transition|transform|hover:|focus:|sm:|md:|lg:|xl:|2xl:)/.test(c)
203
+ ).slice(0, 3).join(" ");
204
+ if (cls) attrs.push(`class="${cls}"`);
205
+ }
206
+ if (el.type) attrs.push(`type="${el.type}"`);
207
+ if (el.name) attrs.push(`name="${el.name}"`);
208
+ if (el.placeholder) attrs.push(`placeholder="${el.placeholder}"`);
209
+ if (el.href && tag === "a") attrs.push(`href="..."`);
210
+ const ds = el.dataset;
211
+ if (ds == null ? void 0 : ds.onthewayId) attrs.push(`data-ontheway-id="${ds.onthewayId}"`);
212
+ const indent = " ".repeat(depth);
213
+ const attrStr = attrs.length ? " " + attrs.join(" ") : "";
214
+ const text = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => {
215
+ var _a2;
216
+ return (_a2 = n.textContent) == null ? void 0 : _a2.trim();
217
+ }).filter(Boolean).join(" ").substring(0, 60);
218
+ const children = Array.from(el.children).map((c) => walk(c, depth + 1)).filter(Boolean).join("\n");
219
+ if (!children && !text && !["input", "button", "img", "video", "iframe"].includes(tag)) {
220
+ return "";
221
+ }
222
+ if (!children) {
223
+ return `${indent}<${tag}${attrStr}>${text ? " " + text + " " : ""}</${tag}>`;
224
+ }
225
+ return `${indent}<${tag}${attrStr}>${text ? " " + text : ""}
226
+ ${children}
227
+ ${indent}</${tag}>`;
228
+ };
229
+ return walk(document.body, 0);
230
+ }, []);
231
+ const aiGenerate = useCallback(async () => {
232
+ if (!aiIntent.trim()) {
233
+ setSaveMsg("\u274C Describe what the tour should do");
234
+ return;
235
+ }
236
+ setAiGenerating(true);
237
+ setSaveMsg("");
238
+ try {
239
+ const dom = extractDOM();
240
+ const res = await fetch(`${baseUrl}/api/ai/generate`, {
241
+ method: "POST",
242
+ headers: { "Content-Type": "application/json" },
243
+ body: JSON.stringify({
244
+ intent: aiIntent,
245
+ dom,
246
+ url: location.href,
247
+ taskName: taskName || void 0
248
+ })
249
+ });
250
+ const data = await res.json();
251
+ if (data.steps && data.steps.length > 0) {
252
+ const newSteps = data.steps.map((s, i) => ({
253
+ id: "ai_" + Date.now() + "_" + i,
254
+ selector: s.selector || "",
255
+ tagName: "",
256
+ innerText: "",
257
+ title: s.title || `Step ${i + 1}`,
258
+ description: s.content || s.description || "",
259
+ position: s.position || "auto",
260
+ spotlight: s.spotlight !== false,
261
+ url: location.href
262
+ }));
263
+ setSteps((prev) => [...prev, ...newSteps]);
264
+ if (!taskName && data.taskName) {
265
+ setTaskName(data.taskName);
266
+ }
267
+ setEditingStep(newSteps[0].id);
268
+ setSaveMsg(`\u2728 ${newSteps.length} steps generated (${data.source})`);
269
+ } else {
270
+ setSaveMsg("\u274C No steps generated");
271
+ }
272
+ } catch (e) {
273
+ setSaveMsg("\u274C AI generation failed");
274
+ }
275
+ setAiGenerating(false);
276
+ }, [aiIntent, baseUrl, extractDOM, taskName]);
277
+ const saveTask = async () => {
278
+ if (!taskName || !taskSlug || steps.length === 0) {
279
+ setSaveMsg("\u274C Fill name + at least 1 step");
280
+ return;
281
+ }
282
+ setSaving(true);
283
+ setSaveMsg("");
284
+ try {
285
+ const res = await fetch(`${baseUrl}/api/projects/${projectId}/tasks`, {
286
+ method: "POST",
287
+ headers: { "Content-Type": "application/json" },
288
+ body: JSON.stringify({
289
+ name: taskName,
290
+ slug: taskSlug,
291
+ trigger,
292
+ steps: steps.map((s) => ({
293
+ selector: s.selector,
294
+ title: s.title,
295
+ content: s.description,
296
+ position: s.position,
297
+ spotlight: s.spotlight
298
+ }))
299
+ })
300
+ });
301
+ if (res.ok) {
302
+ setSaveMsg("\u2705 Saved!");
303
+ setSteps([]);
304
+ setTaskName("");
305
+ setTaskSlug("");
306
+ setEditingStep(null);
307
+ stopRecording();
308
+ } else {
309
+ const err = await res.json();
310
+ setSaveMsg("\u274C " + (err.error || "Failed"));
311
+ }
312
+ } catch (e) {
313
+ setSaveMsg("\u274C Network error");
314
+ }
315
+ setSaving(false);
316
+ };
317
+ steps.find((s) => s.id === editingStep);
318
+ const S = {
319
+ panel: {
320
+ position: "fixed",
321
+ bottom: 16,
322
+ right: 16,
323
+ zIndex: 2147483646,
324
+ fontFamily: "system-ui, -apple-system, sans-serif",
325
+ fontSize: 13,
326
+ color: "#1f2937"
327
+ },
328
+ card: {
329
+ width: 360,
330
+ maxHeight: "80vh",
331
+ background: "#fff",
332
+ borderRadius: 12,
333
+ boxShadow: "0 8px 40px rgba(0,0,0,0.18)",
334
+ border: "1px solid #e5e7eb",
335
+ overflow: "hidden",
336
+ display: "flex",
337
+ flexDirection: "column"
338
+ },
339
+ header: {
340
+ display: "flex",
341
+ alignItems: "center",
342
+ justifyContent: "space-between",
343
+ padding: "10px 14px",
344
+ background: "#111",
345
+ color: "#fff",
346
+ fontSize: 13,
347
+ fontWeight: 600
348
+ },
349
+ tabs: {
350
+ display: "flex",
351
+ borderBottom: "1px solid #e5e7eb"
352
+ },
353
+ tab: (active) => ({
354
+ flex: 1,
355
+ padding: "8px 0",
356
+ border: "none",
357
+ background: active ? "#fff" : "#f9fafb",
358
+ borderBottom: active ? "2px solid #111" : "2px solid transparent",
359
+ cursor: "pointer",
360
+ fontSize: 12,
361
+ fontWeight: active ? 600 : 400,
362
+ color: active ? "#111" : "#6b7280"
363
+ }),
364
+ body: {
365
+ flex: 1,
366
+ overflow: "auto",
367
+ maxHeight: "calc(80vh - 100px)"
368
+ },
369
+ section: {
370
+ padding: "10px 14px",
371
+ borderBottom: "1px solid #f3f4f6"
372
+ },
373
+ input: {
374
+ width: "100%",
375
+ padding: "6px 8px",
376
+ border: "1px solid #d1d5db",
377
+ borderRadius: 6,
378
+ fontSize: 12,
379
+ marginTop: 4,
380
+ boxSizing: "border-box"
381
+ },
382
+ select: {
383
+ padding: "6px 8px",
384
+ border: "1px solid #d1d5db",
385
+ borderRadius: 6,
386
+ fontSize: 12,
387
+ marginTop: 4
388
+ },
389
+ btn: (color, disabled = false) => ({
390
+ padding: "6px 14px",
391
+ border: "none",
392
+ borderRadius: 6,
393
+ background: disabled ? "#d1d5db" : color,
394
+ color: "#fff",
395
+ fontSize: 12,
396
+ fontWeight: 600,
397
+ cursor: disabled ? "not-allowed" : "pointer"
398
+ }),
399
+ btnOutline: {
400
+ padding: "6px 14px",
401
+ border: "1px solid #d1d5db",
402
+ borderRadius: 6,
403
+ background: "#fff",
404
+ fontSize: 12,
405
+ cursor: "pointer"
406
+ },
407
+ stepItem: (active) => ({
408
+ padding: "8px 10px",
409
+ margin: "4px 0",
410
+ borderRadius: 6,
411
+ border: active ? "1px solid #3b82f6" : "1px solid #e5e7eb",
412
+ background: active ? "#eff6ff" : "#fff",
413
+ cursor: "pointer"
414
+ }),
415
+ fab: {
416
+ width: 48,
417
+ height: 48,
418
+ borderRadius: "50%",
419
+ border: "none",
420
+ background: "#111",
421
+ color: "#fff",
422
+ fontSize: 22,
423
+ cursor: "pointer",
424
+ boxShadow: "0 4px 16px rgba(0,0,0,0.2)",
425
+ display: "flex",
426
+ alignItems: "center",
427
+ justifyContent: "center"
428
+ },
429
+ label: {
430
+ fontSize: 11,
431
+ fontWeight: 600,
432
+ color: "#6b7280",
433
+ marginBottom: 2,
434
+ display: "block"
435
+ },
436
+ recDot: {
437
+ width: 8,
438
+ height: 8,
439
+ borderRadius: "50%",
440
+ background: "#ef4444",
441
+ animation: "otw-blink 1s ease-in-out infinite",
442
+ display: "inline-block",
443
+ marginRight: 6
444
+ }
445
+ };
446
+ useEffect(() => {
447
+ if (document.getElementById("otw-devtools-style")) return;
448
+ const style = document.createElement("style");
449
+ style.id = "otw-devtools-style";
450
+ style.textContent = "@keyframes otw-blink{0%,100%{opacity:1}50%{opacity:0.3}}";
451
+ document.head.appendChild(style);
452
+ return () => {
453
+ style.remove();
454
+ };
455
+ }, []);
456
+ const logoSvg = `data:image/svg+xml,${encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" fill="none"><rect width="40" height="40" rx="10" fill="#111"/><path d="M12 32 C12 24,16 22,20 20 C24 18,28 16,28 8" stroke="#22c55e" stroke-width="3.5" stroke-linecap="round" fill="none"/><path d="M12 32 C12 24,16 22,20 20 C24 18,28 16,28 8" stroke="#fff" stroke-width="1.2" stroke-linecap="round" stroke-dasharray="2.5 3.5" fill="none" opacity="0.6"/><circle cx="28" cy="8" r="3.5" fill="#22c55e"/><circle cx="28" cy="8" r="1.5" fill="#111"/><circle cx="12" cy="32" r="2.5" fill="#fff" opacity="0.9"/></svg>')}`;
457
+ if (minimized) {
458
+ return /* @__PURE__ */ jsx("div", { ref: panelRef, style: S.panel, children: /* @__PURE__ */ jsx(
459
+ "button",
460
+ {
461
+ onClick: () => setMinimized(false),
462
+ style: __spreadValues(__spreadValues({}, S.fab), recording ? { background: "#22c55e", boxShadow: "0 0 20px rgba(34,197,94,0.5)" } : {}),
463
+ title: "OnTheWay DevTools",
464
+ children: recording ? /* @__PURE__ */ jsx("span", { style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx("span", { style: S.recDot }) }) : /* @__PURE__ */ jsx("img", { src: logoSvg, alt: "OTW", style: { width: 24, height: 24 } })
465
+ }
466
+ ) });
467
+ }
468
+ return /* @__PURE__ */ jsx("div", { ref: panelRef, style: S.panel, children: /* @__PURE__ */ jsxs("div", { style: S.card, children: [
469
+ /* @__PURE__ */ jsxs("div", { style: S.header, children: [
470
+ /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
471
+ /* @__PURE__ */ jsx("img", { src: logoSvg, alt: "OTW", style: { width: 18, height: 18 } }),
472
+ "OnTheWay DevTools"
473
+ ] }),
474
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
475
+ recording && /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", fontSize: 11 }, children: [
476
+ /* @__PURE__ */ jsx("span", { style: S.recDot }),
477
+ " REC"
478
+ ] }),
479
+ /* @__PURE__ */ jsx("button", { onClick: () => setMinimized(true), style: { background: "none", border: "none", color: "#fff", cursor: "pointer", fontSize: 16 }, children: "\u2212" })
480
+ ] })
481
+ ] }),
482
+ /* @__PURE__ */ jsxs("div", { style: S.tabs, children: [
483
+ /* @__PURE__ */ jsx("button", { style: S.tab(tab === "record"), onClick: () => setTab("record"), children: "\u23FA Record" }),
484
+ /* @__PURE__ */ jsxs("button", { style: S.tab(tab === "tasks"), onClick: () => setTab("tasks"), children: [
485
+ "\u{1F4CB} Tasks (",
486
+ tasks.length,
487
+ ")"
488
+ ] })
489
+ ] }),
490
+ /* @__PURE__ */ jsx("div", { style: S.body, children: tab === "record" ? /* @__PURE__ */ jsxs(Fragment, { children: [
491
+ /* @__PURE__ */ jsxs("div", { style: S.section, children: [
492
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }, children: [
493
+ /* @__PURE__ */ jsxs("div", { children: [
494
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "Task Name" }),
495
+ /* @__PURE__ */ jsx("input", { style: S.input, value: taskName, onChange: (e) => setTaskName(e.target.value), placeholder: "Welcome Tour" })
496
+ ] }),
497
+ /* @__PURE__ */ jsxs("div", { children: [
498
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "Trigger" }),
499
+ /* @__PURE__ */ jsxs("select", { style: __spreadProps(__spreadValues({}, S.select), { width: "100%" }), value: trigger, onChange: (e) => setTrigger(e.target.value), children: [
500
+ /* @__PURE__ */ jsx("option", { value: "manual", children: "Manual" }),
501
+ /* @__PURE__ */ jsx("option", { value: "auto", children: "Auto" }),
502
+ /* @__PURE__ */ jsx("option", { value: "first-visit", children: "First Visit" })
503
+ ] })
504
+ ] })
505
+ ] }),
506
+ taskSlug && /* @__PURE__ */ jsxs("div", { style: { fontSize: 11, color: "#9ca3af", marginTop: 4 }, children: [
507
+ "slug: ",
508
+ taskSlug
509
+ ] })
510
+ ] }),
511
+ /* @__PURE__ */ jsxs("div", { style: __spreadProps(__spreadValues({}, S.section), { display: "flex", gap: 8, flexWrap: "wrap" }), children: [
512
+ !recording ? /* @__PURE__ */ jsx("button", { style: S.btn("#22c55e"), onClick: startRecording, children: "\u23FA Record" }) : /* @__PURE__ */ jsx("button", { style: S.btn("#ef4444"), onClick: stopRecording, children: "\u23F9 Stop" }),
513
+ /* @__PURE__ */ jsx("button", { style: S.btn("#111", saving || steps.length === 0 || !taskName), onClick: saveTask, disabled: saving || steps.length === 0 || !taskName, children: saving ? "..." : "\u{1F4BE} Save" })
514
+ ] }),
515
+ /* @__PURE__ */ jsxs("div", { style: S.section, children: [
516
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "\u2728 AI Generate" }),
517
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
518
+ /* @__PURE__ */ jsx(
519
+ "input",
520
+ {
521
+ style: __spreadProps(__spreadValues({}, S.input), { flex: 1, marginTop: 0 }),
522
+ value: aiIntent,
523
+ onChange: (e) => setAiIntent(e.target.value),
524
+ placeholder: "e.g. Guide new users to create their first project",
525
+ onKeyDown: (e) => {
526
+ if (e.key === "Enter" && !aiGenerating) aiGenerate();
527
+ }
528
+ }
529
+ ),
530
+ /* @__PURE__ */ jsx(
531
+ "button",
532
+ {
533
+ style: S.btn("#7c3aed", aiGenerating || !aiIntent.trim()),
534
+ onClick: aiGenerate,
535
+ disabled: aiGenerating || !aiIntent.trim(),
536
+ children: aiGenerating ? "..." : "\u2728"
537
+ }
538
+ )
539
+ ] }),
540
+ saveMsg && /* @__PURE__ */ jsx("div", { style: { fontSize: 11, marginTop: 4, color: saveMsg.startsWith("\u2705") || saveMsg.startsWith("\u2728") ? "#16a34a" : saveMsg.startsWith("\u274C") ? "#dc2626" : "#6b7280" }, children: saveMsg })
541
+ ] }),
542
+ /* @__PURE__ */ jsxs("div", { style: S.section, children: [
543
+ /* @__PURE__ */ jsxs("label", { style: __spreadProps(__spreadValues({}, S.label), { marginBottom: 6 }), children: [
544
+ "Steps (",
545
+ steps.length,
546
+ ")"
547
+ ] }),
548
+ steps.length === 0 ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "16px 0", color: "#9ca3af", fontSize: 12 }, children: recording ? "Click elements on the page to capture steps" : "Click Record to start" }) : steps.map((step, i) => /* @__PURE__ */ jsxs(
549
+ "div",
550
+ {
551
+ style: S.stepItem(editingStep === step.id),
552
+ onClick: () => setEditingStep(editingStep === step.id ? null : step.id),
553
+ children: [
554
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
555
+ /* @__PURE__ */ jsxs("span", { style: { fontWeight: 500, fontSize: 12 }, children: [
556
+ /* @__PURE__ */ jsx("span", { style: { color: "#9ca3af", marginRight: 6 }, children: i + 1 }),
557
+ step.title
558
+ ] }),
559
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 4 }, children: [
560
+ /* @__PURE__ */ jsx(
561
+ "button",
562
+ {
563
+ onClick: (e) => {
564
+ e.stopPropagation();
565
+ moveStep(step.id, "up");
566
+ },
567
+ disabled: i === 0,
568
+ style: __spreadProps(__spreadValues({}, S.btnOutline), { padding: "2px 6px", fontSize: 10 }),
569
+ children: "\u2191"
570
+ }
571
+ ),
572
+ /* @__PURE__ */ jsx(
573
+ "button",
574
+ {
575
+ onClick: (e) => {
576
+ e.stopPropagation();
577
+ moveStep(step.id, "down");
578
+ },
579
+ disabled: i === steps.length - 1,
580
+ style: __spreadProps(__spreadValues({}, S.btnOutline), { padding: "2px 6px", fontSize: 10 }),
581
+ children: "\u2193"
582
+ }
583
+ ),
584
+ /* @__PURE__ */ jsx(
585
+ "button",
586
+ {
587
+ onClick: (e) => {
588
+ e.stopPropagation();
589
+ deleteStep(step.id);
590
+ },
591
+ style: __spreadProps(__spreadValues({}, S.btnOutline), { padding: "2px 6px", fontSize: 10, color: "#ef4444" }),
592
+ children: "\u2715"
593
+ }
594
+ )
595
+ ] })
596
+ ] }),
597
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 10, color: "#9ca3af", fontFamily: "monospace", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: step.selector }),
598
+ editingStep === step.id && /* @__PURE__ */ jsxs(
599
+ "div",
600
+ {
601
+ style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 6 },
602
+ onClick: (e) => e.stopPropagation(),
603
+ children: [
604
+ /* @__PURE__ */ jsxs("div", { children: [
605
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "Selector" }),
606
+ /* @__PURE__ */ jsx(
607
+ "input",
608
+ {
609
+ style: __spreadProps(__spreadValues({}, S.input), { fontFamily: "monospace" }),
610
+ value: step.selector,
611
+ onChange: (e) => updateStep(step.id, { selector: e.target.value })
612
+ }
613
+ )
614
+ ] }),
615
+ /* @__PURE__ */ jsxs("div", { children: [
616
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "Title" }),
617
+ /* @__PURE__ */ jsx(
618
+ "input",
619
+ {
620
+ style: S.input,
621
+ value: step.title,
622
+ onChange: (e) => updateStep(step.id, { title: e.target.value })
623
+ }
624
+ )
625
+ ] }),
626
+ /* @__PURE__ */ jsxs("div", { children: [
627
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "Description" }),
628
+ /* @__PURE__ */ jsx(
629
+ "input",
630
+ {
631
+ style: S.input,
632
+ value: step.description,
633
+ onChange: (e) => updateStep(step.id, { description: e.target.value })
634
+ }
635
+ )
636
+ ] }),
637
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
638
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
639
+ /* @__PURE__ */ jsx("label", { style: S.label, children: "Position" }),
640
+ /* @__PURE__ */ jsxs(
641
+ "select",
642
+ {
643
+ style: __spreadProps(__spreadValues({}, S.select), { width: "100%" }),
644
+ value: step.position,
645
+ onChange: (e) => updateStep(step.id, { position: e.target.value }),
646
+ children: [
647
+ /* @__PURE__ */ jsx("option", { value: "auto", children: "Auto" }),
648
+ /* @__PURE__ */ jsx("option", { value: "top", children: "Top" }),
649
+ /* @__PURE__ */ jsx("option", { value: "bottom", children: "Bottom" }),
650
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
651
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
652
+ ]
653
+ }
654
+ )
655
+ ] }),
656
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "end", paddingBottom: 2 }, children: /* @__PURE__ */ jsxs("label", { style: { fontSize: 11, display: "flex", alignItems: "center", gap: 4 }, children: [
657
+ /* @__PURE__ */ jsx(
658
+ "input",
659
+ {
660
+ type: "checkbox",
661
+ checked: step.spotlight,
662
+ onChange: (e) => updateStep(step.id, { spotlight: e.target.checked })
663
+ }
664
+ ),
665
+ "Spotlight"
666
+ ] }) })
667
+ ] })
668
+ ]
669
+ }
670
+ )
671
+ ]
672
+ },
673
+ step.id
674
+ ))
675
+ ] })
676
+ ] }) : (
677
+ /* Tasks tab */
678
+ /* @__PURE__ */ jsxs("div", { style: S.section, children: [
679
+ loadingTasks ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: 16, color: "#9ca3af" }, children: "Loading..." }) : tasks.length === 0 ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: 16, color: "#9ca3af" }, children: "No tasks yet" }) : tasks.map((task) => /* @__PURE__ */ jsxs("div", { style: __spreadProps(__spreadValues({}, S.stepItem(false)), { display: "flex", justifyContent: "space-between", alignItems: "center" }), children: [
680
+ /* @__PURE__ */ jsxs("div", { children: [
681
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 500, fontSize: 12 }, children: task.name }),
682
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 10, color: "#9ca3af" }, children: [
683
+ task.slug,
684
+ " \xB7 ",
685
+ task.steps.length,
686
+ " steps"
687
+ ] })
688
+ ] }),
689
+ /* @__PURE__ */ jsx(
690
+ "button",
691
+ {
692
+ style: S.btn("#111"),
693
+ onClick: () => {
694
+ if (window.ontheway) {
695
+ window.ontheway.start(task.slug);
696
+ }
697
+ },
698
+ children: "\u25B6"
699
+ }
700
+ )
701
+ ] }, task.id)),
702
+ /* @__PURE__ */ jsx("button", { style: __spreadProps(__spreadValues({}, S.btnOutline), { width: "100%", marginTop: 8 }), onClick: fetchTasks, children: "\u21BB Refresh" })
703
+ ] })
704
+ ) })
705
+ ] }) });
706
+ }
707
+ var OnTheWayDevTools = {
708
+ init(config) {
709
+ if (typeof window === "undefined") return;
710
+ if (typeof document === "undefined") return;
711
+ console.log(
712
+ "%c\u{1F6E4}\uFE0F OnTheWay DevTools %c Use <OnTheWayDevToolsPanel /> in React, or import the standalone recorder-snippet.js",
713
+ "background:#22c55e;color:#fff;padding:4px 8px;border-radius:4px;font-weight:bold",
714
+ "color:#666"
715
+ );
716
+ const script = document.createElement("script");
717
+ script.src = (config.serverUrl || "") + "/recorder-snippet.js";
718
+ script.dataset.session = "devtools_" + Date.now().toString(36);
719
+ script.dataset.server = config.serverUrl || window.location.origin;
720
+ document.head.appendChild(script);
721
+ }
722
+ };
723
+ var devtools_default = OnTheWayDevToolsPanel;
724
+
725
+ export { OnTheWayDevTools, OnTheWayDevToolsPanel, devtools_default as default };
726
+ //# sourceMappingURL=devtools.js.map
727
+ //# sourceMappingURL=devtools.js.map