@bitovi/vybit 0.8.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,523 @@
1
1
  "use strict";
2
2
  (() => {
3
+ // overlay/src/ws.ts
4
+ var socket = null;
5
+ var connected = false;
6
+ var handlers = [];
7
+ function connect(url = "ws://localhost:3333") {
8
+ socket = new WebSocket(url);
9
+ socket.addEventListener("open", () => {
10
+ connected = true;
11
+ send({ type: "REGISTER", role: "overlay" });
12
+ window.dispatchEvent(new CustomEvent("overlay-ws-connected"));
13
+ });
14
+ socket.addEventListener("close", () => {
15
+ connected = false;
16
+ socket = null;
17
+ window.dispatchEvent(new CustomEvent("overlay-ws-disconnected"));
18
+ setTimeout(() => connect(url), 3e3);
19
+ });
20
+ socket.addEventListener("message", (event) => {
21
+ try {
22
+ const data = JSON.parse(event.data);
23
+ for (const handler of handlers) {
24
+ handler(data);
25
+ }
26
+ } catch (err) {
27
+ console.error("[tw-overlay] Failed to parse message:", err);
28
+ }
29
+ });
30
+ socket.addEventListener("error", (err) => {
31
+ console.error("[tw-overlay] WebSocket error:", err);
32
+ });
33
+ }
34
+ function send(data) {
35
+ if (connected && socket) {
36
+ socket.send(JSON.stringify(data));
37
+ } else {
38
+ console.warn("[tw-overlay] Cannot send \u2014 not connected");
39
+ }
40
+ }
41
+ function onMessage(handler) {
42
+ handlers.push(handler);
43
+ }
44
+ function sendTo(role, data) {
45
+ send({ ...data, to: role });
46
+ }
47
+ window.addEventListener("message", (event) => {
48
+ if (event.data?.type === "STORYBOOK_STORY_RENDERED") {
49
+ send({ type: "RESET_SELECTION" });
50
+ }
51
+ });
52
+
53
+ // overlay/src/context.ts
54
+ function buildContext(target, oldClass, newClass, originalClassMap) {
55
+ const ancestors = [];
56
+ let current = target;
57
+ while (current && current !== document.documentElement) {
58
+ ancestors.push(current);
59
+ current = current.parentElement;
60
+ }
61
+ ancestors.reverse();
62
+ return buildLevel(ancestors, 0, target, oldClass, newClass, originalClassMap, 0);
63
+ }
64
+ function buildLevel(ancestors, ancestorIndex, target, oldClass, newClass, originalClassMap, indent) {
65
+ const el = ancestors[ancestorIndex];
66
+ const pad = " ".repeat(indent);
67
+ const tag = el.tagName.toLowerCase();
68
+ let attrs = "";
69
+ if (el.id) attrs += ` id="${el.id}"`;
70
+ const originalClass = originalClassMap.get(el);
71
+ const classStr = originalClass != null ? originalClass.trim() : typeof el.className === "string" ? el.className.trim() : "";
72
+ if (classStr) {
73
+ attrs += ` class="${classStr}"`;
74
+ }
75
+ const isTarget = el === target;
76
+ if (isTarget) {
77
+ const text = getInnerText(el);
78
+ const textNode = text ? `
79
+ ${pad} ${text}` : "";
80
+ return `${pad}<${tag}${attrs}> <!-- TARGET: change ${oldClass} \u2192 ${newClass} -->${textNode}
81
+ ${pad}</${tag}>`;
82
+ }
83
+ if (ancestorIndex >= ancestors.length - 1) {
84
+ return `${pad}<${tag}${attrs} />`;
85
+ }
86
+ const nextAncestor = ancestors[ancestorIndex + 1];
87
+ const children = Array.from(el.children);
88
+ const relevantIndex = children.indexOf(nextAncestor);
89
+ let inner = "";
90
+ if (relevantIndex === -1) {
91
+ inner = buildLevel(ancestors, ancestorIndex + 1, target, oldClass, newClass, originalClassMap, indent + 1);
92
+ } else {
93
+ const start = Math.max(0, relevantIndex - 3);
94
+ const end = Math.min(children.length - 1, relevantIndex + 3);
95
+ if (start > 0) {
96
+ inner += `${pad} ...
97
+ `;
98
+ }
99
+ for (let i = start; i <= end; i++) {
100
+ if (i === relevantIndex) {
101
+ inner += buildLevel(ancestors, ancestorIndex + 1, target, oldClass, newClass, originalClassMap, indent + 1) + "\n";
102
+ } else {
103
+ inner += renderSiblingNode(children[i], indent + 1, originalClassMap) + "\n";
104
+ }
105
+ }
106
+ if (end < children.length - 1) {
107
+ inner += `${pad} ...
108
+ `;
109
+ }
110
+ }
111
+ return `${pad}<${tag}${attrs}>
112
+ ${inner}${pad}</${tag}>`;
113
+ }
114
+ function renderSiblingNode(el, indent, originalClassMap) {
115
+ const pad = " ".repeat(indent);
116
+ const tag = el.tagName.toLowerCase();
117
+ let attrs = "";
118
+ if (el.id) attrs += ` id="${el.id}"`;
119
+ const originalClass = originalClassMap.get(el);
120
+ const classStr = originalClass != null ? originalClass.trim() : typeof el.className === "string" ? el.className.trim() : "";
121
+ if (classStr) {
122
+ attrs += ` class="${classStr}"`;
123
+ }
124
+ const text = getInnerText(el);
125
+ if (!el.id && (!el.className || !el.className.trim()) && !text) {
126
+ return `${pad}<${tag}>...</${tag}>`;
127
+ }
128
+ if (text) {
129
+ return `${pad}<${tag}${attrs}>
130
+ ${pad} ${text}
131
+ ${pad}</${tag}>`;
132
+ }
133
+ if (el.children.length > 0) {
134
+ return `${pad}<${tag}${attrs}>
135
+ ${pad} ...
136
+ ${pad}</${tag}>`;
137
+ }
138
+ return `${pad}<${tag}${attrs} />`;
139
+ }
140
+ function getInnerText(el) {
141
+ let text = "";
142
+ for (const node of Array.from(el.childNodes)) {
143
+ if (node.nodeType === Node.TEXT_NODE) {
144
+ text += node.textContent || "";
145
+ }
146
+ }
147
+ text = text.trim();
148
+ if (text.length > 60) text = text.slice(0, 57) + "...";
149
+ return text;
150
+ }
151
+
152
+ // overlay/src/fiber.ts
153
+ function getFiber(domNode) {
154
+ const key = Object.keys(domNode).find((k) => k.startsWith("__reactFiber$"));
155
+ return key ? domNode[key] : null;
156
+ }
157
+ function findComponentBoundary(fiber) {
158
+ let current = fiber.return;
159
+ while (current) {
160
+ if (typeof current.type === "function") {
161
+ return {
162
+ componentType: current.type,
163
+ componentName: current.type.displayName || current.type.name || "Unknown",
164
+ componentFiber: current
165
+ };
166
+ }
167
+ current = current.return;
168
+ }
169
+ return null;
170
+ }
171
+ function getRootFiber() {
172
+ const candidateIds = ["root", "app", "__next"];
173
+ for (const id of candidateIds) {
174
+ const el = document.getElementById(id);
175
+ if (!el) continue;
176
+ const key = Object.keys(el).find((k) => k.startsWith("__reactContainer$"));
177
+ if (key) {
178
+ const container = el[key];
179
+ if (container?.stateNode?.current) {
180
+ return container.stateNode.current;
181
+ }
182
+ return container;
183
+ }
184
+ }
185
+ const reactRoot = document.querySelector("[data-reactroot]");
186
+ if (reactRoot) {
187
+ return getFiber(reactRoot);
188
+ }
189
+ return null;
190
+ }
191
+ function findAllInstances(rootFiber, componentType) {
192
+ const results = [];
193
+ function walk(fiber) {
194
+ if (!fiber) return;
195
+ if (fiber.type === componentType) {
196
+ results.push(fiber);
197
+ }
198
+ walk(fiber.child);
199
+ walk(fiber.sibling);
200
+ }
201
+ walk(rootFiber);
202
+ return results;
203
+ }
204
+
205
+ // overlay/src/drop-zone.ts
206
+ var active = false;
207
+ var componentName = "";
208
+ var storyId = "";
209
+ var ghostHtml = "";
210
+ var componentPath = "";
211
+ var componentArgs = {};
212
+ var cursorLabelEl = null;
213
+ var indicatorEl = null;
214
+ var arrowLeftEl = null;
215
+ var arrowRightEl = null;
216
+ var currentTarget = null;
217
+ var currentPosition = null;
218
+ var overlayHost = null;
219
+ var TEAL = "#00848B";
220
+ function armInsert(msg, shadowHost2) {
221
+ if (active) cleanup();
222
+ active = true;
223
+ componentName = msg.componentName;
224
+ storyId = msg.storyId;
225
+ ghostHtml = msg.ghostHtml;
226
+ componentPath = msg.componentPath ?? "";
227
+ componentArgs = msg.args ?? {};
228
+ overlayHost = shadowHost2;
229
+ document.documentElement.style.cursor = "crosshair";
230
+ cursorLabelEl = document.createElement("div");
231
+ cursorLabelEl.style.cssText = `position:fixed;pointer-events:none;z-index:2147483647;background:${TEAL};color:#fff;font-size:11px;font-family:system-ui,sans-serif;padding:3px 8px;border-radius:4px;white-space:nowrap;opacity:0;box-shadow:0 2px 6px rgba(0,0,0,0.3);transition:opacity 0.1s;`;
232
+ cursorLabelEl.textContent = `Place: ${componentName}`;
233
+ document.body.appendChild(cursorLabelEl);
234
+ indicatorEl = document.createElement("div");
235
+ indicatorEl.style.cssText = "position:fixed;pointer-events:none;z-index:2147483645;display:none;";
236
+ document.body.appendChild(indicatorEl);
237
+ document.addEventListener("mousemove", onMouseMove);
238
+ document.documentElement.addEventListener("mouseleave", onMouseLeave);
239
+ document.addEventListener("click", onClick, true);
240
+ document.addEventListener("keydown", onKeyDown);
241
+ }
242
+ function cancelInsert() {
243
+ cleanup();
244
+ }
245
+ function getAxis(el) {
246
+ const style = getComputedStyle(el);
247
+ if (style.display.includes("flex")) {
248
+ return style.flexDirection.startsWith("row") ? "horizontal" : "vertical";
249
+ }
250
+ if (style.display.includes("grid")) {
251
+ return style.gridAutoFlow.startsWith("column") ? "horizontal" : "vertical";
252
+ }
253
+ return "vertical";
254
+ }
255
+ function computeDropPosition(cursor, rect, axis) {
256
+ const ratio = axis === "horizontal" ? (cursor.x - rect.left) / rect.width : (cursor.y - rect.top) / rect.height;
257
+ if (ratio < 0.25) return "before";
258
+ if (ratio < 0.5) return "first-child";
259
+ if (ratio < 0.75) return "last-child";
260
+ return "after";
261
+ }
262
+ function findTarget(x, y) {
263
+ if (indicatorEl) indicatorEl.style.display = "none";
264
+ const el = document.elementFromPoint(x, y);
265
+ if (indicatorEl) indicatorEl.style.display = "";
266
+ if (!el || el === document.documentElement || el === document.body) return null;
267
+ if (overlayHost && (el === overlayHost || overlayHost.contains(el))) return null;
268
+ if (indicatorEl && (el === indicatorEl || indicatorEl.contains(el))) return null;
269
+ return el;
270
+ }
271
+ function showIndicator(target, position, axis) {
272
+ if (!indicatorEl) return;
273
+ const rect = target.getBoundingClientRect();
274
+ const isInside = position === "first-child" || position === "last-child";
275
+ if (arrowLeftEl) {
276
+ arrowLeftEl.remove();
277
+ arrowLeftEl = null;
278
+ }
279
+ if (arrowRightEl) {
280
+ arrowRightEl.remove();
281
+ arrowRightEl = null;
282
+ }
283
+ if (isInside) {
284
+ indicatorEl.style.cssText = `position:fixed;pointer-events:none;z-index:2147483645;top:${rect.top}px;left:${rect.left}px;width:${rect.width}px;height:${rect.height}px;border:2px dashed ${TEAL};border-radius:4px;box-sizing:border-box;display:block;background:none;`;
285
+ const arrow2 = document.createElement("div");
286
+ arrow2.style.cssText = "position:absolute;width:0;height:0;border-style:solid;";
287
+ const size2 = 6;
288
+ const isVertical = axis === "vertical";
289
+ if (position === "first-child") {
290
+ if (isVertical) {
291
+ arrow2.style.top = "4px";
292
+ arrow2.style.left = "50%";
293
+ arrow2.style.transform = "translateX(-50%)";
294
+ arrow2.style.borderWidth = `${size2}px ${size2}px 0 ${size2}px`;
295
+ arrow2.style.borderColor = `${TEAL} transparent transparent transparent`;
296
+ } else {
297
+ arrow2.style.left = "4px";
298
+ arrow2.style.top = "50%";
299
+ arrow2.style.transform = "translateY(-50%)";
300
+ arrow2.style.borderWidth = `${size2}px 0 ${size2}px ${size2}px`;
301
+ arrow2.style.borderColor = `transparent transparent transparent ${TEAL}`;
302
+ }
303
+ } else {
304
+ if (isVertical) {
305
+ arrow2.style.bottom = "4px";
306
+ arrow2.style.left = "50%";
307
+ arrow2.style.transform = "translateX(-50%)";
308
+ arrow2.style.borderWidth = `0 ${size2}px ${size2}px ${size2}px`;
309
+ arrow2.style.borderColor = `transparent transparent ${TEAL} transparent`;
310
+ } else {
311
+ arrow2.style.right = "4px";
312
+ arrow2.style.top = "50%";
313
+ arrow2.style.transform = "translateY(-50%)";
314
+ arrow2.style.borderWidth = `${size2}px ${size2}px ${size2}px 0`;
315
+ arrow2.style.borderColor = `transparent ${TEAL} transparent transparent`;
316
+ }
317
+ }
318
+ indicatorEl.appendChild(arrow2);
319
+ arrowLeftEl = arrow2;
320
+ } else {
321
+ const lineWidth = 3;
322
+ const isHorizontalLine = axis === "vertical";
323
+ if (isHorizontalLine) {
324
+ const y = position === "before" ? rect.top : rect.bottom;
325
+ indicatorEl.style.cssText = `position:fixed;pointer-events:none;z-index:2147483645;display:block;top:${y - lineWidth / 2}px;left:${rect.left}px;width:${rect.width}px;height:${lineWidth}px;background:${TEAL};border-radius:${lineWidth}px;`;
326
+ } else {
327
+ const x = position === "before" ? rect.left : rect.right;
328
+ indicatorEl.style.cssText = `position:fixed;pointer-events:none;z-index:2147483645;display:block;top:${rect.top}px;left:${x - lineWidth / 2}px;width:${lineWidth}px;height:${rect.height}px;background:${TEAL};border-radius:${lineWidth}px;`;
329
+ }
330
+ const arrowSize = 5;
331
+ const inset = -2;
332
+ arrowLeftEl = document.createElement("div");
333
+ arrowLeftEl.style.cssText = "position:absolute;width:0;height:0;border-style:solid;";
334
+ arrowRightEl = document.createElement("div");
335
+ arrowRightEl.style.cssText = "position:absolute;width:0;height:0;border-style:solid;";
336
+ if (isHorizontalLine) {
337
+ arrowLeftEl.style.top = "50%";
338
+ arrowLeftEl.style.left = `${inset}px`;
339
+ arrowLeftEl.style.transform = "translateY(-50%)";
340
+ arrowLeftEl.style.borderWidth = `${arrowSize}px 0 ${arrowSize}px ${arrowSize}px`;
341
+ arrowLeftEl.style.borderColor = `transparent transparent transparent ${TEAL}`;
342
+ arrowRightEl.style.top = "50%";
343
+ arrowRightEl.style.right = `${inset}px`;
344
+ arrowRightEl.style.transform = "translateY(-50%)";
345
+ arrowRightEl.style.borderWidth = `${arrowSize}px ${arrowSize}px ${arrowSize}px 0`;
346
+ arrowRightEl.style.borderColor = `transparent ${TEAL} transparent transparent`;
347
+ } else {
348
+ arrowLeftEl.style.left = "50%";
349
+ arrowLeftEl.style.top = `${inset}px`;
350
+ arrowLeftEl.style.transform = "translateX(-50%)";
351
+ arrowLeftEl.style.borderWidth = `${arrowSize}px ${arrowSize}px 0 ${arrowSize}px`;
352
+ arrowLeftEl.style.borderColor = `${TEAL} transparent transparent transparent`;
353
+ arrowRightEl.style.left = "50%";
354
+ arrowRightEl.style.bottom = `${inset}px`;
355
+ arrowRightEl.style.transform = "translateX(-50%)";
356
+ arrowRightEl.style.borderWidth = `0 ${arrowSize}px ${arrowSize}px ${arrowSize}px`;
357
+ arrowRightEl.style.borderColor = `transparent transparent ${TEAL} transparent`;
358
+ }
359
+ indicatorEl.appendChild(arrowLeftEl);
360
+ indicatorEl.appendChild(arrowRightEl);
361
+ }
362
+ }
363
+ function hideIndicator() {
364
+ if (indicatorEl) indicatorEl.style.display = "none";
365
+ if (arrowLeftEl) {
366
+ arrowLeftEl.remove();
367
+ arrowLeftEl = null;
368
+ }
369
+ if (arrowRightEl) {
370
+ arrowRightEl.remove();
371
+ arrowRightEl = null;
372
+ }
373
+ currentTarget = null;
374
+ currentPosition = null;
375
+ }
376
+ function onMouseMove(e) {
377
+ if (!active) return;
378
+ if (cursorLabelEl) {
379
+ cursorLabelEl.style.left = `${e.clientX + 14}px`;
380
+ cursorLabelEl.style.top = `${e.clientY - 28}px`;
381
+ cursorLabelEl.style.opacity = "1";
382
+ }
383
+ const target = findTarget(e.clientX, e.clientY);
384
+ if (!target) {
385
+ hideIndicator();
386
+ return;
387
+ }
388
+ const parentAxis = target.parentElement ? getAxis(target.parentElement) : "vertical";
389
+ const rect = target.getBoundingClientRect();
390
+ const position = computeDropPosition(
391
+ { x: e.clientX, y: e.clientY },
392
+ rect,
393
+ parentAxis
394
+ );
395
+ currentTarget = target;
396
+ currentPosition = position;
397
+ showIndicator(target, position, parentAxis);
398
+ }
399
+ function onMouseLeave() {
400
+ hideIndicator();
401
+ if (cursorLabelEl) cursorLabelEl.style.opacity = "0";
402
+ }
403
+ function onClick(e) {
404
+ if (!active) return;
405
+ if (!currentTarget || !currentPosition) {
406
+ cleanup();
407
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
408
+ return;
409
+ }
410
+ e.preventDefault();
411
+ e.stopPropagation();
412
+ const template = document.createElement("template");
413
+ template.innerHTML = ghostHtml.trim();
414
+ const inserted = template.content.firstElementChild;
415
+ if (!inserted) {
416
+ cleanup();
417
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
418
+ return;
419
+ }
420
+ inserted.dataset.twDroppedComponent = componentName;
421
+ switch (currentPosition) {
422
+ case "before":
423
+ currentTarget.insertAdjacentElement("beforebegin", inserted);
424
+ break;
425
+ case "after":
426
+ currentTarget.insertAdjacentElement("afterend", inserted);
427
+ break;
428
+ case "first-child":
429
+ currentTarget.insertAdjacentElement("afterbegin", inserted);
430
+ break;
431
+ case "last-child":
432
+ currentTarget.appendChild(inserted);
433
+ break;
434
+ }
435
+ const targetSelector = buildSelector(currentTarget);
436
+ const isGhostTarget = !!currentTarget.dataset.twDroppedComponent;
437
+ const ghostTargetPatchId = currentTarget.dataset.twDroppedPatchId;
438
+ const ghostTargetName = currentTarget.dataset.twDroppedComponent;
439
+ const ghostAncestor = !isGhostTarget ? findGhostAncestor(currentTarget) : null;
440
+ const effectiveGhostName = isGhostTarget ? ghostTargetName : ghostAncestor?.dataset.twDroppedComponent;
441
+ const effectiveGhostPatchId = isGhostTarget ? ghostTargetPatchId : ghostAncestor?.dataset.twDroppedPatchId;
442
+ const context = effectiveGhostName ? `Place "${componentName}" ${currentPosition} the <${effectiveGhostName} /> component (pending insertion from an earlier drop)` : buildContext(currentTarget, "", "", /* @__PURE__ */ new Map());
443
+ let parentComponent;
444
+ const fiber = getFiber(currentTarget);
445
+ if (fiber) {
446
+ const boundary = findComponentBoundary(fiber);
447
+ if (boundary) {
448
+ parentComponent = { name: boundary.componentName };
449
+ }
450
+ }
451
+ const patch = {
452
+ id: crypto.randomUUID(),
453
+ kind: "component-drop",
454
+ elementKey: targetSelector,
455
+ status: "staged",
456
+ originalClass: "",
457
+ newClass: "",
458
+ property: "component-drop",
459
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
460
+ component: { name: componentName },
461
+ target: isGhostTarget ? { tag: ghostTargetName?.toLowerCase() ?? "unknown", classes: "", innerText: "" } : {
462
+ tag: currentTarget.tagName.toLowerCase(),
463
+ classes: currentTarget.className,
464
+ innerText: currentTarget.innerText.slice(0, 100)
465
+ },
466
+ ghostHtml,
467
+ componentStoryId: storyId,
468
+ componentPath: componentPath || void 0,
469
+ componentArgs: Object.keys(componentArgs).length > 0 ? componentArgs : void 0,
470
+ parentComponent,
471
+ insertMode: currentPosition,
472
+ context,
473
+ ...effectiveGhostPatchId ? { targetPatchId: effectiveGhostPatchId, targetComponentName: effectiveGhostName } : {}
474
+ };
475
+ inserted.dataset.twDroppedPatchId = patch.id;
476
+ send({ type: "COMPONENT_DROPPED", patch });
477
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
478
+ cleanup();
479
+ }
480
+ function onKeyDown(e) {
481
+ if (e.key === "Escape") {
482
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
483
+ cleanup();
484
+ }
485
+ }
486
+ function findGhostAncestor(el) {
487
+ let current = el.parentElement;
488
+ while (current && current !== document.body) {
489
+ if (current.dataset.twDroppedComponent) return current;
490
+ current = current.parentElement;
491
+ }
492
+ return null;
493
+ }
494
+ function buildSelector(el) {
495
+ const tag = el.tagName.toLowerCase();
496
+ if (el.id) return `#${el.id}`;
497
+ const classes = Array.from(el.classList).slice(0, 3).join(".");
498
+ return classes ? `${tag}.${classes}` : tag;
499
+ }
500
+ function cleanup() {
501
+ active = false;
502
+ document.documentElement.style.cursor = "";
503
+ document.removeEventListener("mousemove", onMouseMove);
504
+ document.documentElement.removeEventListener("mouseleave", onMouseLeave);
505
+ document.removeEventListener("click", onClick, true);
506
+ document.removeEventListener("keydown", onKeyDown);
507
+ if (cursorLabelEl) {
508
+ cursorLabelEl.remove();
509
+ cursorLabelEl = null;
510
+ }
511
+ if (indicatorEl) {
512
+ indicatorEl.remove();
513
+ indicatorEl = null;
514
+ }
515
+ arrowLeftEl = null;
516
+ arrowRightEl = null;
517
+ currentTarget = null;
518
+ currentPosition = null;
519
+ }
520
+
3
521
  // node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
4
522
  var min = Math.min;
5
523
  var max = Math.max;
@@ -1442,164 +1960,12 @@
1442
1960
  }
1443
1961
  };
