@bitovi/vybit 0.8.1 → 0.9.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.
@@ -1,5 +1,518 @@
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
+
48
+ // overlay/src/context.ts
49
+ function buildContext(target, oldClass, newClass, originalClassMap) {
50
+ const ancestors = [];
51
+ let current = target;
52
+ while (current && current !== document.documentElement) {
53
+ ancestors.push(current);
54
+ current = current.parentElement;
55
+ }
56
+ ancestors.reverse();
57
+ return buildLevel(ancestors, 0, target, oldClass, newClass, originalClassMap, 0);
58
+ }
59
+ function buildLevel(ancestors, ancestorIndex, target, oldClass, newClass, originalClassMap, indent) {
60
+ const el = ancestors[ancestorIndex];
61
+ const pad = " ".repeat(indent);
62
+ const tag = el.tagName.toLowerCase();
63
+ let attrs = "";
64
+ if (el.id) attrs += ` id="${el.id}"`;
65
+ const originalClass = originalClassMap.get(el);
66
+ const classStr = originalClass != null ? originalClass.trim() : typeof el.className === "string" ? el.className.trim() : "";
67
+ if (classStr) {
68
+ attrs += ` class="${classStr}"`;
69
+ }
70
+ const isTarget = el === target;
71
+ if (isTarget) {
72
+ const text = getInnerText(el);
73
+ const textNode = text ? `
74
+ ${pad} ${text}` : "";
75
+ return `${pad}<${tag}${attrs}> <!-- TARGET: change ${oldClass} \u2192 ${newClass} -->${textNode}
76
+ ${pad}</${tag}>`;
77
+ }
78
+ if (ancestorIndex >= ancestors.length - 1) {
79
+ return `${pad}<${tag}${attrs} />`;
80
+ }
81
+ const nextAncestor = ancestors[ancestorIndex + 1];
82
+ const children = Array.from(el.children);
83
+ const relevantIndex = children.indexOf(nextAncestor);
84
+ let inner = "";
85
+ if (relevantIndex === -1) {
86
+ inner = buildLevel(ancestors, ancestorIndex + 1, target, oldClass, newClass, originalClassMap, indent + 1);
87
+ } else {
88
+ const start = Math.max(0, relevantIndex - 3);
89
+ const end = Math.min(children.length - 1, relevantIndex + 3);
90
+ if (start > 0) {
91
+ inner += `${pad} ...
92
+ `;
93
+ }
94
+ for (let i = start; i <= end; i++) {
95
+ if (i === relevantIndex) {
96
+ inner += buildLevel(ancestors, ancestorIndex + 1, target, oldClass, newClass, originalClassMap, indent + 1) + "\n";
97
+ } else {
98
+ inner += renderSiblingNode(children[i], indent + 1, originalClassMap) + "\n";
99
+ }
100
+ }
101
+ if (end < children.length - 1) {
102
+ inner += `${pad} ...
103
+ `;
104
+ }
105
+ }
106
+ return `${pad}<${tag}${attrs}>
107
+ ${inner}${pad}</${tag}>`;
108
+ }
109
+ function renderSiblingNode(el, indent, originalClassMap) {
110
+ const pad = " ".repeat(indent);
111
+ const tag = el.tagName.toLowerCase();
112
+ let attrs = "";
113
+ if (el.id) attrs += ` id="${el.id}"`;
114
+ const originalClass = originalClassMap.get(el);
115
+ const classStr = originalClass != null ? originalClass.trim() : typeof el.className === "string" ? el.className.trim() : "";
116
+ if (classStr) {
117
+ attrs += ` class="${classStr}"`;
118
+ }
119
+ const text = getInnerText(el);
120
+ if (!el.id && (!el.className || !el.className.trim()) && !text) {
121
+ return `${pad}<${tag}>...</${tag}>`;
122
+ }
123
+ if (text) {
124
+ return `${pad}<${tag}${attrs}>
125
+ ${pad} ${text}
126
+ ${pad}</${tag}>`;
127
+ }
128
+ if (el.children.length > 0) {
129
+ return `${pad}<${tag}${attrs}>
130
+ ${pad} ...
131
+ ${pad}</${tag}>`;
132
+ }
133
+ return `${pad}<${tag}${attrs} />`;
134
+ }
135
+ function getInnerText(el) {
136
+ let text = "";
137
+ for (const node of Array.from(el.childNodes)) {
138
+ if (node.nodeType === Node.TEXT_NODE) {
139
+ text += node.textContent || "";
140
+ }
141
+ }
142
+ text = text.trim();
143
+ if (text.length > 60) text = text.slice(0, 57) + "...";
144
+ return text;
145
+ }
146
+
147
+ // overlay/src/fiber.ts
148
+ function getFiber(domNode) {
149
+ const key = Object.keys(domNode).find((k) => k.startsWith("__reactFiber$"));
150
+ return key ? domNode[key] : null;
151
+ }
152
+ function findComponentBoundary(fiber) {
153
+ let current = fiber.return;
154
+ while (current) {
155
+ if (typeof current.type === "function") {
156
+ return {
157
+ componentType: current.type,
158
+ componentName: current.type.displayName || current.type.name || "Unknown",
159
+ componentFiber: current
160
+ };
161
+ }
162
+ current = current.return;
163
+ }
164
+ return null;
165
+ }
166
+ function getRootFiber() {
167
+ const candidateIds = ["root", "app", "__next"];
168
+ for (const id of candidateIds) {
169
+ const el = document.getElementById(id);
170
+ if (!el) continue;
171
+ const key = Object.keys(el).find((k) => k.startsWith("__reactContainer$"));
172
+ if (key) {
173
+ const container = el[key];
174
+ if (container?.stateNode?.current) {
175
+ return container.stateNode.current;
176
+ }
177
+ return container;
178
+ }
179
+ }
180
+ const reactRoot = document.querySelector("[data-reactroot]");
181
+ if (reactRoot) {
182
+ return getFiber(reactRoot);
183
+ }
184
+ return null;
185
+ }
186
+ function findAllInstances(rootFiber, componentType) {
187
+ const results = [];
188
+ function walk(fiber) {
189
+ if (!fiber) return;
190
+ if (fiber.type === componentType) {
191
+ results.push(fiber);
192
+ }
193
+ walk(fiber.child);
194
+ walk(fiber.sibling);
195
+ }
196
+ walk(rootFiber);
197
+ return results;
198
+ }
199
+
200
+ // overlay/src/drop-zone.ts
201
+ var active = false;
202
+ var componentName = "";
203
+ var storyId = "";
204
+ var ghostHtml = "";
205
+ var componentPath = "";
206
+ var componentArgs = {};
207
+ var cursorLabelEl = null;
208
+ var indicatorEl = null;
209
+ var arrowLeftEl = null;
210
+ var arrowRightEl = null;
211
+ var currentTarget = null;
212
+ var currentPosition = null;
213
+ var overlayHost = null;
214
+ var TEAL = "#00848B";
215
+ function armInsert(msg, shadowHost2) {
216
+ if (active) cleanup();
217
+ active = true;
218
+ componentName = msg.componentName;
219
+ storyId = msg.storyId;
220
+ ghostHtml = msg.ghostHtml;
221
+ componentPath = msg.componentPath ?? "";
222
+ componentArgs = msg.args ?? {};
223
+ overlayHost = shadowHost2;
224
+ document.documentElement.style.cursor = "crosshair";
225
+ cursorLabelEl = document.createElement("div");
226
+ 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;`;
227
+ cursorLabelEl.textContent = `Place: ${componentName}`;
228
+ document.body.appendChild(cursorLabelEl);
229
+ indicatorEl = document.createElement("div");
230
+ indicatorEl.style.cssText = "position:fixed;pointer-events:none;z-index:2147483645;display:none;";
231
+ document.body.appendChild(indicatorEl);
232
+ document.addEventListener("mousemove", onMouseMove);
233
+ document.documentElement.addEventListener("mouseleave", onMouseLeave);
234
+ document.addEventListener("click", onClick, true);
235
+ document.addEventListener("keydown", onKeyDown);
236
+ }
237
+ function cancelInsert() {
238
+ cleanup();
239
+ }
240
+ function getAxis(el) {
241
+ const style = getComputedStyle(el);
242
+ if (style.display.includes("flex")) {
243
+ return style.flexDirection.startsWith("row") ? "horizontal" : "vertical";
244
+ }
245
+ if (style.display.includes("grid")) {
246
+ return style.gridAutoFlow.startsWith("column") ? "horizontal" : "vertical";
247
+ }
248
+ return "vertical";
249
+ }
250
+ function computeDropPosition(cursor, rect, axis) {
251
+ const ratio = axis === "horizontal" ? (cursor.x - rect.left) / rect.width : (cursor.y - rect.top) / rect.height;
252
+ if (ratio < 0.25) return "before";
253
+ if (ratio < 0.5) return "first-child";
254
+ if (ratio < 0.75) return "last-child";
255
+ return "after";
256
+ }
257
+ function findTarget(x, y) {
258
+ if (indicatorEl) indicatorEl.style.display = "none";
259
+ const el = document.elementFromPoint(x, y);
260
+ if (indicatorEl) indicatorEl.style.display = "";
261
+ if (!el || el === document.documentElement || el === document.body) return null;
262
+ if (overlayHost && (el === overlayHost || overlayHost.contains(el))) return null;
263
+ if (indicatorEl && (el === indicatorEl || indicatorEl.contains(el))) return null;
264
+ return el;
265
+ }
266
+ function showIndicator(target, position, axis) {
267
+ if (!indicatorEl) return;
268
+ const rect = target.getBoundingClientRect();
269
+ const isInside = position === "first-child" || position === "last-child";
270
+ if (arrowLeftEl) {
271
+ arrowLeftEl.remove();
272
+ arrowLeftEl = null;
273
+ }
274
+ if (arrowRightEl) {
275
+ arrowRightEl.remove();
276
+ arrowRightEl = null;
277
+ }
278
+ if (isInside) {
279
+ 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;`;
280
+ const arrow2 = document.createElement("div");
281
+ arrow2.style.cssText = "position:absolute;width:0;height:0;border-style:solid;";
282
+ const size2 = 6;
283
+ const isVertical = axis === "vertical";
284
+ if (position === "first-child") {
285
+ if (isVertical) {
286
+ arrow2.style.top = "4px";
287
+ arrow2.style.left = "50%";
288
+ arrow2.style.transform = "translateX(-50%)";
289
+ arrow2.style.borderWidth = `${size2}px ${size2}px 0 ${size2}px`;
290
+ arrow2.style.borderColor = `${TEAL} transparent transparent transparent`;
291
+ } else {
292
+ arrow2.style.left = "4px";
293
+ arrow2.style.top = "50%";
294
+ arrow2.style.transform = "translateY(-50%)";
295
+ arrow2.style.borderWidth = `${size2}px 0 ${size2}px ${size2}px`;
296
+ arrow2.style.borderColor = `transparent transparent transparent ${TEAL}`;
297
+ }
298
+ } else {
299
+ if (isVertical) {
300
+ arrow2.style.bottom = "4px";
301
+ arrow2.style.left = "50%";
302
+ arrow2.style.transform = "translateX(-50%)";
303
+ arrow2.style.borderWidth = `0 ${size2}px ${size2}px ${size2}px`;
304
+ arrow2.style.borderColor = `transparent transparent ${TEAL} transparent`;
305
+ } else {
306
+ arrow2.style.right = "4px";
307
+ arrow2.style.top = "50%";
308
+ arrow2.style.transform = "translateY(-50%)";
309
+ arrow2.style.borderWidth = `${size2}px ${size2}px ${size2}px 0`;
310
+ arrow2.style.borderColor = `transparent ${TEAL} transparent transparent`;
311
+ }
312
+ }
313
+ indicatorEl.appendChild(arrow2);
314
+ arrowLeftEl = arrow2;
315
+ } else {
316
+ const lineWidth = 3;
317
+ const isHorizontalLine = axis === "vertical";
318
+ if (isHorizontalLine) {
319
+ const y = position === "before" ? rect.top : rect.bottom;
320
+ 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;`;
321
+ } else {
322
+ const x = position === "before" ? rect.left : rect.right;
323
+ 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;`;
324
+ }
325
+ const arrowSize = 5;
326
+ const inset = -2;
327
+ arrowLeftEl = document.createElement("div");
328
+ arrowLeftEl.style.cssText = "position:absolute;width:0;height:0;border-style:solid;";
329
+ arrowRightEl = document.createElement("div");
330
+ arrowRightEl.style.cssText = "position:absolute;width:0;height:0;border-style:solid;";
331
+ if (isHorizontalLine) {
332
+ arrowLeftEl.style.top = "50%";
333
+ arrowLeftEl.style.left = `${inset}px`;
334
+ arrowLeftEl.style.transform = "translateY(-50%)";
335
+ arrowLeftEl.style.borderWidth = `${arrowSize}px 0 ${arrowSize}px ${arrowSize}px`;
336
+ arrowLeftEl.style.borderColor = `transparent transparent transparent ${TEAL}`;
337
+ arrowRightEl.style.top = "50%";
338
+ arrowRightEl.style.right = `${inset}px`;
339
+ arrowRightEl.style.transform = "translateY(-50%)";
340
+ arrowRightEl.style.borderWidth = `${arrowSize}px ${arrowSize}px ${arrowSize}px 0`;
341
+ arrowRightEl.style.borderColor = `transparent ${TEAL} transparent transparent`;
342
+ } else {
343
+ arrowLeftEl.style.left = "50%";
344
+ arrowLeftEl.style.top = `${inset}px`;
345
+ arrowLeftEl.style.transform = "translateX(-50%)";
346
+ arrowLeftEl.style.borderWidth = `${arrowSize}px ${arrowSize}px 0 ${arrowSize}px`;
347
+ arrowLeftEl.style.borderColor = `${TEAL} transparent transparent transparent`;
348
+ arrowRightEl.style.left = "50%";
349
+ arrowRightEl.style.bottom = `${inset}px`;
350
+ arrowRightEl.style.transform = "translateX(-50%)";
351
+ arrowRightEl.style.borderWidth = `0 ${arrowSize}px ${arrowSize}px ${arrowSize}px`;
352
+ arrowRightEl.style.borderColor = `transparent transparent ${TEAL} transparent`;
353
+ }
354
+ indicatorEl.appendChild(arrowLeftEl);
355
+ indicatorEl.appendChild(arrowRightEl);
356
+ }
357
+ }
358
+ function hideIndicator() {
359
+ if (indicatorEl) indicatorEl.style.display = "none";
360
+ if (arrowLeftEl) {
361
+ arrowLeftEl.remove();
362
+ arrowLeftEl = null;
363
+ }
364
+ if (arrowRightEl) {
365
+ arrowRightEl.remove();
366
+ arrowRightEl = null;
367
+ }
368
+ currentTarget = null;
369
+ currentPosition = null;
370
+ }
371
+ function onMouseMove(e) {
372
+ if (!active) return;
373
+ if (cursorLabelEl) {
374
+ cursorLabelEl.style.left = `${e.clientX + 14}px`;
375
+ cursorLabelEl.style.top = `${e.clientY - 28}px`;
376
+ cursorLabelEl.style.opacity = "1";
377
+ }
378
+ const target = findTarget(e.clientX, e.clientY);
379
+ if (!target) {
380
+ hideIndicator();
381
+ return;
382
+ }
383
+ const parentAxis = target.parentElement ? getAxis(target.parentElement) : "vertical";
384
+ const rect = target.getBoundingClientRect();
385
+ const position = computeDropPosition(
386
+ { x: e.clientX, y: e.clientY },
387
+ rect,
388
+ parentAxis
389
+ );
390
+ currentTarget = target;
391
+ currentPosition = position;
392
+ showIndicator(target, position, parentAxis);
393
+ }
394
+ function onMouseLeave() {
395
+ hideIndicator();
396
+ if (cursorLabelEl) cursorLabelEl.style.opacity = "0";
397
+ }
398
+ function onClick(e) {
399
+ if (!active) return;
400
+ if (!currentTarget || !currentPosition) {
401
+ cleanup();
402
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
403
+ return;
404
+ }
405
+ e.preventDefault();
406
+ e.stopPropagation();
407
+ const template = document.createElement("template");
408
+ template.innerHTML = ghostHtml.trim();
409
+ const inserted = template.content.firstElementChild;
410
+ if (!inserted) {
411
+ cleanup();
412
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
413
+ return;
414
+ }
415
+ inserted.dataset.twDroppedComponent = componentName;
416
+ switch (currentPosition) {
417
+ case "before":
418
+ currentTarget.insertAdjacentElement("beforebegin", inserted);
419
+ break;
420
+ case "after":
421
+ currentTarget.insertAdjacentElement("afterend", inserted);
422
+ break;
423
+ case "first-child":
424
+ currentTarget.insertAdjacentElement("afterbegin", inserted);
425
+ break;
426
+ case "last-child":
427
+ currentTarget.appendChild(inserted);
428
+ break;
429
+ }
430
+ const targetSelector = buildSelector(currentTarget);
431
+ const isGhostTarget = !!currentTarget.dataset.twDroppedComponent;
432
+ const ghostTargetPatchId = currentTarget.dataset.twDroppedPatchId;
433
+ const ghostTargetName = currentTarget.dataset.twDroppedComponent;
434
+ const ghostAncestor = !isGhostTarget ? findGhostAncestor(currentTarget) : null;
435
+ const effectiveGhostName = isGhostTarget ? ghostTargetName : ghostAncestor?.dataset.twDroppedComponent;
436
+ const effectiveGhostPatchId = isGhostTarget ? ghostTargetPatchId : ghostAncestor?.dataset.twDroppedPatchId;
437
+ const context = effectiveGhostName ? `Place "${componentName}" ${currentPosition} the <${effectiveGhostName} /> component (pending insertion from an earlier drop)` : buildContext(currentTarget, "", "", /* @__PURE__ */ new Map());
438
+ let parentComponent;
439
+ const fiber = getFiber(currentTarget);
440
+ if (fiber) {
441
+ const boundary = findComponentBoundary(fiber);
442
+ if (boundary) {
443
+ parentComponent = { name: boundary.componentName };
444
+ }
445
+ }
446
+ const patch = {
447
+ id: crypto.randomUUID(),
448
+ kind: "component-drop",
449
+ elementKey: targetSelector,
450
+ status: "staged",
451
+ originalClass: "",
452
+ newClass: "",
453
+ property: "component-drop",
454
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
455
+ component: { name: componentName },
456
+ target: isGhostTarget ? { tag: ghostTargetName?.toLowerCase() ?? "unknown", classes: "", innerText: "" } : {
457
+ tag: currentTarget.tagName.toLowerCase(),
458
+ classes: currentTarget.className,
459
+ innerText: currentTarget.innerText.slice(0, 100)
460
+ },
461
+ ghostHtml,
462
+ componentStoryId: storyId,
463
+ componentPath: componentPath || void 0,
464
+ componentArgs: Object.keys(componentArgs).length > 0 ? componentArgs : void 0,
465
+ parentComponent,
466
+ insertMode: currentPosition,
467
+ context,
468
+ ...effectiveGhostPatchId ? { targetPatchId: effectiveGhostPatchId, targetComponentName: effectiveGhostName } : {}
469
+ };
470
+ inserted.dataset.twDroppedPatchId = patch.id;
471
+ send({ type: "COMPONENT_DROPPED", patch });
472
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
473
+ cleanup();
474
+ }
475
+ function onKeyDown(e) {
476
+ if (e.key === "Escape") {
477
+ sendTo("panel", { type: "COMPONENT_DISARMED" });
478
+ cleanup();
479
+ }
480
+ }
481
+ function findGhostAncestor(el) {
482
+ let current = el.parentElement;
483
+ while (current && current !== document.body) {
484
+ if (current.dataset.twDroppedComponent) return current;
485
+ current = current.parentElement;
486
+ }
487
+ return null;
488
+ }
489
+ function buildSelector(el) {
490
+ const tag = el.tagName.toLowerCase();
491
+ if (el.id) return `#${el.id}`;
492
+ const classes = Array.from(el.classList).slice(0, 3).join(".");
493
+ return classes ? `${tag}.${classes}` : tag;
494
+ }
495
+ function cleanup() {
496
+ active = false;
497
+ document.documentElement.style.cursor = "";
498
+ document.removeEventListener("mousemove", onMouseMove);
499
+ document.documentElement.removeEventListener("mouseleave", onMouseLeave);
500
+ document.removeEventListener("click", onClick, true);
501
+ document.removeEventListener("keydown", onKeyDown);
502
+ if (cursorLabelEl) {
503
+ cursorLabelEl.remove();
504
+ cursorLabelEl = null;
505
+ }
506
+ if (indicatorEl) {
507
+ indicatorEl.remove();
508
+ indicatorEl = null;
509
+ }
510
+ arrowLeftEl = null;
511
+ arrowRightEl = null;
512
+ currentTarget = null;
513
+ currentPosition = null;
514
+ }
515
+
3
516
  // node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
