@designtools/next-plugin 0.1.9 → 0.1.10

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.
@@ -0,0 +1,1027 @@
1
+ "use client";
2
+ import "./chunk-Y6FXYEAI.mjs";
3
+
4
+ // src/surface.tsx
5
+ import { useEffect, useRef, useState, createElement } from "react";
6
+ import { createPortal } from "react-dom";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ function Surface() {
9
+ const stateRef = useRef({
10
+ selectionMode: false,
11
+ hoveredElement: null,
12
+ selectedElement: null,
13
+ selectedDomPath: null,
14
+ overlayRafId: null,
15
+ inlineStyleBackups: /* @__PURE__ */ new Map(),
16
+ tokenValueBackups: /* @__PURE__ */ new Map(),
17
+ tokenPreviewValues: /* @__PURE__ */ new Map(),
18
+ tokenPreviewStyle: null,
19
+ highlightOverlay: null,
20
+ tooltip: null,
21
+ selectedOverlay: null
22
+ });
23
+ const [previewComponent, setPreviewComponent] = useState(null);
24
+ const [previewCombinations, setPreviewCombinations] = useState([]);
25
+ const [previewDefaultChildren, setPreviewDefaultChildren] = useState("");
26
+ const [previewError, setPreviewError] = useState(null);
27
+ const [showPreview, setShowPreview] = useState(false);
28
+ const setPreviewRef = useRef({
29
+ setPreviewComponent,
30
+ setPreviewCombinations,
31
+ setPreviewDefaultChildren,
32
+ setPreviewError,
33
+ setShowPreview
34
+ });
35
+ setPreviewRef.current = {
36
+ setPreviewComponent,
37
+ setPreviewCombinations,
38
+ setPreviewDefaultChildren,
39
+ setPreviewError,
40
+ setShowPreview
41
+ };
42
+ useEffect(() => {
43
+ const s = stateRef.current;
44
+ s.highlightOverlay = document.createElement("div");
45
+ s.highlightOverlay.id = "tool-highlight";
46
+ Object.assign(s.highlightOverlay.style, {
47
+ position: "fixed",
48
+ pointerEvents: "none",
49
+ border: "2px solid #3b82f6",
50
+ backgroundColor: "rgba(59, 130, 246, 0.08)",
51
+ borderRadius: "2px",
52
+ zIndex: "99999",
53
+ display: "none",
54
+ transition: "all 0.1s ease"
55
+ });
56
+ document.body.appendChild(s.highlightOverlay);
57
+ s.tooltip = document.createElement("div");
58
+ s.tooltip.id = "tool-tooltip";
59
+ Object.assign(s.tooltip.style, {
60
+ position: "fixed",
61
+ pointerEvents: "none",
62
+ backgroundColor: "#1e1e2e",
63
+ color: "#cdd6f4",
64
+ padding: "3px 8px",
65
+ borderRadius: "4px",
66
+ fontSize: "11px",
67
+ fontFamily: "ui-monospace, monospace",
68
+ zIndex: "100000",
69
+ display: "none",
70
+ whiteSpace: "nowrap",
71
+ boxShadow: "0 2px 8px rgba(0,0,0,0.3)"
72
+ });
73
+ document.body.appendChild(s.tooltip);
74
+ s.selectedOverlay = document.createElement("div");
75
+ s.selectedOverlay.id = "tool-selected";
76
+ Object.assign(s.selectedOverlay.style, {
77
+ position: "fixed",
78
+ pointerEvents: "none",
79
+ border: "2px solid #f59e0b",
80
+ backgroundColor: "rgba(245, 158, 11, 0.06)",
81
+ borderRadius: "2px",
82
+ zIndex: "99998",
83
+ display: "none"
84
+ });
85
+ document.body.appendChild(s.selectedOverlay);
86
+ function getElementName(el) {
87
+ const slot = el.getAttribute("data-slot");
88
+ if (slot) return slot.charAt(0).toUpperCase() + slot.slice(1);
89
+ return `<${el.tagName.toLowerCase()}>`;
90
+ }
91
+ function getDomPath(el) {
92
+ const parts = [];
93
+ let current = el;
94
+ while (current && current !== document.body) {
95
+ const parent = current.parentElement;
96
+ if (parent) {
97
+ const idx = Array.from(parent.children).indexOf(current) + 1;
98
+ parts.unshift(`${current.tagName.toLowerCase()}:nth-child(${idx})`);
99
+ } else {
100
+ parts.unshift(current.tagName.toLowerCase());
101
+ }
102
+ current = current.parentElement;
103
+ }
104
+ return parts.join(" > ");
105
+ }
106
+ function positionOverlay(overlay, rect) {
107
+ Object.assign(overlay.style, {
108
+ left: `${rect.left}px`,
109
+ top: `${rect.top}px`,
110
+ width: `${rect.width}px`,
111
+ height: `${rect.height}px`,
112
+ display: "block"
113
+ });
114
+ }
115
+ function findSelectableElement(target) {
116
+ let el = target;
117
+ while (el && el !== document.body) {
118
+ if (el.getAttribute("data-slot")) return el;
119
+ el = el.parentElement;
120
+ }
121
+ return target;
122
+ }
123
+ const overlayIds = /* @__PURE__ */ new Set(["tool-highlight", "tool-tooltip", "tool-selected", "surface-token-preview"]);
124
+ const semanticTags = /* @__PURE__ */ new Set(["header", "main", "nav", "section", "article", "footer", "aside"]);
125
+ const skipTags = /* @__PURE__ */ new Set([
126
+ "html",
127
+ "body",
128
+ "head",
129
+ // document structure
130
+ "br",
131
+ "hr",
132
+ "wbr",
133
+ // void/formatting
134
+ "template",
135
+ "slot"
136
+ // shadow DOM
137
+ ]);
138
+ const frameworkPatterns = [
139
+ /^Fragment$/,
140
+ /^Suspense$/,
141
+ /^ErrorBoundary$/,
142
+ /^Provider$/,
143
+ /^Consumer$/,
144
+ /Context$/,
145
+ /^ForwardRef$/,
146
+ /^Memo$/,
147
+ /^Lazy$/,
148
+ // Next.js routing internals
149
+ /^InnerLayoutRouter$/,
150
+ /^OuterLayoutRouter$/,
151
+ /^LayoutRouter$/,
152
+ /^RenderFromTemplateContext$/,
153
+ /^TemplateContext$/,
154
+ /^RedirectBoundary$/,
155
+ /^RedirectErrorBoundary$/,
156
+ /^NotFoundBoundary$/,
157
+ /^LoadingBoundary$/,
158
+ /^HTTPAccessFallbackBoundary$/,
159
+ /^HTTPAccessFallbackErrorBoundary$/,
160
+ /^ClientPageRoot$/,
161
+ /^HotReload$/,
162
+ /^ReactDevOverlay$/,
163
+ /^PathnameContextProviderAdapter$/,
164
+ // Next.js App Router internals (segment tree)
165
+ /^SegmentViewNode$/,
166
+ /^SegmentTrieNode$/,
167
+ /^SegmentViewStateNode$/,
168
+ /^SegmentBoundaryTriggerNode$/,
169
+ /^SegmentStateProvider$/,
170
+ /^ScrollAndFocusHandler$/,
171
+ /^InnerScrollAndFocusHandler$/,
172
+ /^AppRouter$/,
173
+ /^Router$/,
174
+ /^Root$/,
175
+ /^ServerRoot$/,
176
+ /^RootErrorBoundary$/,
177
+ /^ErrorBoundaryHandler$/,
178
+ /^AppRouterAnnouncer$/,
179
+ /^HistoryUpdater$/,
180
+ /^RuntimeStyles$/,
181
+ /^DevRootHTTPAccessFallbackBoundary$/,
182
+ /^AppDevOverlayErrorBoundary$/,
183
+ /^ReplaySsrOnlyErrors$/,
184
+ /^HeadManagerContext$/,
185
+ /^Head$/,
186
+ /^MetadataOutlet$/,
187
+ /^AsyncMetadataOutlet$/,
188
+ /^__next_/
189
+ // All __next_ prefixed components
190
+ ];
191
+ function isFrameworkComponent(name) {
192
+ return frameworkPatterns.some((p) => p.test(name));
193
+ }
194
+ function getFiber(el) {
195
+ const key = Object.keys(el).find((k) => k.startsWith("__reactFiber$"));
196
+ return key ? el[key] : null;
197
+ }
198
+ function getDirectText(el) {
199
+ let text = "";
200
+ for (const node of Array.from(el.childNodes)) {
201
+ if (node.nodeType === Node.TEXT_NODE) {
202
+ text += (node.textContent || "").trim();
203
+ }
204
+ }
205
+ return text.slice(0, 40);
206
+ }
207
+ function inferScope(sourcePath) {
208
+ if (!sourcePath) return null;
209
+ const colonIdx = sourcePath.indexOf(":");
210
+ const file = colonIdx > 0 ? sourcePath.slice(0, colonIdx) : sourcePath;
211
+ if (/\/layout\.[tjsx]+$/i.test(file) || /^layout\.[tjsx]+$/i.test(file)) return "layout";
212
+ if (/\/page\.[tjsx]+$/i.test(file) || /^page\.[tjsx]+$/i.test(file)) return "page";
213
+ return null;
214
+ }
215
+ function getScopeForElement(el, parentScope) {
216
+ if (!el) return parentScope;
217
+ const instanceSource = el.getAttribute("data-instance-source");
218
+ const fromInstance = inferScope(instanceSource);
219
+ if (fromInstance) return fromInstance;
220
+ const source = el.getAttribute("data-source");
221
+ const fromSource = inferScope(source);
222
+ if (fromSource) return fromSource;
223
+ return parentScope;
224
+ }
225
+ function buildComponentTree(rootEl) {
226
+ const fiber = getFiber(rootEl);
227
+ if (!fiber) {
228
+ return buildDataSlotTree(rootEl);
229
+ }
230
+ let fiberRoot = fiber;
231
+ while (fiberRoot.return) fiberRoot = fiberRoot.return;
232
+ const results = [];
233
+ walkFiber(fiberRoot.child, results, null);
234
+ return results;
235
+ }
236
+ function walkFiber(fiber, siblings, parentScope) {
237
+ while (fiber) {
238
+ const node = processFiber(fiber, parentScope);
239
+ if (node) {
240
+ siblings.push(node);
241
+ } else {
242
+ if (fiber.child) {
243
+ let childScope = parentScope;
244
+ if (typeof fiber.type === "string" && fiber.stateNode instanceof Element) {
245
+ childScope = getScopeForElement(fiber.stateNode, parentScope);
246
+ } else if (typeof fiber.type === "function" || typeof fiber.type === "object") {
247
+ const hostEl = findOwnHostElement(fiber);
248
+ if (hostEl) {
249
+ childScope = getScopeForElement(hostEl, parentScope);
250
+ }
251
+ }
252
+ walkFiber(fiber.child, siblings, childScope);
253
+ }
254
+ }
255
+ fiber = fiber.sibling;
256
+ }
257
+ }
258
+ function processFiber(fiber, parentScope) {
259
+ if (typeof fiber.type === "string") {
260
+ return processHostFiber(fiber, parentScope);
261
+ }
262
+ if (typeof fiber.type === "function" || typeof fiber.type === "object") {
263
+ return processComponentFiber(fiber, parentScope);
264
+ }
265
+ return null;
266
+ }
267
+ function processHostFiber(fiber, parentScope) {
268
+ const tag = fiber.type;
269
+ const el = fiber.stateNode;
270
+ if (el && el.id && overlayIds.has(el.id)) return null;
271
+ if (["script", "style", "link", "noscript"].includes(tag)) return null;
272
+ const scope = getScopeForElement(el, parentScope);
273
+ const dataSlot = el?.getAttribute("data-slot") || null;
274
+ if (dataSlot) {
275
+ const name = dataSlot.split("-").map((s2) => s2.charAt(0).toUpperCase() + s2.slice(1)).join("");
276
+ const children = [];
277
+ if (fiber.child) walkFiber(fiber.child, children, scope);
278
+ return {
279
+ id: el ? getDomPath(el) : "",
280
+ name,
281
+ type: "component",
282
+ dataSlot,
283
+ source: el?.getAttribute("data-source") || null,
284
+ scope,
285
+ textContent: el ? getDirectText(el) : "",
286
+ children
287
+ };
288
+ }
289
+ if (semanticTags.has(tag)) {
290
+ const children = [];
291
+ if (fiber.child) walkFiber(fiber.child, children, scope);
292
+ const text = el ? getDirectText(el) : "";
293
+ return {
294
+ id: el ? getDomPath(el) : "",
295
+ name: `<${tag}>`,
296
+ type: "element",
297
+ dataSlot: null,
298
+ source: el?.getAttribute("data-source") || null,
299
+ scope,
300
+ textContent: text,
301
+ children
302
+ };
303
+ }
304
+ if (currentTreeMode === "dom" && el?.hasAttribute("data-source") && !skipTags.has(tag)) {
305
+ const children = [];
306
+ if (fiber.child) walkFiber(fiber.child, children, scope);
307
+ const text = el ? getDirectText(el) : "";
308
+ return {
309
+ id: getDomPath(el),
310
+ name: `<${tag}>`,
311
+ type: "element",
312
+ dataSlot: null,
313
+ source: el.getAttribute("data-source"),
314
+ scope,
315
+ textContent: text,
316
+ children
317
+ };
318
+ }
319
+ return null;
320
+ }
321
+ function processComponentFiber(fiber, parentScope) {
322
+ const type = fiber.type;
323
+ const name = type?.displayName || type?.name || null;
324
+ if (!name) return null;
325
+ if (isFrameworkComponent(name)) return null;
326
+ if (name === "Surface") return null;
327
+ const hostEl = findOwnHostElement(fiber);
328
+ const hasInstanceSource = hostEl?.getAttribute("data-instance-source");
329
+ const hasDataSlot = hostEl?.getAttribute("data-slot");
330
+ if (!hasInstanceSource && !hasDataSlot) return null;
331
+ const scope = getScopeForElement(hostEl, parentScope);
332
+ const dataSlot = hasDataSlot || null;
333
+ const children = [];
334
+ const hostFiber = dataSlot ? findHostFiber(fiber) : null;
335
+ const childFiber = hostFiber ? hostFiber.child : fiber.child;
336
+ if (childFiber) walkFiber(childFiber, children, scope);
337
+ if (children.length === 1 && !dataSlot && !(hostEl && getDirectText(hostEl))) {
338
+ const child = children[0];
339
+ if (child.type === "component") {
340
+ return child;
341
+ }
342
+ }
343
+ return {
344
+ id: hostEl ? getDomPath(hostEl) : "",
345
+ name,
346
+ type: "component",
347
+ dataSlot,
348
+ source: hostEl?.getAttribute("data-source") || null,
349
+ scope,
350
+ textContent: hostEl ? getDirectText(hostEl) : "",
351
+ children
352
+ };
353
+ }
354
+ function findHostFiber(fiber) {
355
+ let child = fiber.child;
356
+ while (child) {
357
+ if (child.stateNode instanceof Element) return child;
358
+ const tag = child.tag;
359
+ const isComponentBoundary = tag === 0 || tag === 1 || tag === 11 || tag === 14 || tag === 15;
360
+ if (!isComponentBoundary && child.child) {
361
+ const found = findHostFiber(child);
362
+ if (found) return found;
363
+ }
364
+ child = child.sibling;
365
+ }
366
+ return null;
367
+ }
368
+ function findOwnHostElement(fiber) {
369
+ let child = fiber.child;
370
+ while (child) {
371
+ if (child.stateNode instanceof Element) return child.stateNode;
372
+ const tag = child.tag;
373
+ const isComponentBoundary = tag === 0 || tag === 1 || tag === 11 || tag === 14 || tag === 15;
374
+ if (!isComponentBoundary && child.child) {
375
+ const found = findOwnHostElement(child);
376
+ if (found) return found;
377
+ }
378
+ child = child.sibling;
379
+ }
380
+ return null;
381
+ }
382
+ function buildDataSlotTree(root) {
383
+ const results = [];
384
+ for (const child of Array.from(root.children)) {
385
+ walkDomForSlots(child, results, null);
386
+ }
387
+ return results;
388
+ }
389
+ function walkDomForSlots(el, siblings, parentScope) {
390
+ if (el.id && overlayIds.has(el.id)) return;
391
+ const dataSlot = el.getAttribute("data-slot");
392
+ const tag = el.tagName.toLowerCase();
393
+ const scope = getScopeForElement(el, parentScope);
394
+ if (dataSlot) {
395
+ const name = dataSlot.split("-").map((s2) => s2.charAt(0).toUpperCase() + s2.slice(1)).join("");
396
+ const children = [];
397
+ for (const child of Array.from(el.children)) {
398
+ walkDomForSlots(child, children, scope);
399
+ }
400
+ siblings.push({
401
+ id: getDomPath(el),
402
+ name,
403
+ type: "component",
404
+ dataSlot,
405
+ source: el.getAttribute("data-source") || null,
406
+ scope,
407
+ textContent: getDirectText(el),
408
+ children
409
+ });
410
+ } else if (semanticTags.has(tag)) {
411
+ const children = [];
412
+ for (const child of Array.from(el.children)) {
413
+ walkDomForSlots(child, children, scope);
414
+ }
415
+ if (children.length > 0 || getDirectText(el)) {
416
+ siblings.push({
417
+ id: getDomPath(el),
418
+ name: `<${tag}>`,
419
+ type: "element",
420
+ dataSlot: null,
421
+ source: el.getAttribute("data-source") || null,
422
+ scope,
423
+ textContent: getDirectText(el),
424
+ children
425
+ });
426
+ }
427
+ } else {
428
+ for (const child of Array.from(el.children)) {
429
+ walkDomForSlots(child, siblings, scope);
430
+ }
431
+ }
432
+ }
433
+ let currentTreeMode = "components";
434
+ function sendComponentTree(mode) {
435
+ if (mode) currentTreeMode = mode;
436
+ const tree = buildComponentTree(document.body);
437
+ window.parent.postMessage({ type: "tool:componentTree", tree }, "*");
438
+ }
439
+ let debounceTimer = null;
440
+ function debouncedSendTree() {
441
+ if (debounceTimer) clearTimeout(debounceTimer);
442
+ debounceTimer = setTimeout(() => sendComponentTree(), 300);
443
+ }
444
+ const treeObserver = new MutationObserver(debouncedSendTree);
445
+ treeObserver.observe(document.body, { childList: true, subtree: true });
446
+ const relevantProps = [
447
+ "display",
448
+ "position",
449
+ "top",
450
+ "right",
451
+ "bottom",
452
+ "left",
453
+ "z-index",
454
+ "overflow",
455
+ "overflow-x",
456
+ "overflow-y",
457
+ "flex-direction",
458
+ "flex-wrap",
459
+ "justify-content",
460
+ "align-items",
461
+ "align-self",
462
+ "flex-grow",
463
+ "flex-shrink",
464
+ "flex-basis",
465
+ "order",
466
+ "grid-template-columns",
467
+ "grid-template-rows",
468
+ "gap",
469
+ "row-gap",
470
+ "column-gap",
471
+ "width",
472
+ "height",
473
+ "min-width",
474
+ "min-height",
475
+ "max-width",
476
+ "max-height",
477
+ "margin-top",
478
+ "margin-right",
479
+ "margin-bottom",
480
+ "margin-left",
481
+ "padding-top",
482
+ "padding-right",
483
+ "padding-bottom",
484
+ "padding-left",
485
+ "font-family",
486
+ "font-size",
487
+ "font-weight",
488
+ "line-height",
489
+ "letter-spacing",
490
+ "text-align",
491
+ "text-decoration",
492
+ "text-transform",
493
+ "color",
494
+ "white-space",
495
+ "background-color",
496
+ "background-image",
497
+ "background-size",
498
+ "background-position",
499
+ "border-top-width",
500
+ "border-right-width",
501
+ "border-bottom-width",
502
+ "border-left-width",
503
+ "border-style",
504
+ "border-color",
505
+ "border-top-left-radius",
506
+ "border-top-right-radius",
507
+ "border-bottom-right-radius",
508
+ "border-bottom-left-radius",
509
+ "opacity",
510
+ "box-shadow",
511
+ "transform",
512
+ "transition"
513
+ ];
514
+ const inheritableProps = [
515
+ "color",
516
+ "font-family",
517
+ "font-size",
518
+ "font-weight",
519
+ "line-height",
520
+ "letter-spacing",
521
+ "text-align",
522
+ "text-transform",
523
+ "white-space"
524
+ ];
525
+ function findComponentFiberAbove(el) {
526
+ const fiber = getFiber(el);
527
+ if (!fiber) return null;
528
+ let candidate = fiber.return;
529
+ while (candidate) {
530
+ const tag = candidate.tag;
531
+ if (tag === 0 || tag === 1 || tag === 11 || tag === 14 || tag === 15) {
532
+ if (findOwnHostElement(candidate) === el) return candidate;
533
+ }
534
+ candidate = candidate.return;
535
+ }
536
+ return null;
537
+ }
538
+ function extractFiberProps(fiber) {
539
+ const props = fiber?.memoizedProps;
540
+ if (!props || typeof props !== "object") return null;
541
+ const skipKeys = /* @__PURE__ */ new Set(["children", "ref", "key", "className", "style"]);
542
+ const result = {};
543
+ let count = 0;
544
+ for (const k of Object.keys(props)) {
545
+ if (skipKeys.has(k)) continue;
546
+ if (k.startsWith("data-")) continue;
547
+ const v = props[k];
548
+ if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
549
+ result[k] = v;
550
+ count++;
551
+ }
552
+ }
553
+ return count > 0 ? result : null;
554
+ }
555
+ function extractElementData(el) {
556
+ const computed = getComputedStyle(el);
557
+ const rect = el.getBoundingClientRect();
558
+ const computedStyles = {};
559
+ for (const prop of relevantProps) {
560
+ computedStyles[prop] = computed.getPropertyValue(prop);
561
+ }
562
+ const parentComputedStyles = {};
563
+ const parentEl = el.parentElement;
564
+ if (parentEl) {
565
+ const parentComputed = getComputedStyle(parentEl);
566
+ for (const prop of inheritableProps) {
567
+ parentComputedStyles[prop] = parentComputed.getPropertyValue(prop);
568
+ }
569
+ }
570
+ const attributes = {};
571
+ for (const attr of Array.from(el.attributes)) {
572
+ if (attr.name.startsWith("data-")) {
573
+ attributes[attr.name] = attr.value;
574
+ }
575
+ }
576
+ let sourceFile = null;
577
+ let sourceLine = null;
578
+ let sourceCol = null;
579
+ const dataSource = el.getAttribute("data-source");
580
+ if (dataSource) {
581
+ const lastColon = dataSource.lastIndexOf(":");
582
+ const secondLastColon = dataSource.lastIndexOf(":", lastColon - 1);
583
+ if (secondLastColon > 0) {
584
+ sourceFile = dataSource.slice(0, secondLastColon);
585
+ sourceLine = parseInt(dataSource.slice(secondLastColon + 1, lastColon), 10);
586
+ sourceCol = parseInt(dataSource.slice(lastColon + 1), 10);
587
+ }
588
+ }
589
+ let instanceSourceFile = null;
590
+ let instanceSourceLine = null;
591
+ let instanceSourceCol = null;
592
+ let componentName = null;
593
+ let packageName = null;
594
+ const dataSlot = el.getAttribute("data-slot");
595
+ const instanceSource = el.getAttribute("data-instance-source");
596
+ if (instanceSource) {
597
+ const lc = instanceSource.lastIndexOf(":");
598
+ const slc = instanceSource.lastIndexOf(":", lc - 1);
599
+ if (slc > 0) {
600
+ instanceSourceFile = instanceSource.slice(0, slc);
601
+ instanceSourceLine = parseInt(instanceSource.slice(slc + 1, lc), 10);
602
+ instanceSourceCol = parseInt(instanceSource.slice(lc + 1), 10);
603
+ }
604
+ if (dataSlot) {
605
+ componentName = dataSlot.split("-").map((s2) => s2.charAt(0).toUpperCase() + s2.slice(1)).join("");
606
+ }
607
+ }
608
+ const compFiber = dataSlot || instanceSource ? findComponentFiberAbove(el) : null;
609
+ let fiberProps = null;
610
+ if (compFiber) {
611
+ fiberProps = extractFiberProps(compFiber);
612
+ if (!componentName && instanceSource) {
613
+ const name = compFiber.type?.displayName || compFiber.type?.name;
614
+ if (name) componentName = name;
615
+ }
616
+ const debugFile = compFiber._debugSource?.fileName;
617
+ if (debugFile) {
618
+ packageName = extractPackageName(debugFile);
619
+ }
620
+ }
621
+ if (!packageName && !sourceFile) {
622
+ const anyFiber = findComponentFiberAbove(el);
623
+ if (anyFiber) {
624
+ const debugFile = anyFiber._debugSource?.fileName;
625
+ if (debugFile) {
626
+ packageName = extractPackageName(debugFile);
627
+ }
628
+ }
629
+ }
630
+ return {
631
+ tag: el.tagName.toLowerCase(),
632
+ className: (el.getAttribute("class") || "").trim(),
633
+ computedStyles,
634
+ parentComputedStyles,
635
+ boundingRect: rect,
636
+ domPath: getDomPath(el),
637
+ textContent: (el.textContent || "").trim().slice(0, 100),
638
+ attributes,
639
+ sourceFile,
640
+ sourceLine,
641
+ sourceCol,
642
+ instanceSourceFile,
643
+ instanceSourceLine,
644
+ instanceSourceCol,
645
+ componentName,
646
+ packageName,
647
+ fiberProps
648
+ };
649
+ }
650
+ function extractPackageName(filePath) {
651
+ const nmIdx = filePath.lastIndexOf("node_modules/");
652
+ if (nmIdx === -1) return null;
653
+ const rest = filePath.slice(nmIdx + "node_modules/".length);
654
+ if (rest.startsWith("@")) {
655
+ const parts = rest.split("/");
656
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
657
+ }
658
+ return rest.split("/")[0] || null;
659
+ }
660
+ function selectElement(el) {
661
+ s.selectedElement = el;
662
+ s.selectedDomPath = getDomPath(el);
663
+ const data = extractElementData(el);
664
+ if (s.selectedOverlay) {
665
+ positionOverlay(s.selectedOverlay, data.boundingRect);
666
+ }
667
+ startOverlayTracking();
668
+ window.parent.postMessage({ type: "tool:elementSelected", data }, "*");
669
+ }
670
+ function reselectCurrentElement() {
671
+ if (!s.selectedDomPath) return;
672
+ const el = document.querySelector(s.selectedDomPath);
673
+ if (el) {
674
+ s.selectedElement = el;
675
+ const data = extractElementData(el);
676
+ if (s.selectedOverlay) {
677
+ positionOverlay(s.selectedOverlay, data.boundingRect);
678
+ }
679
+ window.parent.postMessage({ type: "tool:elementSelected", data }, "*");
680
+ }
681
+ }
682
+ function startOverlayTracking() {
683
+ if (s.overlayRafId) cancelAnimationFrame(s.overlayRafId);
684
+ let lastRect = "";
685
+ function tick() {
686
+ if (s.selectedElement && s.selectedOverlay) {
687
+ if (!document.contains(s.selectedElement)) {
688
+ if (s.selectedDomPath) {
689
+ const newEl = document.querySelector(s.selectedDomPath);
690
+ if (newEl) {
691
+ s.selectedElement = newEl;
692
+ reselectCurrentElement();
693
+ }
694
+ }
695
+ }
696
+ if (s.selectedElement && document.contains(s.selectedElement)) {
697
+ const rect = s.selectedElement.getBoundingClientRect();
698
+ const key = `${rect.left},${rect.top},${rect.width},${rect.height}`;
699
+ if (key !== lastRect) {
700
+ lastRect = key;
701
+ positionOverlay(s.selectedOverlay, rect);
702
+ }
703
+ }
704
+ }
705
+ s.overlayRafId = requestAnimationFrame(tick);
706
+ }
707
+ tick();
708
+ }
709
+ function hideSelectionOverlays() {
710
+ if (s.highlightOverlay) s.highlightOverlay.style.display = "none";
711
+ if (s.tooltip) s.tooltip.style.display = "none";
712
+ if (s.selectedOverlay) s.selectedOverlay.style.display = "none";
713
+ s.hoveredElement = null;
714
+ }
715
+ function enterSelectionMode() {
716
+ s.selectionMode = true;
717
+ document.body.style.cursor = "crosshair";
718
+ }
719
+ function exitSelectionMode() {
720
+ s.selectionMode = false;
721
+ document.body.style.cursor = "";
722
+ if (s.highlightOverlay) s.highlightOverlay.style.display = "none";
723
+ if (s.tooltip) s.tooltip.style.display = "none";
724
+ s.hoveredElement = null;
725
+ }
726
+ function clearSelection() {
727
+ s.selectedElement = null;
728
+ s.selectedDomPath = null;
729
+ if (s.selectedOverlay) s.selectedOverlay.style.display = "none";
730
+ if (s.overlayRafId) {
731
+ cancelAnimationFrame(s.overlayRafId);
732
+ s.overlayRafId = null;
733
+ }
734
+ }
735
+ function onMouseMove(e) {
736
+ if (!s.selectionMode || !s.highlightOverlay || !s.tooltip) return;
737
+ const el = document.elementFromPoint(e.clientX, e.clientY);
738
+ if (!el || el === s.highlightOverlay || el === s.tooltip || el === s.selectedOverlay) return;
739
+ const selectable = findSelectableElement(el);
740
+ if (selectable === s.hoveredElement) return;
741
+ s.hoveredElement = selectable;
742
+ const rect = selectable.getBoundingClientRect();
743
+ positionOverlay(s.highlightOverlay, rect);
744
+ const name = getElementName(selectable);
745
+ s.tooltip.textContent = name;
746
+ s.tooltip.style.display = "block";
747
+ s.tooltip.style.left = `${rect.left}px`;
748
+ s.tooltip.style.top = `${Math.max(0, rect.top - 24)}px`;
749
+ }
750
+ function onMouseLeave() {
751
+ if (!s.highlightOverlay || !s.tooltip) return;
752
+ s.highlightOverlay.style.display = "none";
753
+ s.tooltip.style.display = "none";
754
+ s.hoveredElement = null;
755
+ }
756
+ function onClick(e) {
757
+ if (!s.selectionMode) return;
758
+ e.preventDefault();
759
+ e.stopPropagation();
760
+ const el = document.elementFromPoint(e.clientX, e.clientY);
761
+ if (!el || el === s.highlightOverlay || el === s.tooltip || el === s.selectedOverlay) return;
762
+ const selectable = findSelectableElement(el);
763
+ selectElement(selectable);
764
+ }
765
+ function onMessage(e) {
766
+ const msg = e.data;
767
+ if (!msg || !msg.type || !msg.type.startsWith("tool:")) return;
768
+ switch (msg.type) {
769
+ case "tool:enterSelectionMode":
770
+ enterSelectionMode();
771
+ break;
772
+ case "tool:exitSelectionMode":
773
+ exitSelectionMode();
774
+ break;
775
+ case "tool:clearSelection":
776
+ clearSelection();
777
+ break;
778
+ case "tool:previewInlineStyle": {
779
+ if (s.selectedElement && s.selectedElement instanceof HTMLElement) {
780
+ const prop = msg.property;
781
+ const value = msg.value;
782
+ if (!s.inlineStyleBackups.has(prop)) {
783
+ s.inlineStyleBackups.set(prop, s.selectedElement.style.getPropertyValue(prop));
784
+ }
785
+ s.selectedElement.style.setProperty(prop, value, "important");
786
+ }
787
+ break;
788
+ }
789
+ case "tool:revertInlineStyles": {
790
+ if (s.selectedElement && s.selectedElement instanceof HTMLElement) {
791
+ for (const [prop, original] of s.inlineStyleBackups) {
792
+ if (original) {
793
+ s.selectedElement.style.setProperty(prop, original);
794
+ } else {
795
+ s.selectedElement.style.removeProperty(prop);
796
+ }
797
+ }
798
+ s.inlineStyleBackups.clear();
799
+ }
800
+ break;
801
+ }
802
+ case "tool:previewTokenValue": {
803
+ const prop = msg.property;
804
+ const value = msg.value;
805
+ s.tokenPreviewValues.set(prop, value);
806
+ if (!s.tokenPreviewStyle) {
807
+ s.tokenPreviewStyle = document.createElement("style");
808
+ s.tokenPreviewStyle.id = "surface-token-preview";
809
+ document.head.appendChild(s.tokenPreviewStyle);
810
+ }
811
+ const cssRules = [];
812
+ for (const [k, v] of s.tokenPreviewValues) {
813
+ if (k.startsWith("--shadow")) {
814
+ const cls = k.slice(2);
815
+ cssRules.push(`.${cls}, [class*="${cls}"] { box-shadow: ${v} !important; }`);
816
+ } else {
817
+ cssRules.push(`*, *::before, *::after { ${k}: ${v} !important; }`);
818
+ }
819
+ }
820
+ s.tokenPreviewStyle.textContent = cssRules.join("\n");
821
+ break;
822
+ }
823
+ case "tool:revertTokenValues": {
824
+ if (s.tokenPreviewStyle) {
825
+ s.tokenPreviewStyle.remove();
826
+ s.tokenPreviewStyle = null;
827
+ }
828
+ s.tokenPreviewValues.clear();
829
+ s.tokenValueBackups.clear();
830
+ break;
831
+ }
832
+ case "tool:reselectElement":
833
+ reselectCurrentElement();
834
+ break;
835
+ case "tool:setTheme":
836
+ if (msg.theme === "dark") {
837
+ document.documentElement.classList.add("dark");
838
+ } else {
839
+ document.documentElement.classList.remove("dark");
840
+ }
841
+ break;
842
+ case "tool:requestComponentTree":
843
+ sendComponentTree(msg.mode || "components");
844
+ break;
845
+ case "tool:highlightByTreeId": {
846
+ const id = msg.id;
847
+ if (!id || !s.highlightOverlay || !s.tooltip) break;
848
+ const target = document.querySelector(id);
849
+ if (target) {
850
+ const rect = target.getBoundingClientRect();
851
+ positionOverlay(s.highlightOverlay, rect);
852
+ const name = getElementName(target);
853
+ s.tooltip.textContent = name;
854
+ s.tooltip.style.display = "block";
855
+ s.tooltip.style.left = `${rect.left}px`;
856
+ s.tooltip.style.top = `${Math.max(0, rect.top - 24)}px`;
857
+ }
858
+ break;
859
+ }
860
+ case "tool:clearHighlight":
861
+ if (s.highlightOverlay) s.highlightOverlay.style.display = "none";
862
+ if (s.tooltip) s.tooltip.style.display = "none";
863
+ break;
864
+ case "tool:selectByTreeId": {
865
+ const id = msg.id;
866
+ if (!id) break;
867
+ const target = document.querySelector(id);
868
+ if (target) {
869
+ const selectable = findSelectableElement(target);
870
+ selectElement(selectable);
871
+ }
872
+ break;
873
+ }
874
+ case "tool:selectParentInstance": {
875
+ if (!s.selectedElement) break;
876
+ let el = s.selectedElement.parentElement;
877
+ while (el && el !== document.body) {
878
+ if (el.getAttribute("data-instance-source")) {
879
+ selectElement(el);
880
+ break;
881
+ }
882
+ el = el.parentElement;
883
+ }
884
+ break;
885
+ }
886
+ case "tool:renderPreview": {
887
+ const { componentPath, exportName, combinations: combos, defaultChildren: children } = msg;
888
+ const currentRegistry = window.__DESIGNTOOLS_REGISTRY__;
889
+ if (!currentRegistry) {
890
+ setPreviewRef.current.setPreviewError("No component registry available. Ensure designtools-registry.ts is imported.");
891
+ setPreviewRef.current.setShowPreview(true);
892
+ return;
893
+ }
894
+ const loader = currentRegistry[componentPath];
895
+ if (!loader) {
896
+ setPreviewRef.current.setPreviewError(
897
+ `Component "${componentPath}" not found in registry. Available: ${Object.keys(currentRegistry).join(", ")}`
898
+ );
899
+ setPreviewRef.current.setShowPreview(true);
900
+ return;
901
+ }
902
+ exitSelectionMode();
903
+ hideSelectionOverlays();
904
+ loader().then((mod) => {
905
+ const Comp = mod[exportName] || mod.default;
906
+ if (!Comp) {
907
+ setPreviewRef.current.setPreviewError(`Export "${exportName}" not found in ${componentPath}`);
908
+ setPreviewRef.current.setShowPreview(true);
909
+ return;
910
+ }
911
+ setPreviewRef.current.setPreviewError(null);
912
+ setPreviewRef.current.setPreviewComponent(() => Comp);
913
+ setPreviewRef.current.setPreviewCombinations(combos || []);
914
+ setPreviewRef.current.setPreviewDefaultChildren(children || exportName);
915
+ setPreviewRef.current.setShowPreview(true);
916
+ window.parent.postMessage(
917
+ { type: "tool:previewReady", cellCount: (combos || []).length },
918
+ "*"
919
+ );
920
+ }).catch((err) => {
921
+ setPreviewRef.current.setPreviewError(`Failed to load component: ${err.message}`);
922
+ setPreviewRef.current.setShowPreview(true);
923
+ });
924
+ break;
925
+ }
926
+ case "tool:exitPreview": {
927
+ setPreviewRef.current.setShowPreview(false);
928
+ setPreviewRef.current.setPreviewComponent(null);
929
+ setPreviewRef.current.setPreviewCombinations([]);
930
+ setPreviewRef.current.setPreviewDefaultChildren("");
931
+ setPreviewRef.current.setPreviewError(null);
932
+ enterSelectionMode();
933
+ break;
934
+ }
935
+ }
936
+ }
937
+ function notifyPathChanged() {
938
+ const fullPath = window.location.pathname + window.location.search + window.location.hash;
939
+ window.parent.postMessage({ type: "tool:pathChanged", path: fullPath }, "*");
940
+ }
941
+ document.addEventListener("mousemove", onMouseMove, true);
942
+ document.addEventListener("mouseleave", onMouseLeave);
943
+ document.addEventListener("click", onClick, true);
944
+ window.addEventListener("message", onMessage);
945
+ window.addEventListener("popstate", notifyPathChanged);
946
+ window.parent.postMessage({ type: "tool:injectedReady" }, "*");
947
+ notifyPathChanged();
948
+ return () => {
949
+ document.removeEventListener("mousemove", onMouseMove, true);
950
+ document.removeEventListener("mouseleave", onMouseLeave);
951
+ document.removeEventListener("click", onClick, true);
952
+ window.removeEventListener("message", onMessage);
953
+ window.removeEventListener("popstate", notifyPathChanged);
954
+ treeObserver.disconnect();
955
+ if (debounceTimer) clearTimeout(debounceTimer);
956
+ if (s.overlayRafId) cancelAnimationFrame(s.overlayRafId);
957
+ s.tokenPreviewStyle?.remove();
958
+ s.highlightOverlay?.remove();
959
+ s.tooltip?.remove();
960
+ s.selectedOverlay?.remove();
961
+ };
962
+ }, []);
963
+ if (!showPreview) return null;
964
+ if (previewError) {
965
+ return createPortal(
966
+ /* @__PURE__ */ jsx("div", { style: {
967
+ position: "fixed",
968
+ inset: 0,
969
+ zIndex: 999999,
970
+ background: "var(--background, white)",
971
+ overflow: "auto",
972
+ padding: 32
973
+ }, children: /* @__PURE__ */ jsx("div", { style: { color: "var(--destructive, #ef4444)", fontFamily: "monospace", fontSize: 14 }, children: previewError }) }),
974
+ document.body
975
+ );
976
+ }
977
+ if (!previewComponent) {
978
+ return createPortal(
979
+ /* @__PURE__ */ jsx("div", { style: {
980
+ position: "fixed",
981
+ inset: 0,
982
+ zIndex: 999999,
983
+ background: "var(--background, white)",
984
+ overflow: "auto",
985
+ padding: 32
986
+ }, children: /* @__PURE__ */ jsx("div", { style: { color: "var(--muted-foreground, #888)", fontFamily: "inherit", fontSize: 14 }, children: "Loading component..." }) }),
987
+ document.body
988
+ );
989
+ }
990
+ const Component = previewComponent;
991
+ return createPortal(
992
+ /* @__PURE__ */ jsx("div", { style: {
993
+ position: "fixed",
994
+ inset: 0,
995
+ zIndex: 999999,
996
+ background: "var(--background, white)",
997
+ overflow: "auto",
998
+ padding: 32
999
+ }, children: /* @__PURE__ */ jsx("div", { style: {
1000
+ display: "grid",
1001
+ gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))",
1002
+ gap: 24
1003
+ }, children: previewCombinations.map((combo, i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1004
+ /* @__PURE__ */ jsx("div", { style: {
1005
+ fontSize: 11,
1006
+ fontWeight: 600,
1007
+ color: "var(--muted-foreground, #888)",
1008
+ textTransform: "uppercase",
1009
+ letterSpacing: "0.05em"
1010
+ }, children: combo.label }),
1011
+ /* @__PURE__ */ jsx("div", { style: {
1012
+ padding: 16,
1013
+ border: "1px solid var(--border, #e5e7eb)",
1014
+ borderRadius: 8,
1015
+ display: "flex",
1016
+ alignItems: "center",
1017
+ justifyContent: "center",
1018
+ minHeight: 64,
1019
+ background: "var(--card, var(--background, #fff))"
1020
+ }, children: createElement(Component, combo.props, previewDefaultChildren) })
1021
+ ] }, i)) }) }),
1022
+ document.body
1023
+ );
1024
+ }
1025
+ export {
1026
+ Surface
1027
+ };