1444
1962
 
1445
- // overlay/src/context.ts
1446
- function buildContext(target, oldClass, newClass, originalClassMap) {
1447
- const ancestors = [];
1448
- let current = target;
1449
- while (current && current !== document.documentElement) {
1450
- ancestors.push(current);
1451
- current = current.parentElement;
1452
- }
1453
- ancestors.reverse();
1454
- return buildLevel(ancestors, 0, target, oldClass, newClass, originalClassMap, 0);
1455
- }
1456
- function buildLevel(ancestors, ancestorIndex, target, oldClass, newClass, originalClassMap, indent) {
1457
- const el = ancestors[ancestorIndex];
1458
- const pad = " ".repeat(indent);
1459
- const tag = el.tagName.toLowerCase();
1460
- let attrs = "";
1461
- if (el.id) attrs += ` id="${el.id}"`;
1462
- const originalClass = originalClassMap.get(el);
1463
- const classStr = originalClass != null ? originalClass.trim() : typeof el.className === "string" ? el.className.trim() : "";
1464
- if (classStr) {
1465
- attrs += ` class="${classStr}"`;
1466
- }
1467
- const isTarget = el === target;
1468
- if (isTarget) {
1469
- const text = getInnerText(el);
1470
- const textNode = text ? `
1471
- ${pad} ${text}` : "";
1472
- return `${pad}<${tag}${attrs}> <!-- TARGET: change ${oldClass} \u2192 ${newClass} -->${textNode}
1473
- ${pad}</${tag}>`;
1474
- }
1475
- if (ancestorIndex >= ancestors.length - 1) {
1476
- return `${pad}<${tag}${attrs} />`;
1477
- }
1478
- const nextAncestor = ancestors[ancestorIndex + 1];
1479
- const children = Array.from(el.children);
1480
- const relevantIndex = children.indexOf(nextAncestor);
1481
- let inner = "";
1482
- if (relevantIndex === -1) {
1483
- inner = buildLevel(ancestors, ancestorIndex + 1, target, oldClass, newClass, originalClassMap, indent + 1);
1484
- } else {
1485
- const start = Math.max(0, relevantIndex - 3);
1486
- const end = Math.min(children.length - 1, relevantIndex + 3);
1487
- if (start > 0) {
1488
- inner += `${pad} ...
1489
- `;
1490
- }
1491
- for (let i = start; i <= end; i++) {
1492
- if (i === relevantIndex) {
1493
- inner += buildLevel(ancestors, ancestorIndex + 1, target, oldClass, newClass, originalClassMap, indent + 1) + "\n";
1494
- } else {
1495
- inner += renderSiblingNode(children[i], indent + 1, originalClassMap) + "\n";
1496
- }
1497
- }
1498
- if (end < children.length - 1) {
1499
- inner += `${pad} ...
1500
- `;
1501
- }
1502
- }
1503
- return `${pad}<${tag}${attrs}>
1504
- ${inner}${pad}</${tag}>`;
1505
- }
1506
- function renderSiblingNode(el, indent, originalClassMap) {
1507
- const pad = " ".repeat(indent);
1508
- const tag = el.tagName.toLowerCase();
1509
- let attrs = "";
1510
- if (el.id) attrs += ` id="${el.id}"`;
1511
- const originalClass = originalClassMap.get(el);
1512
- const classStr = originalClass != null ? originalClass.trim() : typeof el.className === "string" ? el.className.trim() : "";
1513
- if (classStr) {
1514
- attrs += ` class="${classStr}"`;
1515
- }
1516
- const text = getInnerText(el);
1517
- if (!el.id && (!el.className || !el.className.trim()) && !text) {
1518
- return `${pad}<${tag}>...</${tag}>`;
1519
- }
1520
- if (text) {
1521
- return `${pad}<${tag}${attrs}>
1522
- ${pad} ${text}
1523
- ${pad}</${tag}>`;
1524
- }
1525
- if (el.children.length > 0) {
1526
- return `${pad}<${tag}${attrs}>
1527
- ${pad} ...
1528
- ${pad}</${tag}>`;
1529
- }
1530
- return `${pad}<${tag}${attrs} />`;
1531
- }
1532
- function getInnerText(el) {
1533
- let text = "";
1534
- for (const node of Array.from(el.childNodes)) {
1535
- if (node.nodeType === Node.TEXT_NODE) {
1536
- text += node.textContent || "";
1537
- }
1538
- }
1539
- text = text.trim();
1540
- if (text.length > 60) text = text.slice(0, 57) + "...";
1541
- return text;
1542
- }
1543
-
1544
- // overlay/src/fiber.ts
1545
- function getFiber(domNode) {
1546
- const key = Object.keys(domNode).find((k) => k.startsWith("__reactFiber$"));
1547
- return key ? domNode[key] : null;
1548
- }
1549
- function findComponentBoundary(fiber) {
1550
- let current = fiber.return;
1551
- while (current) {
1552
- if (typeof current.type === "function") {
1553
- return {
1554
- componentType: current.type,
1555
- componentName: current.type.displayName || current.type.name || "Unknown",
1556
- componentFiber: current
1557
- };
1558
- }
1559
- current = current.return;
1560
- }
1561
- return null;
1562
- }
1563
- function getRootFiber() {
1564
- const candidateIds = ["root", "app", "__next"];
1565
- for (const id of candidateIds) {
1566
- const el = document.getElementById(id);
1567
- if (!el) continue;
1568
- const key = Object.keys(el).find((k) => k.startsWith("__reactContainer$"));
1569
- if (key) {
1570
- const container = el[key];
1571
- if (container?.stateNode?.current) {
1572
- return container.stateNode.current;
1573
- }
1574
- return container;
1575
- }
1576
- }
1577
- const reactRoot = document.querySelector("[data-reactroot]");
1578
- if (reactRoot) {
1579
- return getFiber(reactRoot);
1580
- }
1581
- return null;
1582
- }
1583
- function findAllInstances(rootFiber, componentType) {
1584
- const results = [];
1585
- function walk(fiber) {
1586
- if (!fiber) return;
1587
- if (fiber.type === componentType) {
1588
- results.push(fiber);
1589
- }
1590
- walk(fiber.child);
1591
- walk(fiber.sibling);
1592
- }
1593
- walk(rootFiber);
1594
- return results;
1595
- }
1596
-
1597
1963
  // overlay/src/grouping.ts