4
517
  var min = Math.min;
5
518
  var max = Math.max;
@@ -1442,164 +1955,12 @@
1442
1955
  }
1443
1956
  };
1444
1957
 
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
1958
  // overlay/src/grouping.ts
1598
1959
  function cssEscape(cls) {
1599
1960
  if (typeof CSS !== "undefined" && CSS.escape) return CSS.escape(cls);
1600
1961
  return cls.replace(/([^\w-])/g, "\\$1");
1601
1962
  }
1602
- function buildSelector(tag, classes) {
1963
+ function buildSelector2(tag, classes) {
1603
1964
  return tag.toLowerCase() + classes.map((c) => `.${cssEscape(c)}`).join("");
1604
1965
  }
1605
1966
  function parseClassList(className) {
@@ -1632,7 +1993,7 @@ ${pad}</${tag}>`;
1632
1993
  const tag = clickedEl.tagName;
1633
1994
  const fiber = getFiber(clickedEl);
1634
1995
  const boundary = fiber ? findComponentBoundary(fiber) : null;
1635
- const componentName = boundary?.componentName ?? null;
1996
+ const componentName2 = boundary?.componentName ?? null;
1636
1997
  let exactMatches;
1637
1998
  if (boundary) {
1638
1999
  const rootFiber = getRootFiber();
@@ -1648,7 +2009,7 @@ ${pad}</${tag}>`;
1648
2009
  (n) => (typeof n.className === "string" ? n.className.trim() : "") === "" && !isInShadowHost(n, shadowHost2)
1649
2010
  );
1650
2011
  } else {
1651
- const selector = buildSelector(tag, classes);
2012
+ const selector = buildSelector2(tag, classes);
1652
2013
  exactMatches = Array.from(
1653
2014
  document.querySelectorAll(selector)
1654
2015
  ).filter(
@@ -1663,7 +2024,7 @@ ${pad}</${tag}>`;
1663
2024
  exactMatch: exactMatches,
1664
2025
  nearGroups: [],
1665
2026
  // Not computed yet — lazy
1666
- componentName
2027
+ componentName: componentName2
1667
2028
  };
1668
2029
  }
1669
2030
  function computeNearGroups(clickedEl, exactMatchSet, shadowHost2) {
@@ -2703,55 +3064,10 @@ ${pad}</${tag}>`;
2703
3064
  }
2704
3065
  }
