made-refine 0.2.13 → 0.2.16

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.
package/dist/index.mjs CHANGED
@@ -117,6 +117,228 @@ function getZoomScale() {
117
117
  return snap.active ? snap.zoom : 1;
118
118
  }
119
119
 
120
+ // src/utils/react-fiber.ts
121
+ function getFiberForElement(element) {
122
+ if (typeof window !== "undefined") {
123
+ const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
124
+ if (devtools?.getFiberForElement) {
125
+ const fiber = devtools.getFiberForElement(element);
126
+ if (fiber) return fiber;
127
+ }
128
+ }
129
+ const fiberKey = Object.keys(element).find(
130
+ (key) => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")
131
+ );
132
+ if (!fiberKey) return null;
133
+ return element[fiberKey] || null;
134
+ }
135
+ function getSourceFromFiber(fiber) {
136
+ const debugSource = fiber?._debugSource;
137
+ if (debugSource?.fileName) return debugSource;
138
+ const owner = fiber?._debugOwner;
139
+ const ownerPending = owner?.pendingProps?.__source;
140
+ if (ownerPending?.fileName) return ownerPending;
141
+ const ownerMemo = owner?.memoizedProps?.__source;
142
+ if (ownerMemo?.fileName) return ownerMemo;
143
+ const pending = fiber?.pendingProps?.__source;
144
+ if (pending?.fileName) return pending;
145
+ const memo = fiber?.memoizedProps?.__source;
146
+ if (memo?.fileName) return memo;
147
+ return null;
148
+ }
149
+ function buildFrame(fiber) {
150
+ const type = fiber?.type;
151
+ if (typeof type !== "function" && typeof type !== "object") return null;
152
+ const name = type?.displayName || type?.name || null;
153
+ if (!name || name === "Fragment") return null;
154
+ const frame = { name };
155
+ const source = getSourceFromFiber(fiber);
156
+ if (source?.fileName) {
157
+ frame.file = source.fileName;
158
+ if (typeof source.lineNumber === "number") {
159
+ frame.line = source.lineNumber;
160
+ }
161
+ if (typeof source.columnNumber === "number") {
162
+ frame.column = source.columnNumber;
163
+ }
164
+ }
165
+ return frame;
166
+ }
167
+ function shouldIncludeFrame(frame, lastFrame) {
168
+ if (!lastFrame) return true;
169
+ if (frame.name !== lastFrame.name) return true;
170
+ if (!lastFrame.file && frame.file) return true;
171
+ if (lastFrame.file && frame.file && lastFrame.line == null && frame.line != null) return true;
172
+ if (lastFrame.file && frame.file && lastFrame.line != null && frame.line != null && lastFrame.column == null && frame.column != null) {
173
+ return true;
174
+ }
175
+ return false;
176
+ }
177
+ function getOwnerStack(fiber) {
178
+ const frames = [];
179
+ let current = fiber;
180
+ let lastFrame = null;
181
+ let nearestComponentFiber = null;
182
+ while (current) {
183
+ const frame = buildFrame(current);
184
+ if (frame && shouldIncludeFrame(frame, lastFrame)) {
185
+ frames.push(frame);
186
+ lastFrame = frame;
187
+ if (!nearestComponentFiber) {
188
+ nearestComponentFiber = current;
189
+ }
190
+ }
191
+ current = current._debugOwner;
192
+ }
193
+ return { frames, nearestComponentFiber };
194
+ }
195
+ function getRenderStack(fiber) {
196
+ const frames = [];
197
+ let current = fiber;
198
+ let lastFrame = null;
199
+ let nearestComponentFiber = null;
200
+ while (current) {
201
+ const frame = buildFrame(current);
202
+ if (frame && shouldIncludeFrame(frame, lastFrame)) {
203
+ frames.push(frame);
204
+ lastFrame = frame;
205
+ if (!nearestComponentFiber) {
206
+ nearestComponentFiber = current;
207
+ }
208
+ }
209
+ current = current.return;
210
+ }
211
+ return { frames, nearestComponentFiber };
212
+ }
213
+ function getReactComponentInfo(element) {
214
+ const fiber = getFiberForElement(element);
215
+ if (!fiber) return { frames: [], nearestComponentFiber: null };
216
+ const elementSource = getSourceFromFiber(fiber);
217
+ const elementSourceFile = elementSource?.fileName || void 0;
218
+ const ownerResult = getOwnerStack(fiber);
219
+ if (ownerResult.frames.length > 0) {
220
+ return { ...ownerResult, elementSourceFile };
221
+ }
222
+ return { ...getRenderStack(fiber), elementSourceFile };
223
+ }
224
+ var EXCLUDED_PROP_KEYS = /* @__PURE__ */ new Set([
225
+ "className",
226
+ "style",
227
+ "children",
228
+ "ref",
229
+ "key",
230
+ "render"
231
+ ]);
232
+ function serializePropValue(value) {
233
+ if (typeof value === "function") return "[function]";
234
+ if (typeof value === "symbol") return void 0;
235
+ if (value === void 0) return void 0;
236
+ if (value !== null && typeof value === "object") {
237
+ if ("$$typeof" in value) return "[element]";
238
+ try {
239
+ JSON.stringify(value);
240
+ return value;
241
+ } catch {
242
+ return "[object]";
243
+ }
244
+ }
245
+ return value;
246
+ }
247
+ function getComponentProps(fiber) {
248
+ const props = fiber?.memoizedProps ?? fiber?.pendingProps;
249
+ if (!props || typeof props !== "object") return {};
250
+ const result = {};
251
+ for (const [key, value] of Object.entries(props)) {
252
+ if (EXCLUDED_PROP_KEYS.has(key)) continue;
253
+ if (key.startsWith("data-")) continue;
254
+ const serialized = serializePropValue(value);
255
+ if (serialized !== void 0) {
256
+ result[key] = serialized;
257
+ }
258
+ }
259
+ return result;
260
+ }
261
+ function getCallSiteSource(fiber) {
262
+ const source = fiber?._debugSource;
263
+ if (source?.fileName) {
264
+ return {
265
+ file: source.fileName,
266
+ line: typeof source.lineNumber === "number" ? source.lineNumber : void 0,
267
+ column: typeof source.columnNumber === "number" ? source.columnNumber : void 0
268
+ };
269
+ }
270
+ const pending = fiber?.pendingProps?.__source;
271
+ if (pending?.fileName) {
272
+ return {
273
+ file: pending.fileName,
274
+ line: typeof pending.lineNumber === "number" ? pending.lineNumber : void 0,
275
+ column: typeof pending.columnNumber === "number" ? pending.columnNumber : void 0
276
+ };
277
+ }
278
+ return null;
279
+ }
280
+ function deriveDefinitionSource(frames) {
281
+ for (const frame of frames) {
282
+ if (frame.file && isComponentPrimitivePath(frame.file)) {
283
+ return { file: frame.file, line: frame.line, column: frame.column };
284
+ }
285
+ }
286
+ return null;
287
+ }
288
+ var PRIMITIVE_PATH_PATTERNS = [
289
+ /\/components\/ui\//,
290
+ /\/ui\/primitives\//,
291
+ /\/design-system\//
292
+ ];
293
+ var PRIMITIVE_NPM_PATTERNS = [
294
+ /@base-ui\//,
295
+ /@radix-ui\//,
296
+ /@headlessui\//,
297
+ /@chakra-ui\//,
298
+ /@mantine\//,
299
+ /@mui\//,
300
+ /@ark-ui\//
301
+ ];
302
+ var FRAMEWORK_EXCLUSION_PATTERNS = [
303
+ /node_modules\/react\//,
304
+ /node_modules\/react-dom\//,
305
+ /node_modules\/next\/dist\//,
306
+ /node_modules\/scheduler\//,
307
+ /node_modules\/react-server\//
308
+ ];
309
+ function isComponentPrimitivePath(filePath) {
310
+ const normalized = filePath.replace(/\\/g, "/");
311
+ for (const pattern of FRAMEWORK_EXCLUSION_PATTERNS) {
312
+ if (pattern.test(normalized)) return false;
313
+ }
314
+ for (const pattern of PRIMITIVE_NPM_PATTERNS) {
315
+ if (pattern.test(normalized)) return true;
316
+ }
317
+ for (const pattern of PRIMITIVE_PATH_PATTERNS) {
318
+ if (pattern.test(normalized)) return true;
319
+ }
320
+ return false;
321
+ }
322
+ function classifyComponentFiber(fiber, frames, elementSourceFile) {
323
+ if (elementSourceFile && isComponentPrimitivePath(elementSourceFile)) {
324
+ return { isComponentPrimitive: true };
325
+ }
326
+ if (!fiber) return { isComponentPrimitive: false };
327
+ const callSite = getCallSiteSource(fiber);
328
+ if (callSite?.file && isComponentPrimitivePath(callSite.file)) {
329
+ return { isComponentPrimitive: true };
330
+ }
331
+ for (const frame of frames) {
332
+ if (frame.file && isComponentPrimitivePath(frame.file)) {
333
+ return { isComponentPrimitive: true };
334
+ }
335
+ }
336
+ if (!elementSourceFile && fiber._debugSource) {
337
+ return { isComponentPrimitive: true };
338
+ }
339
+ return { isComponentPrimitive: false };
340
+ }
341
+
120
342
  // src/utils.ts