1598
1964
  function cssEscape(cls) {
1599
1965
  if (typeof CSS !== "undefined" && CSS.escape) return CSS.escape(cls);
1600
1966
  return cls.replace(/([^\w-])/g, "\\$1");
1601
1967
  }
1602
- function buildSelector(tag, classes) {
1968
+ function buildSelector2(tag, classes) {
1603
1969
  return tag.toLowerCase() + classes.map((c) => `.${cssEscape(c)}`).join("");
1604
1970
  }
1605
1971
  function parseClassList(className) {
@@ -1632,7 +1998,7 @@ ${pad}</${tag}>`;
1632
1998
  const tag = clickedEl.tagName;
1633
1999
  const fiber = getFiber(clickedEl);
1634
2000
  const boundary = fiber ? findComponentBoundary(fiber) : null;
1635
- const componentName = boundary?.componentName ?? null;
2001
+ const componentName2 = boundary?.componentName ?? null;
1636
2002
  let exactMatches;
1637
2003
  if (boundary) {
1638
2004
  const rootFiber = getRootFiber();
@@ -1648,7 +2014,7 @@ ${pad}</${tag}>`;
1648
2014
  (n) => (typeof n.className === "string" ? n.className.trim() : "") === "" && !isInShadowHost(n, shadowHost2)
1649
2015
  );
1650
2016
  } else {
1651
- const selector = buildSelector(tag, classes);
2017
+ const selector = buildSelector2(tag, classes);
1652
2018
  exactMatches = Array.from(
1653
2019
  document.querySelectorAll(selector)
1654
2020
  ).filter(
@@ -1663,7 +2029,7 @@ ${pad}</${tag}>`;
1663
2029
  exactMatch: exactMatches,
1664
2030
  nearGroups: [],
1665
2031
  // Not computed yet — lazy
1666
- componentName
2032
+ componentName: componentName2
1667
2033
  };
1668
2034
  }
1669
2035
  function computeNearGroups(clickedEl, exactMatchSet, shadowHost2) {
@@ -2703,55 +3069,10 @@ ${pad}</${tag}>`;
2703
3069
  }
2704
3070
  }