2705
3066
 
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
3067
  // overlay/src/index.ts
2752
3068
  var shadowRoot;
2753
3069
  var shadowHost;
2754
- var active = false;
3070
+ var active2 = false;
2755
3071
  var wasConnected = false;
2756
3072
  var tailwindConfigCache = null;
2757
3073
  var currentEquivalentNodes = [];
@@ -3210,7 +3526,7 @@ ${pad}</${tag}>`;
3210
3526
  hoverTooltipEl = null;
3211
3527
  lastHoveredEl = null;
3212
3528
  }
3213
- function showHoverPreview(el, componentName) {
3529
+ function showHoverPreview(el, componentName2) {
3214
3530
  const rect = el.getBoundingClientRect();
3215
3531
  if (!hoverOutlineEl) {
3216
3532
  hoverOutlineEl = document.createElement("div");
@@ -3228,7 +3544,7 @@ ${pad}</${tag}>`;
3228
3544
  }
3229
3545
  const tag = el.tagName.toLowerCase();
3230
3546
  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>`;
3547
+ hoverTooltipEl.innerHTML = `<span class="ht-dim">&lt;</span>${componentName2}<span class="ht-dim">&gt;</span> <span class="ht-dim">${tag}${cls ? `.${cls}` : ""}</span>`;
3232
3548
  const tooltipHeight = 24;
3233
3549
  const ttTop = rect.top - tooltipHeight - 6;
3234
3550
  hoverTooltipEl.style.top = `${ttTop < 4 ? rect.bottom + 6 : ttTop}px`;
@@ -3584,7 +3900,7 @@ ${pad}</${tag}>`;
3584
3900
  const targetEl = target;