121
343
  function clamp(value, min, max) {
122
344
  if (!Number.isFinite(value)) return min;
@@ -1504,7 +1726,7 @@ function calculateDropPosition(container, pointerX, pointerY, draggedElement) {
1504
1726
  };
1505
1727
  return { insertBefore, indicator };
1506
1728
  }
1507
- function getFiberForElement(element) {
1729
+ function getFiberForElement2(element) {
1508
1730
  if (typeof window !== "undefined") {
1509
1731
  const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
1510
1732
  if (devtools?.getFiberForElement) {
@@ -1765,7 +1987,7 @@ function getSourceFromDebugStack(fiber) {
1765
1987
  }
1766
1988
  return null;
1767
1989
  }
1768
- function getSourceFromFiber(fiber) {
1990
+ function getSourceFromFiber2(fiber) {
1769
1991
  const debugSource = fiber?._debugSource;
1770
1992
  if (debugSource?.fileName) return debugSource;
1771
1993
  const owner = fiber?._debugOwner;
@@ -1781,13 +2003,13 @@ function getSourceFromFiber(fiber) {
1781
2003
  if (fromDebugStack?.fileName) return fromDebugStack;
1782
2004
  return null;
1783
2005
  }
1784
- function buildFrame(fiber) {
2006
+ function buildFrame2(fiber) {
1785
2007
  const type = fiber?.type;
1786
2008
  if (typeof type !== "function" && typeof type !== "object") return null;
1787
2009
  const name = type?.displayName || type?.name || null;
1788
2010
  if (!name || name === "Fragment") return null;
1789
2011
  const frame = { name };
1790
- const source = getSourceFromFiber(fiber);
2012
+ const source = getSourceFromFiber2(fiber);
1791
2013
  if (source?.fileName) {
1792
2014
  frame.file = source.fileName;
1793
2015
  if (typeof source.lineNumber === "number") {
@@ -1799,7 +2021,7 @@ function buildFrame(fiber) {
1799
2021
  }
1800
2022
  return frame;
1801
2023
  }
1802
- function shouldIncludeFrame(frame, lastFrame) {
2024
+ function shouldIncludeFrame2(frame, lastFrame) {
1803
2025
  if (!lastFrame) return true;
1804
2026
  if (frame.name !== lastFrame.name) return true;
1805
2027
  if (!lastFrame.file && frame.file) return true;
@@ -1809,42 +2031,52 @@ function shouldIncludeFrame(frame, lastFrame) {
1809
2031
  }
1810
2032
  return false;
1811
2033
  }
1812
- function getOwnerStack(fiber) {
2034
+ function getOwnerStack2(fiber) {
1813
2035
  const frames = [];
1814
2036
  let current = fiber;
1815
2037
  let lastFrame = null;
2038
+ let nearestComponentFiber = null;
1816
2039
  while (current) {
1817
- const frame = buildFrame(current);
1818
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2040
+ const frame = buildFrame2(current);
2041
+ if (frame && shouldIncludeFrame2(frame, lastFrame)) {
1819
2042
  frames.push(frame);
1820
2043
  lastFrame = frame;
2044
+ if (!nearestComponentFiber) {
2045
+ nearestComponentFiber = current;
2046
+ }
1821
2047
  }
1822
2048
  current = current._debugOwner;
1823
2049
  }
1824
- return frames;
2050
+ return { frames, nearestComponentFiber };
1825
2051
  }
1826
- function getRenderStack(fiber) {
2052
+ function getRenderStack2(fiber) {
1827
2053
  const frames = [];
1828
2054
  let current = fiber;
1829
2055
  let lastFrame = null;
2056
+ let nearestComponentFiber = null;
1830
2057
  while (current) {
1831
- const frame = buildFrame(current);
1832
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2058
+ const frame = buildFrame2(current);
2059
+ if (frame && shouldIncludeFrame2(frame, lastFrame)) {
1833
2060
  frames.push(frame);
1834
2061
  lastFrame = frame;
2062
+ if (!nearestComponentFiber) {
2063
+ nearestComponentFiber = current;
2064
+ }
1835
2065
  }
1836
2066
  current = current.return;
1837
2067
  }
1838
- return frames;
2068
+ return { frames, nearestComponentFiber };
1839
2069
  }
1840
- function getReactComponentStack(element) {
1841
- const fiber = getFiberForElement(element);
1842
- if (!fiber) return [];
1843
- const ownerStack = getOwnerStack(fiber);
1844
- if (ownerStack.length > 0) {
1845
- return ownerStack;
2070
+ function getReactComponentInfo2(element) {
2071
+ const fiber = getFiberForElement2(element);
2072
+ if (!fiber) return { frames: [], nearestComponentFiber: null };
2073
+ const elementSource = getSourceFromFiber2(fiber);
2074
+ const elementSourceFile = elementSource?.fileName || void 0;
2075
+ const ownerResult = getOwnerStack2(fiber);
2076
+ if (ownerResult.frames.length > 0) {
2077
+ return { ...ownerResult, elementSourceFile };
1846
2078
  }
1847
- return getRenderStack(fiber);
2079
+ return { ...getRenderStack2(fiber), elementSourceFile };
1848
2080
  }
1849
2081
  function getElementDisplayName(element) {
1850
2082
  const tag = element.tagName.toLowerCase();
@@ -2139,14 +2371,35 @@ function parseDomSource(element) {
2139
2371
  }
2140
2372
  return { file, line, column };
2141
2373
  }
2374
+ var MAX_SUB_ELEMENT_SOURCES = 20;
2375
+ function collectSubElementSources(element) {
2376
+ const sources = {};
2377
+ const children = element.querySelectorAll("[data-direct-edit-source]");
2378
+ const labelCounts = /* @__PURE__ */ new Map();
2379
+ let count = 0;
2380
+ for (const child of children) {
2381
+ if (count >= MAX_SUB_ELEMENT_SOURCES) break;
2382
+ if (!(child instanceof HTMLElement)) continue;
2383
+ const source = parseDomSource(child);
2384
+ if (!source) continue;
2385
+ const text = ((child.innerText || child.textContent) ?? "").trim();
2386
+ let baseLabel = text.length > 0 && text.length <= 30 ? text.slice(0, 30).toLowerCase().replace(/\s+/g, "_") : child.tagName.toLowerCase();
2387
+ const existing = labelCounts.get(baseLabel) ?? 0;
2388
+ labelCounts.set(baseLabel, existing + 1);
2389
+ const label = existing > 0 ? `${baseLabel}_${existing + 1}` : baseLabel;
2390
+ sources[label] = source;
2391
+ count++;
2392
+ }
2393
+ return sources;
2394
+ }
2142
2395
  function getElementSource(element) {
2143
2396
  const domSource = parseDomSource(element);
2144
2397
  if (domSource) return domSource;
2145
2398
  const seenFibers = /* @__PURE__ */ new Set();
2146
- let fiber = getFiberForElement(element);
2399
+ let fiber = getFiberForElement2(element);
2147
2400
  while (fiber && !seenFibers.has(fiber)) {
2148
2401
  seenFibers.add(fiber);
2149
- const fiberSource = getSourceFromFiber(fiber);
2402
+ const fiberSource = getSourceFromFiber2(fiber);
2150
2403
  if (fiberSource?.fileName) {
2151
2404
  return {
2152
2405
  file: fiberSource.fileName,
@@ -2161,8 +2414,15 @@ function getElementSource(element) {
2161
2414
  function getElementLocator(element) {
2162
2415
  const elementInfo = getElementInfo(element);
2163
2416
  const domSource = getElementSource(element);
2417
+ const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo2(element);
2418
+ const componentName = nearestComponentFiber?.type?.displayName || nearestComponentFiber?.type?.name || void 0;
2419
+ const authoredProps = nearestComponentFiber ? getComponentProps(nearestComponentFiber) : void 0;
2420
+ const classification = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile);
2421
+ const callSite = nearestComponentFiber ? getCallSiteSource(nearestComponentFiber) : null;
2422
+ const definitionSrc = classification.isComponentPrimitive ? deriveDefinitionSource(frames) : null;
2423
+ const subSources = collectSubElementSources(element);
2164
2424
  return {
2165
- reactStack: getReactComponentStack(element),
2425
+ reactStack: frames,
2166
2426
  domSelector: buildDomSelector(element),
2167
2427
  domContextHtml: buildDomContextHtml(element),
2168
2428
  targetHtml: buildTargetHtml(element),
@@ -2170,36 +2430,80 @@ function getElementLocator(element) {
2170
2430
  tagName: elementInfo.tagName,
2171
2431
  id: elementInfo.id,
2172
2432
  classList: elementInfo.classList,
2173
- domSource: domSource ?? void 0
2433
+ domSource: domSource ?? void 0,
2434
+ reactComponentName: componentName,
2435
+ authoredProps: authoredProps && Object.keys(authoredProps).length > 0 ? authoredProps : void 0,
2436
+ subElementSources: Object.keys(subSources).length > 0 ? subSources : void 0,
2437
+ callSiteSource: callSite ?? void 0,
2438
+ definitionSource: definitionSrc ?? void 0,
2439
+ isComponentPrimitive: nearestComponentFiber || elementSourceFile ? classification.isComponentPrimitive : void 0
2174
2440
  };
2175
2441
  }
2176
2442
  function getLocatorHeader(locator) {
2177
2443
  const primaryFrame = getPrimaryFrame(locator);
2178
- const componentLabel = primaryFrame?.name ? primaryFrame.name : locator.tagName;
2179
- const formattedSource = locator.domSource?.file ? formatSourceLocation(locator.domSource.file, locator.domSource.line, locator.domSource.column) : primaryFrame?.file ? formatSourceLocation(primaryFrame.file, primaryFrame.line, primaryFrame.column) : null;
2180
- return { componentLabel, formattedSource };
2444
+ const componentLabel = locator.reactComponentName ?? primaryFrame?.name ?? locator.tagName;
2445
+ let formattedSource;
2446
+ if (locator.isComponentPrimitive && locator.definitionSource?.file) {
2447
+ formattedSource = formatSourceLocation(
2448
+ locator.definitionSource.file,
2449
+ locator.definitionSource.line,
2450
+ locator.definitionSource.column
2451
+ );
2452
+ } else {
2453
+ formattedSource = locator.domSource?.file ? formatSourceLocation(locator.domSource.file, locator.domSource.line, locator.domSource.column) : primaryFrame?.file ? formatSourceLocation(primaryFrame.file, primaryFrame.line, primaryFrame.column) : null;
2454
+ }
2455
+ const formattedCallSite = locator.callSiteSource?.file ? formatSourceLocation(locator.callSiteSource.file, locator.callSiteSource.line, locator.callSiteSource.column) : null;
2456
+ return { componentLabel, formattedSource, formattedCallSite };
2457
+ }
2458
+ function formatComponentTree(reactStack) {
2459
+ const names = reactStack.map((f) => f.name).filter(Boolean);
2460
+ if (names.length === 0) return null;
2461
+ if (names.length === 1) return names[0];
2462
+ const [component, ...ancestors] = names;
2463
+ return `${component} (in ${ancestors.join(" > ")})`;
2181
2464
  }
2182
2465
  function buildLocatorContextLines(locator, options) {
2183
2466
  const lines = [];
2184
- const { componentLabel, formattedSource } = getLocatorHeader(locator);
2467
+ const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
2185
2468
  const target = (locator.targetHtml || locator.domContextHtml || "").trim();
2186
2469
  const context = locator.domContextHtml?.trim() || "";
2187
- const selector = locator.domSelector?.trim();
2470
+ const path = locator.domSelector?.trim();
2188
2471
  const text = locator.textPreview?.trim();
2189
2472
  lines.push(`@<${componentLabel}>`);
2190
2473
  lines.push("");
2474
+ const tree = formatComponentTree(locator.reactStack);
2475
+ if (tree) {
2476
+ lines.push(`react: ${tree}`);
2477
+ }
2478
+ if (locator.authoredProps && Object.keys(locator.authoredProps).length > 0) {
2479
+ lines.push(`props: ${JSON.stringify(locator.authoredProps)}`);
2480
+ }
2481
+ if (locator.isComponentPrimitive != null) {
2482
+ lines.push(`type: ${locator.isComponentPrimitive ? "component" : "instance"}`);
2483
+ }
2484
+ lines.push(`source: ${formattedSource ?? "(file not available)"}`);
2485
+ if (formattedCallSite && formattedCallSite !== formattedSource) {
2486
+ lines.push(`call-site: ${formattedCallSite}`);
2487
+ }
2488
+ if (locator.subElementSources && Object.keys(locator.subElementSources).length > 0) {
2489
+ lines.push("source-map:");
2490
+ for (const [label, source] of Object.entries(locator.subElementSources)) {
2491
+ lines.push(` - ${label}: ${formatSourceLocation(source.file, source.line, source.column)}`);
2492
+ }
2493
+ }
2494
+ if (path) {
2495
+ lines.push(`path: ${path}`);
2496
+ }
2191
2497
  if (target) {
2498
+ lines.push("");
2192
2499
  lines.push("target:");
2193
2500
  lines.push(target);
2194
2501
  }
2195
2502
  if (!options?.skipContext && context && context !== target) {
2503
+ lines.push("");
2196
2504
  lines.push("context:");
2197
2505
  lines.push(context);
2198
2506
  }
2199
- lines.push(`in ${formattedSource ?? "(file not available)"}`);
2200
- if (selector) {
2201
- lines.push(`selector: ${selector}`);
2202
- }
2203
2507
  if (text) {
2204
2508
  lines.push(`text: ${text}`);
2205
2509
  }
@@ -3944,6 +4248,8 @@ function useSessionManager({
3944
4248
  const originalStyles = options?.originalStyles ?? existingEdit?.originalStyles ?? getOriginalInlineStyles(nextSingleElement);
3945
4249
  const pendingStyles = options?.pendingStyles ?? existingEdit?.pendingStyles ?? {};
3946
4250
  const elementInfo = getElementInfo(nextSingleElement);
4251
+ const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo(nextSingleElement);
4252
+ const isPrimitive = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile).isComponentPrimitive;
3947
4253
  setState((prev) => ({
3948
4254
  comments: prev.activeCommentId ? prev.comments.filter((comment) => {
3949
4255
  if (comment.id !== prev.activeCommentId) return true;
@@ -3962,6 +4268,7 @@ function useSessionManager({
3962
4268
  computedColor: computed.color,
3963
4269
  computedBoxShadow: computed.boxShadow,
3964
4270
  computedTypography: computed.typography,
4271
+ isComponentPrimitive: isPrimitive,
3965
4272
  originalStyles,
3966
4273
  pendingStyles,
3967
4274
  editModeActive: prev.editModeActive,
@@ -3992,6 +4299,7 @@ function useSessionManager({
3992
4299
  computedColor: null,
3993
4300
  computedBoxShadow: null,
3994
4301
  computedTypography: null,
4302
+ isComponentPrimitive: false,
3995
4303
  originalStyles: {},
3996
4304
  pendingStyles: {},
3997
4305
  activeCommentId: null,
@@ -4532,6 +4840,7 @@ function useSessionManager({
4532
4840
  computedColor: computed.color,
4533
4841
  computedBoxShadow: computed.boxShadow,
4534
4842
  computedTypography: computed.typography,
4843
+ isComponentPrimitive: prev.isComponentPrimitive,
4535
4844
  originalStyles: styleState.originalStyles,
4536
4845
  pendingStyles: styleState.pendingStyles,
4537
4846
  editModeActive: prev.editModeActive,
@@ -5316,6 +5625,8 @@ function withInstruction(profile, markdown) {
5316
5625
  ${markdown}` : markdown;
5317
5626
  }
5318
5627
  function buildLocatorPayload(locator) {
5628
+ const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
5629
+ const reactTree = formatComponentTree(locator.reactStack);
5319
5630
  return {
5320
5631
  element: {
5321
5632
  tagName: locator.tagName,
@@ -5323,10 +5634,22 @@ function buildLocatorPayload(locator) {
5323
5634
  classList: locator.classList,
5324
5635
  domSelector: locator.domSelector,
5325
5636
  targetHtml: locator.targetHtml,
5637
+ contextHtml: locator.domContextHtml || null,
5326
5638
  textPreview: locator.textPreview
5327
5639
  },
5328
- source: locator.domSource || null,
5329
- reactStack: locator.reactStack
5640
+ componentLabel,
5641
+ reactTree,
5642
+ reactStack: locator.reactStack,
5643
+ reactComponentName: locator.reactComponentName ?? null,
5644
+ authoredProps: locator.authoredProps ?? null,
5645
+ type: locator.isComponentPrimitive != null ? locator.isComponentPrimitive ? "component" : "instance" : null,
5646
+ isComponentPrimitive: locator.isComponentPrimitive ?? false,
5647
+ source: formattedSource,
5648
+ callSite: formattedCallSite,
5649
+ rawSource: locator.domSource || null,
5650
+ callSiteSource: locator.callSiteSource ?? null,
5651
+ definitionSource: locator.definitionSource ?? null,
5652
+ subElementSources: locator.subElementSources ?? null
5330
5653
  };
5331
5654
  }
5332
5655
  function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrentToSession, removeSessionEdit, deleteComment }) {
@@ -6302,6 +6625,7 @@ function DirectEditProvider({ children }) {
6302
6625
  computedColor: null,
6303
6626
  computedBoxShadow: null,
6304
6627
  computedTypography: null,
6628
+ isComponentPrimitive: false,
6305
6629
  originalStyles: {},
6306
6630
  pendingStyles: {},
6307
6631
  editModeActive: false,
@@ -8594,6 +8918,7 @@ function useSelectionResize({
8594
8918
  import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
8595
8919
  var BLUE3 = "#0D99FF";
8596
8920
  var MAGENTA = "#E11BB6";
8921
+ var COMPONENT_PURPLE = "#8B5CF6";
8597
8922
  var DRAG_THRESHOLD = 4;
8598
8923
  var DBLCLICK_DELAY = 300;
8599
8924
  var HANDLE_SIZE = 12;
@@ -8637,9 +8962,11 @@ function SelectionOverlay({
8637
8962
  onHoverElement,
8638
8963
  onClickThrough,
8639
8964
  onSelectPageFrame,
8965
+ isComponentPrimitive = false,
8640
8966
  enableResizeHandles = false,
8641
8967
  onResizeSizingChange
8642
8968
  }) {
8969
+ const selectionColor = isComponentPrimitive ? COMPONENT_PURPLE : BLUE3;
8643
8970
  const rectElement = isDragging && draggedElement ? draggedElement : selectedElement;
8644
8971
  const [rect, setRect] = React19.useState(() => rectElement.getBoundingClientRect());
8645
8972
  const [pageFrameRect, setPageFrameRect] = React19.useState(() => pageFrameElement ? pageFrameElement.getBoundingClientRect() : null);
@@ -8967,7 +9294,7 @@ function SelectionOverlay({
8967
9294
  zIndex: 99997,
8968
9295
  background: "transparent",
8969
9296
  border: "none",
8970
- color: BLUE3,
9297
+ color: selectionColor,
8971
9298
  fontSize: `${pageLabelFontSize}px`,
8972
9299
  lineHeight: `${pageLabelLineHeight}px`,
8973
9300
  padding: 0,
@@ -8995,7 +9322,7 @@ function SelectionOverlay({
8995
9322
  height: rect.height,
8996
9323
  pointerEvents: "none",
8997
9324
  zIndex: 99996,
8998
- border: `1px solid ${BLUE3}`,
9325
+ border: `1px solid ${selectionColor}`,
8999
9326
  borderRadius: "0px",
9000
9327
  boxSizing: "border-box"
9001
9328
  }
@@ -9012,18 +9339,28 @@ function SelectionOverlay({
9012
9339
  transform: "translateX(-50%)",
9013
9340
  pointerEvents: "none",
9014
9341
  zIndex: 99992,
9015
- background: BLUE3,
9016
- color: "white",
9017
- fontSize: "11px",
9018
- lineHeight: "20px",
9019
- padding: "0 6px",
9020
- borderRadius: "4px",
9021
- whiteSpace: "nowrap",
9022
- fontFamily: "system-ui, sans-serif",
9023
- fontWeight: 500,
9024
- letterSpacing: "-0.01em"
9342
+ display: "flex",
9343
+ alignItems: "center",
9344
+ gap: "4px"
9025
9345
  },
9026
- children: dimensionText
9346
+ children: /* @__PURE__ */ jsx9(
9347
+ "span",
9348
+ {
9349
+ style: {
9350
+ background: selectionColor,
9351
+ color: "white",
9352
+ fontSize: "11px",
9353
+ lineHeight: "20px",
9354
+ padding: "0 6px",
9355
+ borderRadius: "4px",
9356
+ whiteSpace: "nowrap",
9357
+ fontFamily: "system-ui, sans-serif",
9358
+ fontWeight: 500,
9359
+ letterSpacing: "-0.01em"
9360
+ },
9361
+ children: dimensionText
9362
+ }
9363
+ )
9027
9364
  }
9028
9365
  ),
9029
9366
  !isDragging && !isTextEditing && /* @__PURE__ */ jsxs5(
@@ -9079,7 +9416,7 @@ function SelectionOverlay({
9079
9416
  position: "absolute",
9080
9417
  width: RESIZE_CORNER_SIZE,
9081
9418
  height: RESIZE_CORNER_SIZE,
9082
- border: `1px solid ${BLUE3}`,
9419
+ border: `1px solid ${selectionColor}`,
9083
9420
  background: "#fff",
9084
9421
  borderRadius: 1,
9085
9422
  boxSizing: "border-box",
@@ -12504,6 +12841,7 @@ function DirectEditPanelContent() {
12504
12841
  computedColor,
12505
12842
  computedBoxShadow,
12506
12843
  computedTypography,
12844
+ isComponentPrimitive,
12507
12845
  borderStyleControlPreference,
12508
12846
  pendingStyles,
12509
12847
  editModeActive,
@@ -12824,6 +13162,7 @@ function DirectEditPanelContent() {
12824
13162
  selectElement(child);
12825
13163
  }
12826
13164
  },
13165
+ isComponentPrimitive,
12827
13166
  enableResizeHandles: true,
12828
13167
  onResizeSizingChange: updateSizingProperties
12829
13168
  }