2705
3071
 
2706
- // overlay/src/ws.ts
2707
- var socket = null;
2708
- var connected = false;
2709
- var handlers = [];
2710
- function connect(url = "ws://localhost:3333") {
2711
- socket = new WebSocket(url);
2712
- socket.addEventListener("open", () => {
2713
- connected = true;
2714
- send({ type: "REGISTER", role: "overlay" });
2715
- window.dispatchEvent(new CustomEvent("overlay-ws-connected"));
2716
- });
2717
- socket.addEventListener("close", () => {
2718
- connected = false;
2719
- socket = null;
2720
- window.dispatchEvent(new CustomEvent("overlay-ws-disconnected"));
2721
- setTimeout(() => connect(url), 3e3);
2722
- });
2723
- socket.addEventListener("message", (event) => {
2724
- try {
2725
- const data = JSON.parse(event.data);
2726
- for (const handler of handlers) {
2727
- handler(data);
2728
- }
2729
- } catch (err) {
2730
- console.error("[tw-overlay] Failed to parse message:", err);
2731
- }
2732
- });
2733
- socket.addEventListener("error", (err) => {
2734
- console.error("[tw-overlay] WebSocket error:", err);
2735
- });
2736
- }
2737
- function send(data) {
2738
- if (connected && socket) {
2739
- socket.send(JSON.stringify(data));
2740
- } else {
2741
- console.warn("[tw-overlay] Cannot send \u2014 not connected");
2742
- }
2743
- }
2744
- function onMessage(handler) {
2745
- handlers.push(handler);
2746
- }
2747
- function sendTo(role, data) {
2748
- send({ ...data, to: role });
2749
- }
2750
-
2751
3072
  // overlay/src/index.ts