3585
3901
  const classString = typeof targetEl.className === "string" ? targetEl.className : "";
3586
3902
  const result = findExactMatches(targetEl, shadowHost);
3587
- const componentName = result.componentName ?? targetEl.tagName.toLowerCase();
3903
+ const componentName2 = result.componentName ?? targetEl.tagName.toLowerCase();
3588
3904
  clearHighlights();
3589
3905
  for (const node of result.exactMatch) {
3590
3906
  highlightElement(node);
@@ -3592,7 +3908,7 @@ ${pad}</${tag}>`;
3592
3908
  const config = await fetchTailwindConfig();
3593
3909
  currentEquivalentNodes = result.exactMatch;
3594
3910
  currentTargetEl = targetEl;
3595
- currentBoundary = { componentName };
3911
+ currentBoundary = { componentName: componentName2 };
3596
3912
  cachedNearGroups = null;
3597
3913
  currentInstances = result.exactMatch.map((node, i) => ({
3598
3914
  index: i,
@@ -3608,7 +3924,7 @@ ${pad}</${tag}>`;
3608
3924
  }
3609
3925
  sendTo("panel", {
3610
3926
  type: "ELEMENT_SELECTED",
3611
- componentName,
3927
+ componentName: componentName2,
3612
3928
  instanceCount: result.exactMatch.length,
3613
3929
  classes: classString,
3614
3930
  tailwindConfig: config
@@ -3629,8 +3945,8 @@ ${pad}</${tag}>`;
3629
3945
  }
3630
3946
  var PANEL_OPEN_KEY = "tw-inspector-panel-open";
3631
3947
  function toggleInspect(btn) {
3632
- active = !active;
3633
- if (active) {
3948
+ active2 = !active2;
3949
+ if (active2) {
3634
3950
  btn.classList.add("active");
3635
3951
  sessionStorage.setItem(PANEL_OPEN_KEY, "1");
3636
3952
  const panelUrl = `${SERVER_ORIGIN}/panel`;
@@ -3721,12 +4037,14 @@ ${pad}</${tag}>`;
3721
4037
  wrapper.style.height = `${newHeight}px`;
3722
4038
  };
3723
4039
  const onResizeUp = () => {
4040
+ iframe.style.pointerEvents = "";
3724
4041
  document.removeEventListener("mousemove", onResizeMove);
3725
4042
  document.removeEventListener("mouseup", onResizeUp);
3726
4043
  document.documentElement.style.cursor = "";
3727
4044
  };
3728
4045
  resizeHandle.addEventListener("mousedown", (e) => {
3729
4046
  e.preventDefault();
4047
+ iframe.style.pointerEvents = "none";
3730
4048
  startY = e.clientY;
3731
4049
  startHeight = wrapper.offsetHeight;
3732
4050
  document.documentElement.style.cursor = "ns-resize";
@@ -3766,12 +4084,14 @@ ${pad}</${tag}>`;
3766
4084
  wrapper.style.height = `${Math.max(150, cornerStartHeight + dh)}px`;
3767
4085
  };
3768
4086
  const onCornerUp = () => {
4087
+ iframe.style.pointerEvents = "";
3769
4088
  document.removeEventListener("mousemove", onCornerMove);
3770
4089
  document.removeEventListener("mouseup", onCornerUp);
3771
4090
  document.documentElement.style.cursor = "";
3772
4091
  };
3773
4092
  cornerHandle.addEventListener("mousedown", (e) => {
3774
4093
  e.preventDefault();
4094
+ iframe.style.pointerEvents = "none";
3775
4095
  cornerStartX = e.clientX;
3776
4096
  cornerStartY = e.clientY;
3777
4097
  cornerStartWidth = wrapper.offsetWidth;
@@ -4025,7 +4345,11 @@ ${pad}</${tag}>`;
4025
4345
  }
4026
4346
  });
