made-refine 0.2.13 → 0.2.15

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,225 @@ 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
+ return { isComponentPrimitive: false };
337
+ }
338
+
120
339
  // src/utils.ts
121
340
  function clamp(value, min, max) {
122
341
  if (!Number.isFinite(value)) return min;
@@ -1504,7 +1723,7 @@ function calculateDropPosition(container, pointerX, pointerY, draggedElement) {
1504
1723
  };
1505
1724
  return { insertBefore, indicator };
1506
1725
  }
1507
- function getFiberForElement(element) {
1726
+ function getFiberForElement2(element) {
1508
1727
  if (typeof window !== "undefined") {
1509
1728
  const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
1510
1729
  if (devtools?.getFiberForElement) {
@@ -1765,7 +1984,7 @@ function getSourceFromDebugStack(fiber) {
1765
1984
  }
1766
1985
  return null;
1767
1986
  }
1768
- function getSourceFromFiber(fiber) {
1987
+ function getSourceFromFiber2(fiber) {
1769
1988
  const debugSource = fiber?._debugSource;
1770
1989
  if (debugSource?.fileName) return debugSource;
1771
1990
  const owner = fiber?._debugOwner;
@@ -1781,13 +2000,13 @@ function getSourceFromFiber(fiber) {
1781
2000
  if (fromDebugStack?.fileName) return fromDebugStack;
1782
2001
  return null;
1783
2002
  }
1784
- function buildFrame(fiber) {
2003
+ function buildFrame2(fiber) {
1785
2004
  const type = fiber?.type;
1786
2005
  if (typeof type !== "function" && typeof type !== "object") return null;
1787
2006
  const name = type?.displayName || type?.name || null;
1788
2007
  if (!name || name === "Fragment") return null;
1789
2008
  const frame = { name };
1790
- const source = getSourceFromFiber(fiber);
2009
+ const source = getSourceFromFiber2(fiber);
1791
2010
  if (source?.fileName) {
1792
2011
  frame.file = source.fileName;
1793
2012
  if (typeof source.lineNumber === "number") {
@@ -1799,7 +2018,7 @@ function buildFrame(fiber) {
1799
2018
  }
1800
2019
  return frame;
1801
2020
  }
1802
- function shouldIncludeFrame(frame, lastFrame) {
2021
+ function shouldIncludeFrame2(frame, lastFrame) {
1803
2022
  if (!lastFrame) return true;
1804
2023
  if (frame.name !== lastFrame.name) return true;
1805
2024
  if (!lastFrame.file && frame.file) return true;
@@ -1809,42 +2028,52 @@ function shouldIncludeFrame(frame, lastFrame) {
1809
2028
  }
1810
2029
  return false;
1811
2030
  }
1812
- function getOwnerStack(fiber) {
2031
+ function getOwnerStack2(fiber) {
1813
2032
  const frames = [];
1814
2033
  let current = fiber;
1815
2034
  let lastFrame = null;
2035
+ let nearestComponentFiber = null;
1816
2036
  while (current) {
1817
- const frame = buildFrame(current);
1818
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2037
+ const frame = buildFrame2(current);
2038
+ if (frame && shouldIncludeFrame2(frame, lastFrame)) {
1819
2039
  frames.push(frame);
1820
2040
  lastFrame = frame;
2041
+ if (!nearestComponentFiber) {
2042
+ nearestComponentFiber = current;
2043
+ }
1821
2044
  }
1822
2045
  current = current._debugOwner;
1823
2046
  }
1824
- return frames;
2047
+ return { frames, nearestComponentFiber };
1825
2048
  }
1826
- function getRenderStack(fiber) {
2049
+ function getRenderStack2(fiber) {
1827
2050
  const frames = [];
1828
2051
  let current = fiber;
1829
2052
  let lastFrame = null;
2053
+ let nearestComponentFiber = null;
1830
2054
  while (current) {
1831
- const frame = buildFrame(current);
1832
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2055
+ const frame = buildFrame2(current);
2056
+ if (frame && shouldIncludeFrame2(frame, lastFrame)) {
1833
2057
  frames.push(frame);
1834
2058
  lastFrame = frame;
2059
+ if (!nearestComponentFiber) {
2060
+ nearestComponentFiber = current;
2061
+ }
1835
2062
  }
1836
2063
  current = current.return;
1837
2064
  }
1838
- return frames;
2065
+ return { frames, nearestComponentFiber };
1839
2066
  }
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;
2067
+ function getReactComponentInfo2(element) {
2068
+ const fiber = getFiberForElement2(element);
2069
+ if (!fiber) return { frames: [], nearestComponentFiber: null };
2070
+ const elementSource = getSourceFromFiber2(fiber);
2071
+ const elementSourceFile = elementSource?.fileName || void 0;
2072
+ const ownerResult = getOwnerStack2(fiber);
2073
+ if (ownerResult.frames.length > 0) {
2074
+ return { ...ownerResult, elementSourceFile };
1846
2075
  }
1847
- return getRenderStack(fiber);
2076
+ return { ...getRenderStack2(fiber), elementSourceFile };
1848
2077
  }
1849
2078
  function getElementDisplayName(element) {
1850
2079
  const tag = element.tagName.toLowerCase();
@@ -2139,14 +2368,35 @@ function parseDomSource(element) {
2139
2368
  }
2140
2369
  return { file, line, column };
2141
2370
  }
2371
+ var MAX_SUB_ELEMENT_SOURCES = 20;
2372
+ function collectSubElementSources(element) {
2373
+ const sources = {};
2374
+ const children = element.querySelectorAll("[data-direct-edit-source]");
2375
+ const labelCounts = /* @__PURE__ */ new Map();
2376
+ let count = 0;
2377
+ for (const child of children) {
2378
+ if (count >= MAX_SUB_ELEMENT_SOURCES) break;
2379
+ if (!(child instanceof HTMLElement)) continue;
2380
+ const source = parseDomSource(child);
2381
+ if (!source) continue;
2382
+ const text = ((child.innerText || child.textContent) ?? "").trim();
2383
+ let baseLabel = text.length > 0 && text.length <= 30 ? text.slice(0, 30).toLowerCase().replace(/\s+/g, "_") : child.tagName.toLowerCase();
2384
+ const existing = labelCounts.get(baseLabel) ?? 0;
2385
+ labelCounts.set(baseLabel, existing + 1);
2386
+ const label = existing > 0 ? `${baseLabel}_${existing + 1}` : baseLabel;
2387
+ sources[label] = source;
2388
+ count++;
2389
+ }
2390
+ return sources;
2391
+ }
2142
2392
  function getElementSource(element) {
2143
2393
  const domSource = parseDomSource(element);
2144
2394
  if (domSource) return domSource;
2145
2395
  const seenFibers = /* @__PURE__ */ new Set();
2146
- let fiber = getFiberForElement(element);
2396
+ let fiber = getFiberForElement2(element);
2147
2397
  while (fiber && !seenFibers.has(fiber)) {
2148
2398
  seenFibers.add(fiber);
2149
- const fiberSource = getSourceFromFiber(fiber);
2399
+ const fiberSource = getSourceFromFiber2(fiber);
2150
2400
  if (fiberSource?.fileName) {
2151
2401
  return {
2152
2402
  file: fiberSource.fileName,
@@ -2161,8 +2411,15 @@ function getElementSource(element) {
2161
2411
  function getElementLocator(element) {
2162
2412
  const elementInfo = getElementInfo(element);
2163
2413
  const domSource = getElementSource(element);
2414
+ const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo2(element);
2415
+ const componentName = nearestComponentFiber?.type?.displayName || nearestComponentFiber?.type?.name || void 0;
2416
+ const authoredProps = nearestComponentFiber ? getComponentProps(nearestComponentFiber) : void 0;
2417
+ const classification = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile);
2418
+ const callSite = nearestComponentFiber ? getCallSiteSource(nearestComponentFiber) : null;
2419
+ const definitionSrc = classification.isComponentPrimitive ? deriveDefinitionSource(frames) : null;
2420
+ const subSources = collectSubElementSources(element);
2164
2421
  return {
2165
- reactStack: getReactComponentStack(element),
2422
+ reactStack: frames,
2166
2423
  domSelector: buildDomSelector(element),
2167
2424
  domContextHtml: buildDomContextHtml(element),
2168
2425
  targetHtml: buildTargetHtml(element),
@@ -2170,36 +2427,80 @@ function getElementLocator(element) {
2170
2427
  tagName: elementInfo.tagName,
2171
2428
  id: elementInfo.id,
2172
2429
  classList: elementInfo.classList,
2173
- domSource: domSource ?? void 0
2430
+ domSource: domSource ?? void 0,
2431
+ reactComponentName: componentName,
2432
+ authoredProps: authoredProps && Object.keys(authoredProps).length > 0 ? authoredProps : void 0,
2433
+ subElementSources: Object.keys(subSources).length > 0 ? subSources : void 0,
2434
+ callSiteSource: callSite ?? void 0,
2435
+ definitionSource: definitionSrc ?? void 0,
2436
+ isComponentPrimitive: nearestComponentFiber || elementSourceFile ? classification.isComponentPrimitive : void 0
2174
2437
  };
2175
2438
  }
2176
2439
  function getLocatorHeader(locator) {
2177
2440
  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 };
2441
+ const componentLabel = locator.reactComponentName ?? primaryFrame?.name ?? locator.tagName;
2442
+ let formattedSource;
2443
+ if (locator.isComponentPrimitive && locator.definitionSource?.file) {
2444
+ formattedSource = formatSourceLocation(
2445
+ locator.definitionSource.file,
2446
+ locator.definitionSource.line,
2447
+ locator.definitionSource.column
2448
+ );
2449
+ } else {
2450
+ formattedSource = locator.domSource?.file ? formatSourceLocation(locator.domSource.file, locator.domSource.line, locator.domSource.column) : primaryFrame?.file ? formatSourceLocation(primaryFrame.file, primaryFrame.line, primaryFrame.column) : null;
2451
+ }
2452
+ const formattedCallSite = locator.callSiteSource?.file ? formatSourceLocation(locator.callSiteSource.file, locator.callSiteSource.line, locator.callSiteSource.column) : null;
2453
+ return { componentLabel, formattedSource, formattedCallSite };
2454
+ }
2455
+ function formatComponentTree(reactStack) {
2456
+ const names = reactStack.map((f) => f.name).filter(Boolean);
2457
+ if (names.length === 0) return null;
2458
+ if (names.length === 1) return names[0];
2459
+ const [component, ...ancestors] = names;
2460
+ return `${component} (in ${ancestors.join(" > ")})`;
2181
2461
  }
2182
2462
  function buildLocatorContextLines(locator, options) {
2183
2463
  const lines = [];
2184
- const { componentLabel, formattedSource } = getLocatorHeader(locator);
2464
+ const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
2185
2465
  const target = (locator.targetHtml || locator.domContextHtml || "").trim();
2186
2466
  const context = locator.domContextHtml?.trim() || "";
2187
- const selector = locator.domSelector?.trim();
2467
+ const path = locator.domSelector?.trim();
2188
2468
  const text = locator.textPreview?.trim();
2189
2469
  lines.push(`@<${componentLabel}>`);
2190
2470
  lines.push("");
2471
+ const tree = formatComponentTree(locator.reactStack);
2472
+ if (tree) {
2473
+ lines.push(`react: ${tree}`);
2474
+ }
2475
+ if (locator.authoredProps && Object.keys(locator.authoredProps).length > 0) {
2476
+ lines.push(`props: ${JSON.stringify(locator.authoredProps)}`);
2477
+ }
2478
+ if (locator.isComponentPrimitive != null) {
2479
+ lines.push(`type: ${locator.isComponentPrimitive ? "component" : "instance"}`);
2480
+ }
2481
+ lines.push(`source: ${formattedSource ?? "(file not available)"}`);
2482
+ if (formattedCallSite && formattedCallSite !== formattedSource) {
2483
+ lines.push(`call-site: ${formattedCallSite}`);
2484
+ }
2485
+ if (locator.subElementSources && Object.keys(locator.subElementSources).length > 0) {
2486
+ lines.push("source-map:");
2487
+ for (const [label, source] of Object.entries(locator.subElementSources)) {
2488
+ lines.push(` - ${label}: ${formatSourceLocation(source.file, source.line, source.column)}`);
2489
+ }
2490
+ }
2491
+ if (path) {
2492
+ lines.push(`path: ${path}`);
2493
+ }
2191
2494
  if (target) {
2495
+ lines.push("");
2192
2496
  lines.push("target:");
2193
2497
  lines.push(target);
2194
2498
  }
2195
2499
  if (!options?.skipContext && context && context !== target) {
2500
+ lines.push("");
2196
2501
  lines.push("context:");
2197
2502
  lines.push(context);
2198
2503
  }
2199
- lines.push(`in ${formattedSource ?? "(file not available)"}`);
2200
- if (selector) {
2201
- lines.push(`selector: ${selector}`);
2202
- }
2203
2504
  if (text) {
2204
2505
  lines.push(`text: ${text}`);
2205
2506
  }
@@ -3944,6 +4245,8 @@ function useSessionManager({
3944
4245
  const originalStyles = options?.originalStyles ?? existingEdit?.originalStyles ?? getOriginalInlineStyles(nextSingleElement);
3945
4246
  const pendingStyles = options?.pendingStyles ?? existingEdit?.pendingStyles ?? {};
3946
4247
  const elementInfo = getElementInfo(nextSingleElement);
4248
+ const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo(nextSingleElement);
4249
+ const isPrimitive = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile).isComponentPrimitive;
3947
4250
  setState((prev) => ({
3948
4251
  comments: prev.activeCommentId ? prev.comments.filter((comment) => {
3949
4252
  if (comment.id !== prev.activeCommentId) return true;
@@ -3962,6 +4265,7 @@ function useSessionManager({
3962
4265
  computedColor: computed.color,
3963
4266
  computedBoxShadow: computed.boxShadow,
3964
4267
  computedTypography: computed.typography,
4268
+ isComponentPrimitive: isPrimitive,
3965
4269
  originalStyles,
3966
4270
  pendingStyles,
3967
4271
  editModeActive: prev.editModeActive,
@@ -3992,6 +4296,7 @@ function useSessionManager({
3992
4296
  computedColor: null,
3993
4297
  computedBoxShadow: null,
3994
4298
  computedTypography: null,
4299
+ isComponentPrimitive: false,
3995
4300
  originalStyles: {},
3996
4301
  pendingStyles: {},
3997
4302
  activeCommentId: null,
@@ -4532,6 +4837,7 @@ function useSessionManager({
4532
4837
  computedColor: computed.color,
4533
4838
  computedBoxShadow: computed.boxShadow,
4534
4839
  computedTypography: computed.typography,
4840
+ isComponentPrimitive: prev.isComponentPrimitive,
4535
4841
  originalStyles: styleState.originalStyles,
4536
4842
  pendingStyles: styleState.pendingStyles,
4537
4843
  editModeActive: prev.editModeActive,
@@ -5316,6 +5622,8 @@ function withInstruction(profile, markdown) {
5316
5622
  ${markdown}` : markdown;
5317
5623
  }
5318
5624
  function buildLocatorPayload(locator) {
5625
+ const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
5626
+ const reactTree = formatComponentTree(locator.reactStack);
5319
5627
  return {
5320
5628
  element: {
5321
5629
  tagName: locator.tagName,
@@ -5323,10 +5631,22 @@ function buildLocatorPayload(locator) {
5323
5631
  classList: locator.classList,
5324
5632
  domSelector: locator.domSelector,
5325
5633
  targetHtml: locator.targetHtml,
5634
+ contextHtml: locator.domContextHtml || null,
5326
5635
  textPreview: locator.textPreview
5327
5636
  },
5328
- source: locator.domSource || null,
5329
- reactStack: locator.reactStack
5637
+ componentLabel,
5638
+ reactTree,
5639
+ reactStack: locator.reactStack,
5640
+ reactComponentName: locator.reactComponentName ?? null,
5641
+ authoredProps: locator.authoredProps ?? null,
5642
+ type: locator.isComponentPrimitive != null ? locator.isComponentPrimitive ? "component" : "instance" : null,
5643
+ isComponentPrimitive: locator.isComponentPrimitive ?? false,
5644
+ source: formattedSource,
5645
+ callSite: formattedCallSite,
5646
+ rawSource: locator.domSource || null,
5647
+ callSiteSource: locator.callSiteSource ?? null,
5648
+ definitionSource: locator.definitionSource ?? null,
5649
+ subElementSources: locator.subElementSources ?? null
5330
5650
  };
5331
5651
  }
5332
5652
  function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrentToSession, removeSessionEdit, deleteComment }) {
@@ -6302,6 +6622,7 @@ function DirectEditProvider({ children }) {
6302
6622
  computedColor: null,
6303
6623
  computedBoxShadow: null,
6304
6624
  computedTypography: null,
6625
+ isComponentPrimitive: false,
6305
6626
  originalStyles: {},
6306
6627
  pendingStyles: {},
6307
6628
  editModeActive: false,
@@ -8594,6 +8915,7 @@ function useSelectionResize({
8594
8915
  import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
8595
8916
  var BLUE3 = "#0D99FF";
8596
8917
  var MAGENTA = "#E11BB6";
8918
+ var COMPONENT_PURPLE = "#8B5CF6";
8597
8919
  var DRAG_THRESHOLD = 4;
8598
8920
  var DBLCLICK_DELAY = 300;
8599
8921
  var HANDLE_SIZE = 12;
@@ -8637,9 +8959,11 @@ function SelectionOverlay({
8637
8959
  onHoverElement,
8638
8960
  onClickThrough,
8639
8961
  onSelectPageFrame,
8962
+ isComponentPrimitive = false,
8640
8963
  enableResizeHandles = false,
8641
8964
  onResizeSizingChange
8642
8965
  }) {
8966
+ const selectionColor = isComponentPrimitive ? COMPONENT_PURPLE : BLUE3;
8643
8967
  const rectElement = isDragging && draggedElement ? draggedElement : selectedElement;
8644
8968
  const [rect, setRect] = React19.useState(() => rectElement.getBoundingClientRect());
8645
8969
  const [pageFrameRect, setPageFrameRect] = React19.useState(() => pageFrameElement ? pageFrameElement.getBoundingClientRect() : null);
@@ -8967,7 +9291,7 @@ function SelectionOverlay({
8967
9291
  zIndex: 99997,
8968
9292
  background: "transparent",
8969
9293
  border: "none",
8970
- color: BLUE3,
9294
+ color: selectionColor,
8971
9295
  fontSize: `${pageLabelFontSize}px`,
8972
9296
  lineHeight: `${pageLabelLineHeight}px`,
8973
9297
  padding: 0,
@@ -8995,7 +9319,7 @@ function SelectionOverlay({
8995
9319
  height: rect.height,
8996
9320
  pointerEvents: "none",
8997
9321
  zIndex: 99996,
8998
- border: `1px solid ${BLUE3}`,
9322
+ border: `1px solid ${selectionColor}`,
8999
9323
  borderRadius: "0px",
9000
9324
  boxSizing: "border-box"
9001
9325
  }
@@ -9012,18 +9336,28 @@ function SelectionOverlay({
9012
9336
  transform: "translateX(-50%)",
9013
9337
  pointerEvents: "none",
9014
9338
  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"
9339
+ display: "flex",
9340
+ alignItems: "center",
9341
+ gap: "4px"
9025
9342
  },
9026
- children: dimensionText
9343
+ children: /* @__PURE__ */ jsx9(
9344
+ "span",
9345
+ {
9346
+ style: {
9347
+ background: selectionColor,
9348
+ color: "white",
9349
+ fontSize: "11px",
9350
+ lineHeight: "20px",
9351
+ padding: "0 6px",
9352
+ borderRadius: "4px",
9353
+ whiteSpace: "nowrap",
9354
+ fontFamily: "system-ui, sans-serif",
9355
+ fontWeight: 500,
9356
+ letterSpacing: "-0.01em"
9357
+ },
9358
+ children: dimensionText
9359
+ }
9360
+ )
9027
9361
  }
9028
9362
  ),
9029
9363
  !isDragging && !isTextEditing && /* @__PURE__ */ jsxs5(
@@ -9079,7 +9413,7 @@ function SelectionOverlay({
9079
9413
  position: "absolute",
9080
9414
  width: RESIZE_CORNER_SIZE,
9081
9415
  height: RESIZE_CORNER_SIZE,
9082
- border: `1px solid ${BLUE3}`,
9416
+ border: `1px solid ${selectionColor}`,
9083
9417
  background: "#fff",
9084
9418
  borderRadius: 1,
9085
9419
  boxSizing: "border-box",
@@ -12504,6 +12838,7 @@ function DirectEditPanelContent() {
12504
12838
  computedColor,
12505
12839
  computedBoxShadow,
12506
12840
  computedTypography,
12841
+ isComponentPrimitive,
12507
12842
  borderStyleControlPreference,
12508
12843
  pendingStyles,
12509
12844
  editModeActive,
@@ -12824,6 +13159,7 @@ function DirectEditPanelContent() {
12824
13159
  selectElement(child);
12825
13160
  }
12826
13161
  },
13162
+ isComponentPrimitive,
12827
13163
  enableResizeHandles: true,
12828
13164
  onResizeSizingChange: updateSizingProperties
12829
13165
  }