2752
3073
  var shadowRoot;
2753
3074
  var shadowHost;
2754
- var active = false;
3075
+ var active2 = false;
2755
3076
  var wasConnected = false;
2756
3077
  var tailwindConfigCache = null;
2757
3078
  var currentEquivalentNodes = [];
@@ -3210,7 +3531,7 @@ ${pad}</${tag}>`;
3210
3531
  hoverTooltipEl = null;
3211
3532
  lastHoveredEl = null;
3212
3533
  }
3213
- function showHoverPreview(el, componentName) {
3534
+ function showHoverPreview(el, componentName2) {
3214
3535
  const rect = el.getBoundingClientRect();
3215
3536
  if (!hoverOutlineEl) {
3216
3537
  hoverOutlineEl = document.createElement("div");
@@ -3228,7 +3549,7 @@ ${pad}</${tag}>`;
3228
3549
  }
3229
3550
  const tag = el.tagName.toLowerCase();
3230
3551
  const cls = (typeof el.className === "string" ? el.className.trim().split(/\s+/)[0] : "") ?? "";
3231
- hoverTooltipEl.innerHTML = `<span class="ht-dim">&lt;</span>${componentName}<span class="ht-dim">&gt;</span> <span class="ht-dim">${tag}${cls ? `.${cls}` : ""}</span>`;
3552
+ hoverTooltipEl.innerHTML = `<span class="ht-dim">&lt;</span>${componentName2}<span class="ht-dim">&gt;</span> <span class="ht-dim">${tag}${cls ? `.${cls}` : ""}</span>`;
3232
3553
  const tooltipHeight = 24;