4027
4347
  showToast("Change staged");
4028
- commitPreview();
4348
+ if (!state && !msg.oldClass && msg.newClass) {
4349
+ applyPreview(currentEquivalentNodes, "", msg.newClass, SERVER_ORIGIN).then(() => commitPreview());
4350
+ } else {
4351
+ commitPreview();
4352
+ }
4029
4353
  } else if (msg.type === "CLEAR_HIGHLIGHTS") {
4030
4354
  clearHighlights();
4031
4355
  } else if (msg.type === "SWITCH_CONTAINER") {
@@ -4064,7 +4388,11 @@ ${pad}</${tag}>`;
4064
4388
  }
4065
4389
  }
4066
4390
  } else if (msg.type === "CLOSE_PANEL") {
4067
- if (active) toggleInspect(btn);
4391
+ if (active2) toggleInspect(btn);
4392
+ } else if (msg.type === "COMPONENT_ARM") {
4393
+ armInsert(msg, shadowHost);
4394
+ } else if (msg.type === "COMPONENT_DISARM") {
4395
+ cancelInsert();
4068
4396
  } else if (msg.type === "DESIGN_CLOSE") {
4069
4397
  const last = designCanvasWrappers.pop();
4070
4398
  if (last) {
@@ -4110,7 +4438,7 @@ ${pad}</${tag}>`;
4110
4438
  { capture: true, passive: true }
4111
4439
  );
4112
4440
  if (sessionStorage.getItem(PANEL_OPEN_KEY) === "1") {
4113
- active = true;
4441
+ active2 = true;
4114
4442
  btn.classList.add("active");
4115
4443
  activeContainer.open(`${SERVER_ORIGIN}/panel`);
4116
4444
  }