3233
3554
  const ttTop = rect.top - tooltipHeight - 6;
3234
3555
  hoverTooltipEl.style.top = `${ttTop < 4 ? rect.bottom + 6 : ttTop}px`;
@@ -3584,7 +3905,7 @@ ${pad}</${tag}>`;
3584
3905
  const targetEl = target;
3585
3906
  const classString = typeof targetEl.className === "string" ? targetEl.className : "";
3586
3907
  const result = findExactMatches(targetEl, shadowHost);
3587
- const componentName = result.componentName ?? targetEl.tagName.toLowerCase();
3908
+ const componentName2 = result.componentName ?? targetEl.tagName.toLowerCase();
3588
3909
  clearHighlights();
3589
3910
  for (const node of result.exactMatch) {
3590
3911
  highlightElement(node);
@@ -3592,7 +3913,7 @@ ${pad}</${tag}>`;
3592
3913
  const config = await fetchTailwindConfig();
3593
3914
  currentEquivalentNodes = result.exactMatch;
3594
3915
  currentTargetEl = targetEl;
3595
- currentBoundary = { componentName };
3916
+ currentBoundary = { componentName: componentName2 };
3596
3917
  cachedNearGroups = null;
3597
3918
  currentInstances = result.exactMatch.map((node, i) => ({
3598
3919
  index: i,
@@ -3608,7 +3929,7 @@ ${pad}</${tag}>`;
3608
3929
  }
3609
3930
  sendTo("panel", {
3610
3931
  type: "ELEMENT_SELECTED",
3611
- componentName,
3932
+ componentName: componentName2,
3612
3933
  instanceCount: result.exactMatch.length,
3613
3934
  classes: classString,
3614
3935
  tailwindConfig: config
@@ -3629,8 +3950,8 @@ ${pad}</${tag}>`;
3629
3950
  }
3630
3951
  var PANEL_OPEN_KEY = "tw-inspector-panel-open";
3631
3952
  function toggleInspect(btn) {
3632
- active = !active;
3633
- if (active) {
3953
+ active2 = !active2;
3954
+ if (active2) {
3634
3955
  btn.classList.add("active");
3635
3956
  sessionStorage.setItem(PANEL_OPEN_KEY, "1");
3636
3957
  const panelUrl = `${SERVER_ORIGIN}/panel`;
@@ -3721,12 +4042,14 @@ ${pad}</${tag}>`;
3721
4042
  wrapper.style.height = `${newHeight}px`;
3722
4043
  };
3723
4044
  const onResizeUp = () => {
4045
+ iframe.style.pointerEvents = "";
3724
4046
  document.removeEventListener("mousemove", onResizeMove);
3725
4047
  document.removeEventListener("mouseup", onResizeUp);
3726
4048
  document.documentElement.style.cursor = "";
3727
4049
  };
3728
4050
  resizeHandle.addEventListener("mousedown", (e) => {
3729
4051
  e.preventDefault();
4052
+ iframe.style.pointerEvents = "none";
3730
4053
  startY = e.clientY;
3731
4054
  startHeight = wrapper.offsetHeight;
3732
4055
  document.documentElement.style.cursor = "ns-resize";
@@ -3766,12 +4089,14 @@ ${pad}</${tag}>`;
3766
4089
  wrapper.style.height = `${Math.max(150, cornerStartHeight + dh)}px`;
3767
4090
  };
3768
4091
  const onCornerUp = () => {
4092
+ iframe.style.pointerEvents = "";
3769
4093
  document.removeEventListener("mousemove", onCornerMove);
3770
4094
  document.removeEventListener("mouseup", onCornerUp);
3771
4095
  document.documentElement.style.cursor = "";
3772
4096
  };
3773
4097
  cornerHandle.addEventListener("mousedown", (e) => {
3774
4098
  e.preventDefault();
4099
+ iframe.style.pointerEvents = "none";
3775
4100
  cornerStartX = e.clientX;
3776
4101
  cornerStartY = e.clientY;
3777
4102
  cornerStartWidth = wrapper.offsetWidth;
@@ -4068,7 +4393,11 @@ ${pad}</${tag}>`;
4068
4393
  }
4069
4394
  }
4070
4395
  } else if (msg.type === "CLOSE_PANEL") {
4071
- if (active) toggleInspect(btn);
4396
+ if (active2) toggleInspect(btn);
4397
+ } else if (msg.type === "COMPONENT_ARM") {
4398
+ armInsert(msg, shadowHost);
4399
+ } else if (msg.type === "COMPONENT_DISARM") {
4400
+ cancelInsert();
4072
4401
  } else if (msg.type === "DESIGN_CLOSE") {
4073
4402
  const last = designCanvasWrappers.pop();
4074
4403
  if (last) {
@@ -4114,7 +4443,7 @@ ${pad}</${tag}>`;
4114
4443
  { capture: true, passive: true }
4115
4444
  );
4116
4445
  if (sessionStorage.getItem(PANEL_OPEN_KEY) === "1") {
4117
- active = true;
4446
+ active2 = true;
4118
4447
  btn.classList.add("active");
4119
4448
  activeContainer.open(`${SERVER_ORIGIN}/panel`);
4120
4449
  }