made-refine 0.2.11 → 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.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +411 -62
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +411 -62
- package/dist/index.mjs.map +1 -1
- package/dist/{utils-Dn_oW8f_.d.mts → utils-lksVP2Wq.d.mts} +14 -1
- package/dist/{utils-Dn_oW8f_.d.ts → utils-lksVP2Wq.d.ts} +14 -1
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +222 -20
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +220 -20
- package/dist/utils.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -197,6 +197,225 @@ function getZoomScale() {
|
|
|
197
197
|
return snap.active ? snap.zoom : 1;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
// src/utils/react-fiber.ts
|
|
201
|
+
function getFiberForElement(element) {
|
|
202
|
+
if (typeof window !== "undefined") {
|
|
203
|
+
const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
|
|
204
|
+
if (devtools?.getFiberForElement) {
|
|
205
|
+
const fiber = devtools.getFiberForElement(element);
|
|
206
|
+
if (fiber) return fiber;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const fiberKey = Object.keys(element).find(
|
|
210
|
+
(key) => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")
|
|
211
|
+
);
|
|
212
|
+
if (!fiberKey) return null;
|
|
213
|
+
return element[fiberKey] || null;
|
|
214
|
+
}
|
|
215
|
+
function getSourceFromFiber(fiber) {
|
|
216
|
+
const debugSource = fiber?._debugSource;
|
|
217
|
+
if (debugSource?.fileName) return debugSource;
|
|
218
|
+
const owner = fiber?._debugOwner;
|
|
219
|
+
const ownerPending = owner?.pendingProps?.__source;
|
|
220
|
+
if (ownerPending?.fileName) return ownerPending;
|
|
221
|
+
const ownerMemo = owner?.memoizedProps?.__source;
|
|
222
|
+
if (ownerMemo?.fileName) return ownerMemo;
|
|
223
|
+
const pending = fiber?.pendingProps?.__source;
|
|
224
|
+
if (pending?.fileName) return pending;
|
|
225
|
+
const memo = fiber?.memoizedProps?.__source;
|
|
226
|
+
if (memo?.fileName) return memo;
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
function buildFrame(fiber) {
|
|
230
|
+
const type = fiber?.type;
|
|
231
|
+
if (typeof type !== "function" && typeof type !== "object") return null;
|
|
232
|
+
const name = type?.displayName || type?.name || null;
|
|
233
|
+
if (!name || name === "Fragment") return null;
|
|
234
|
+
const frame = { name };
|
|
235
|
+
const source = getSourceFromFiber(fiber);
|
|
236
|
+
if (source?.fileName) {
|
|
237
|
+
frame.file = source.fileName;
|
|
238
|
+
if (typeof source.lineNumber === "number") {
|
|
239
|
+
frame.line = source.lineNumber;
|
|
240
|
+
}
|
|
241
|
+
if (typeof source.columnNumber === "number") {
|
|
242
|
+
frame.column = source.columnNumber;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return frame;
|
|
246
|
+
}
|
|
247
|
+
function shouldIncludeFrame(frame, lastFrame) {
|
|
248
|
+
if (!lastFrame) return true;
|
|
249
|
+
if (frame.name !== lastFrame.name) return true;
|
|
250
|
+
if (!lastFrame.file && frame.file) return true;
|
|
251
|
+
if (lastFrame.file && frame.file && lastFrame.line == null && frame.line != null) return true;
|
|
252
|
+
if (lastFrame.file && frame.file && lastFrame.line != null && frame.line != null && lastFrame.column == null && frame.column != null) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
function getOwnerStack(fiber) {
|
|
258
|
+
const frames = [];
|
|
259
|
+
let current = fiber;
|
|
260
|
+
let lastFrame = null;
|
|
261
|
+
let nearestComponentFiber = null;
|
|
262
|
+
while (current) {
|
|
263
|
+
const frame = buildFrame(current);
|
|
264
|
+
if (frame && shouldIncludeFrame(frame, lastFrame)) {
|
|
265
|
+
frames.push(frame);
|
|
266
|
+
lastFrame = frame;
|
|
267
|
+
if (!nearestComponentFiber) {
|
|
268
|
+
nearestComponentFiber = current;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
current = current._debugOwner;
|
|
272
|
+
}
|
|
273
|
+
return { frames, nearestComponentFiber };
|
|
274
|
+
}
|
|
275
|
+
function getRenderStack(fiber) {
|
|
276
|
+
const frames = [];
|
|
277
|
+
let current = fiber;
|
|
278
|
+
let lastFrame = null;
|
|
279
|
+
let nearestComponentFiber = null;
|
|
280
|
+
while (current) {
|
|
281
|
+
const frame = buildFrame(current);
|
|
282
|
+
if (frame && shouldIncludeFrame(frame, lastFrame)) {
|
|
283
|
+
frames.push(frame);
|
|
284
|
+
lastFrame = frame;
|
|
285
|
+
if (!nearestComponentFiber) {
|
|
286
|
+
nearestComponentFiber = current;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
current = current.return;
|
|
290
|
+
}
|
|
291
|
+
return { frames, nearestComponentFiber };
|
|
292
|
+
}
|
|
293
|
+
function getReactComponentInfo(element) {
|
|
294
|
+
const fiber = getFiberForElement(element);
|
|
295
|
+
if (!fiber) return { frames: [], nearestComponentFiber: null };
|
|
296
|
+
const elementSource = getSourceFromFiber(fiber);
|
|
297
|
+
const elementSourceFile = elementSource?.fileName || void 0;
|
|
298
|
+
const ownerResult = getOwnerStack(fiber);
|
|
299
|
+
if (ownerResult.frames.length > 0) {
|
|
300
|
+
return { ...ownerResult, elementSourceFile };
|
|
301
|
+
}
|
|
302
|
+
return { ...getRenderStack(fiber), elementSourceFile };
|
|
303
|
+
}
|
|
304
|
+
var EXCLUDED_PROP_KEYS = /* @__PURE__ */ new Set([
|
|
305
|
+
"className",
|
|
306
|
+
"style",
|
|
307
|
+
"children",
|
|
308
|
+
"ref",
|
|
309
|
+
"key",
|
|
310
|
+
"render"
|
|
311
|
+
]);
|
|
312
|
+
function serializePropValue(value) {
|
|
313
|
+
if (typeof value === "function") return "[function]";
|
|
314
|
+
if (typeof value === "symbol") return void 0;
|
|
315
|
+
if (value === void 0) return void 0;
|
|
316
|
+
if (value !== null && typeof value === "object") {
|
|
317
|
+
if ("$$typeof" in value) return "[element]";
|
|
318
|
+
try {
|
|
319
|
+
JSON.stringify(value);
|
|
320
|
+
return value;
|
|
321
|
+
} catch {
|
|
322
|
+
return "[object]";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return value;
|
|
326
|
+
}
|
|
327
|
+
function getComponentProps(fiber) {
|
|
328
|
+
const props = fiber?.memoizedProps ?? fiber?.pendingProps;
|
|
329
|
+
if (!props || typeof props !== "object") return {};
|
|
330
|
+
const result = {};
|
|
331
|
+
for (const [key, value] of Object.entries(props)) {
|
|
332
|
+
if (EXCLUDED_PROP_KEYS.has(key)) continue;
|
|
333
|
+
if (key.startsWith("data-")) continue;
|
|
334
|
+
const serialized = serializePropValue(value);
|
|
335
|
+
if (serialized !== void 0) {
|
|
336
|
+
result[key] = serialized;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return result;
|
|
340
|
+
}
|
|
341
|
+
function getCallSiteSource(fiber) {
|
|
342
|
+
const source = fiber?._debugSource;
|
|
343
|
+
if (source?.fileName) {
|
|
344
|
+
return {
|
|
345
|
+
file: source.fileName,
|
|
346
|
+
line: typeof source.lineNumber === "number" ? source.lineNumber : void 0,
|
|
347
|
+
column: typeof source.columnNumber === "number" ? source.columnNumber : void 0
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
const pending = fiber?.pendingProps?.__source;
|
|
351
|
+
if (pending?.fileName) {
|
|
352
|
+
return {
|
|
353
|
+
file: pending.fileName,
|
|
354
|
+
line: typeof pending.lineNumber === "number" ? pending.lineNumber : void 0,
|
|
355
|
+
column: typeof pending.columnNumber === "number" ? pending.columnNumber : void 0
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
function deriveDefinitionSource(frames) {
|
|
361
|
+
for (const frame of frames) {
|
|
362
|
+
if (frame.file && isComponentPrimitivePath(frame.file)) {
|
|
363
|
+
return { file: frame.file, line: frame.line, column: frame.column };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
var PRIMITIVE_PATH_PATTERNS = [
|
|
369
|
+
/\/components\/ui\//,
|
|
370
|
+
/\/ui\/primitives\//,
|
|
371
|
+
/\/design-system\//
|
|
372
|
+
];
|
|
373
|
+
var PRIMITIVE_NPM_PATTERNS = [
|
|
374
|
+
/@base-ui\//,
|
|
375
|
+
/@radix-ui\//,
|
|
376
|
+
/@headlessui\//,
|
|
377
|
+
/@chakra-ui\//,
|
|
378
|
+
/@mantine\//,
|
|
379
|
+
/@mui\//,
|
|
380
|
+
/@ark-ui\//
|
|
381
|
+
];
|
|
382
|
+
var FRAMEWORK_EXCLUSION_PATTERNS = [
|
|
383
|
+
/node_modules\/react\//,
|
|
384
|
+
/node_modules\/react-dom\//,
|
|
385
|
+
/node_modules\/next\/dist\//,
|
|
386
|
+
/node_modules\/scheduler\//,
|
|
387
|
+
/node_modules\/react-server\//
|
|
388
|
+
];
|
|
389
|
+
function isComponentPrimitivePath(filePath) {
|
|
390
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
391
|
+
for (const pattern of FRAMEWORK_EXCLUSION_PATTERNS) {
|
|
392
|
+
if (pattern.test(normalized)) return false;
|
|
393
|
+
}
|
|
394
|
+
for (const pattern of PRIMITIVE_NPM_PATTERNS) {
|
|
395
|
+
if (pattern.test(normalized)) return true;
|
|
396
|
+
}
|
|
397
|
+
for (const pattern of PRIMITIVE_PATH_PATTERNS) {
|
|
398
|
+
if (pattern.test(normalized)) return true;
|
|
399
|
+
}
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
function classifyComponentFiber(fiber, frames, elementSourceFile) {
|
|
403
|
+
if (elementSourceFile && isComponentPrimitivePath(elementSourceFile)) {
|
|
404
|
+
return { isComponentPrimitive: true };
|
|
405
|
+
}
|
|
406
|
+
if (!fiber) return { isComponentPrimitive: false };
|
|
407
|
+
const callSite = getCallSiteSource(fiber);
|
|
408
|
+
if (callSite?.file && isComponentPrimitivePath(callSite.file)) {
|
|
409
|
+
return { isComponentPrimitive: true };
|
|
410
|
+
}
|
|
411
|
+
for (const frame of frames) {
|
|
412
|
+
if (frame.file && isComponentPrimitivePath(frame.file)) {
|
|
413
|
+
return { isComponentPrimitive: true };
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return { isComponentPrimitive: false };
|
|
417
|
+
}
|
|
418
|
+
|
|
200
419
|
// src/utils.ts
|
|
201
420
|
function clamp(value, min, max) {
|
|
202
421
|
if (!Number.isFinite(value)) return min;
|
|
@@ -1584,7 +1803,7 @@ function calculateDropPosition(container, pointerX, pointerY, draggedElement) {
|
|
|
1584
1803
|
};
|
|
1585
1804
|
return { insertBefore, indicator };
|
|
1586
1805
|
}
|
|
1587
|
-
function
|
|
1806
|
+
function getFiberForElement2(element) {
|
|
1588
1807
|
if (typeof window !== "undefined") {
|
|
1589
1808
|
const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
|
|
1590
1809
|
if (devtools?.getFiberForElement) {
|
|
@@ -1845,7 +2064,7 @@ function getSourceFromDebugStack(fiber) {
|
|
|
1845
2064
|
}
|
|
1846
2065
|
return null;
|
|
1847
2066
|
}
|
|
1848
|
-
function
|
|
2067
|
+
function getSourceFromFiber2(fiber) {
|
|
1849
2068
|
const debugSource = fiber?._debugSource;
|
|
1850
2069
|
if (debugSource?.fileName) return debugSource;
|
|
1851
2070
|
const owner = fiber?._debugOwner;
|
|
@@ -1861,13 +2080,13 @@ function getSourceFromFiber(fiber) {
|
|
|
1861
2080
|
if (fromDebugStack?.fileName) return fromDebugStack;
|
|
1862
2081
|
return null;
|
|
1863
2082
|
}
|
|
1864
|
-
function
|
|
2083
|
+
function buildFrame2(fiber) {
|
|
1865
2084
|
const type = fiber?.type;
|
|
1866
2085
|
if (typeof type !== "function" && typeof type !== "object") return null;
|
|
1867
2086
|
const name = type?.displayName || type?.name || null;
|
|
1868
2087
|
if (!name || name === "Fragment") return null;
|
|
1869
2088
|
const frame = { name };
|
|
1870
|
-
const source =
|
|
2089
|
+
const source = getSourceFromFiber2(fiber);
|
|
1871
2090
|
if (source?.fileName) {
|
|
1872
2091
|
frame.file = source.fileName;
|
|
1873
2092
|
if (typeof source.lineNumber === "number") {
|
|
@@ -1879,7 +2098,7 @@ function buildFrame(fiber) {
|
|
|
1879
2098
|
}
|
|
1880
2099
|
return frame;
|
|
1881
2100
|
}
|
|
1882
|
-
function
|
|
2101
|
+
function shouldIncludeFrame2(frame, lastFrame) {
|
|
1883
2102
|
if (!lastFrame) return true;
|
|
1884
2103
|
if (frame.name !== lastFrame.name) return true;
|
|
1885
2104
|
if (!lastFrame.file && frame.file) return true;
|
|
@@ -1889,42 +2108,52 @@ function shouldIncludeFrame(frame, lastFrame) {
|
|
|
1889
2108
|
}
|
|
1890
2109
|
return false;
|
|
1891
2110
|
}
|
|
1892
|
-
function
|
|
2111
|
+
function getOwnerStack2(fiber) {
|
|
1893
2112
|
const frames = [];
|
|
1894
2113
|
let current = fiber;
|
|
1895
2114
|
let lastFrame = null;
|
|
2115
|
+
let nearestComponentFiber = null;
|
|
1896
2116
|
while (current) {
|
|
1897
|
-
const frame =
|
|
1898
|
-
if (frame &&
|
|
2117
|
+
const frame = buildFrame2(current);
|
|
2118
|
+
if (frame && shouldIncludeFrame2(frame, lastFrame)) {
|
|
1899
2119
|
frames.push(frame);
|
|
1900
2120
|
lastFrame = frame;
|
|
2121
|
+
if (!nearestComponentFiber) {
|
|
2122
|
+
nearestComponentFiber = current;
|
|
2123
|
+
}
|
|
1901
2124
|
}
|
|
1902
2125
|
current = current._debugOwner;
|
|
1903
2126
|
}
|
|
1904
|
-
return frames;
|
|
2127
|
+
return { frames, nearestComponentFiber };
|
|
1905
2128
|
}
|
|
1906
|
-
function
|
|
2129
|
+
function getRenderStack2(fiber) {
|
|
1907
2130
|
const frames = [];
|
|
1908
2131
|
let current = fiber;
|
|
1909
2132
|
let lastFrame = null;
|
|
2133
|
+
let nearestComponentFiber = null;
|
|
1910
2134
|
while (current) {
|
|
1911
|
-
const frame =
|
|
1912
|
-
if (frame &&
|
|
2135
|
+
const frame = buildFrame2(current);
|
|
2136
|
+
if (frame && shouldIncludeFrame2(frame, lastFrame)) {
|
|
1913
2137
|
frames.push(frame);
|
|
1914
2138
|
lastFrame = frame;
|
|
2139
|
+
if (!nearestComponentFiber) {
|
|
2140
|
+
nearestComponentFiber = current;
|
|
2141
|
+
}
|
|
1915
2142
|
}
|
|
1916
2143
|
current = current.return;
|
|
1917
2144
|
}
|
|
1918
|
-
return frames;
|
|
2145
|
+
return { frames, nearestComponentFiber };
|
|
1919
2146
|
}
|
|
1920
|
-
function
|
|
1921
|
-
const fiber =
|
|
1922
|
-
if (!fiber) return [];
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
|
|
2147
|
+
function getReactComponentInfo2(element) {
|
|
2148
|
+
const fiber = getFiberForElement2(element);
|
|
2149
|
+
if (!fiber) return { frames: [], nearestComponentFiber: null };
|
|
2150
|
+
const elementSource = getSourceFromFiber2(fiber);
|
|
2151
|
+
const elementSourceFile = elementSource?.fileName || void 0;
|
|
2152
|
+
const ownerResult = getOwnerStack2(fiber);
|
|
2153
|
+
if (ownerResult.frames.length > 0) {
|
|
2154
|
+
return { ...ownerResult, elementSourceFile };
|
|
1926
2155
|
}
|
|
1927
|
-
return
|
|
2156
|
+
return { ...getRenderStack2(fiber), elementSourceFile };
|
|
1928
2157
|
}
|
|
1929
2158
|
function getElementDisplayName(element) {
|
|
1930
2159
|
const tag = element.tagName.toLowerCase();
|
|
@@ -2219,14 +2448,35 @@ function parseDomSource(element) {
|
|
|
2219
2448
|
}
|
|
2220
2449
|
return { file, line, column };
|
|
2221
2450
|
}
|
|
2451
|
+
var MAX_SUB_ELEMENT_SOURCES = 20;
|
|
2452
|
+
function collectSubElementSources(element) {
|
|
2453
|
+
const sources = {};
|
|
2454
|
+
const children = element.querySelectorAll("[data-direct-edit-source]");
|
|
2455
|
+
const labelCounts = /* @__PURE__ */ new Map();
|
|
2456
|
+
let count = 0;
|
|
2457
|
+
for (const child of children) {
|
|
2458
|
+
if (count >= MAX_SUB_ELEMENT_SOURCES) break;
|
|
2459
|
+
if (!(child instanceof HTMLElement)) continue;
|
|
2460
|
+
const source = parseDomSource(child);
|
|
2461
|
+
if (!source) continue;
|
|
2462
|
+
const text = ((child.innerText || child.textContent) ?? "").trim();
|
|
2463
|
+
let baseLabel = text.length > 0 && text.length <= 30 ? text.slice(0, 30).toLowerCase().replace(/\s+/g, "_") : child.tagName.toLowerCase();
|
|
2464
|
+
const existing = labelCounts.get(baseLabel) ?? 0;
|
|
2465
|
+
labelCounts.set(baseLabel, existing + 1);
|
|
2466
|
+
const label = existing > 0 ? `${baseLabel}_${existing + 1}` : baseLabel;
|
|
2467
|
+
sources[label] = source;
|
|
2468
|
+
count++;
|
|
2469
|
+
}
|
|
2470
|
+
return sources;
|
|
2471
|
+
}
|
|
2222
2472
|
function getElementSource(element) {
|
|
2223
2473
|
const domSource = parseDomSource(element);
|
|
2224
2474
|
if (domSource) return domSource;
|
|
2225
2475
|
const seenFibers = /* @__PURE__ */ new Set();
|
|
2226
|
-
let fiber =
|
|
2476
|
+
let fiber = getFiberForElement2(element);
|
|
2227
2477
|
while (fiber && !seenFibers.has(fiber)) {
|
|
2228
2478
|
seenFibers.add(fiber);
|
|
2229
|
-
const fiberSource =
|
|
2479
|
+
const fiberSource = getSourceFromFiber2(fiber);
|
|
2230
2480
|
if (fiberSource?.fileName) {
|
|
2231
2481
|
return {
|
|
2232
2482
|
file: fiberSource.fileName,
|
|
@@ -2241,8 +2491,15 @@ function getElementSource(element) {
|
|
|
2241
2491
|
function getElementLocator(element) {
|
|
2242
2492
|
const elementInfo = getElementInfo(element);
|
|
2243
2493
|
const domSource = getElementSource(element);
|
|
2494
|
+
const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo2(element);
|
|
2495
|
+
const componentName = nearestComponentFiber?.type?.displayName || nearestComponentFiber?.type?.name || void 0;
|
|
2496
|
+
const authoredProps = nearestComponentFiber ? getComponentProps(nearestComponentFiber) : void 0;
|
|
2497
|
+
const classification = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile);
|
|
2498
|
+
const callSite = nearestComponentFiber ? getCallSiteSource(nearestComponentFiber) : null;
|
|
2499
|
+
const definitionSrc = classification.isComponentPrimitive ? deriveDefinitionSource(frames) : null;
|
|
2500
|
+
const subSources = collectSubElementSources(element);
|
|
2244
2501
|
return {
|
|
2245
|
-
reactStack:
|
|
2502
|
+
reactStack: frames,
|
|
2246
2503
|
domSelector: buildDomSelector(element),
|
|
2247
2504
|
domContextHtml: buildDomContextHtml(element),
|
|
2248
2505
|
targetHtml: buildTargetHtml(element),
|
|
@@ -2250,36 +2507,80 @@ function getElementLocator(element) {
|
|
|
2250
2507
|
tagName: elementInfo.tagName,
|
|
2251
2508
|
id: elementInfo.id,
|
|
2252
2509
|
classList: elementInfo.classList,
|
|
2253
|
-
domSource: domSource ?? void 0
|
|
2510
|
+
domSource: domSource ?? void 0,
|
|
2511
|
+
reactComponentName: componentName,
|
|
2512
|
+
authoredProps: authoredProps && Object.keys(authoredProps).length > 0 ? authoredProps : void 0,
|
|
2513
|
+
subElementSources: Object.keys(subSources).length > 0 ? subSources : void 0,
|
|
2514
|
+
callSiteSource: callSite ?? void 0,
|
|
2515
|
+
definitionSource: definitionSrc ?? void 0,
|
|
2516
|
+
isComponentPrimitive: nearestComponentFiber || elementSourceFile ? classification.isComponentPrimitive : void 0
|
|
2254
2517
|
};
|
|
2255
2518
|
}
|
|
2256
2519
|
function getLocatorHeader(locator) {
|
|
2257
2520
|
const primaryFrame = getPrimaryFrame(locator);
|
|
2258
|
-
const componentLabel =
|
|
2259
|
-
|
|
2260
|
-
|
|
2521
|
+
const componentLabel = locator.reactComponentName ?? primaryFrame?.name ?? locator.tagName;
|
|
2522
|
+
let formattedSource;
|
|
2523
|
+
if (locator.isComponentPrimitive && locator.definitionSource?.file) {
|
|
2524
|
+
formattedSource = formatSourceLocation(
|
|
2525
|
+
locator.definitionSource.file,
|
|
2526
|
+
locator.definitionSource.line,
|
|
2527
|
+
locator.definitionSource.column
|
|
2528
|
+
);
|
|
2529
|
+
} else {
|
|
2530
|
+
formattedSource = locator.domSource?.file ? formatSourceLocation(locator.domSource.file, locator.domSource.line, locator.domSource.column) : primaryFrame?.file ? formatSourceLocation(primaryFrame.file, primaryFrame.line, primaryFrame.column) : null;
|
|
2531
|
+
}
|
|
2532
|
+
const formattedCallSite = locator.callSiteSource?.file ? formatSourceLocation(locator.callSiteSource.file, locator.callSiteSource.line, locator.callSiteSource.column) : null;
|
|
2533
|
+
return { componentLabel, formattedSource, formattedCallSite };
|
|
2534
|
+
}
|
|
2535
|
+
function formatComponentTree(reactStack) {
|
|
2536
|
+
const names = reactStack.map((f) => f.name).filter(Boolean);
|
|
2537
|
+
if (names.length === 0) return null;
|
|
2538
|
+
if (names.length === 1) return names[0];
|
|
2539
|
+
const [component, ...ancestors] = names;
|
|
2540
|
+
return `${component} (in ${ancestors.join(" > ")})`;
|
|
2261
2541
|
}
|
|
2262
2542
|
function buildLocatorContextLines(locator, options) {
|
|
2263
2543
|
const lines = [];
|
|
2264
|
-
const { componentLabel, formattedSource } = getLocatorHeader(locator);
|
|
2544
|
+
const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
|
|
2265
2545
|
const target = (locator.targetHtml || locator.domContextHtml || "").trim();
|
|
2266
2546
|
const context = locator.domContextHtml?.trim() || "";
|
|
2267
|
-
const
|
|
2547
|
+
const path = locator.domSelector?.trim();
|
|
2268
2548
|
const text = locator.textPreview?.trim();
|
|
2269
2549
|
lines.push(`@<${componentLabel}>`);
|
|
2270
2550
|
lines.push("");
|
|
2551
|
+
const tree = formatComponentTree(locator.reactStack);
|
|
2552
|
+
if (tree) {
|
|
2553
|
+
lines.push(`react: ${tree}`);
|
|
2554
|
+
}
|
|
2555
|
+
if (locator.authoredProps && Object.keys(locator.authoredProps).length > 0) {
|
|
2556
|
+
lines.push(`props: ${JSON.stringify(locator.authoredProps)}`);
|
|
2557
|
+
}
|
|
2558
|
+
if (locator.isComponentPrimitive != null) {
|
|
2559
|
+
lines.push(`type: ${locator.isComponentPrimitive ? "component" : "instance"}`);
|
|
2560
|
+
}
|
|
2561
|
+
lines.push(`source: ${formattedSource ?? "(file not available)"}`);
|
|
2562
|
+
if (formattedCallSite && formattedCallSite !== formattedSource) {
|
|
2563
|
+
lines.push(`call-site: ${formattedCallSite}`);
|
|
2564
|
+
}
|
|
2565
|
+
if (locator.subElementSources && Object.keys(locator.subElementSources).length > 0) {
|
|
2566
|
+
lines.push("source-map:");
|
|
2567
|
+
for (const [label, source] of Object.entries(locator.subElementSources)) {
|
|
2568
|
+
lines.push(` - ${label}: ${formatSourceLocation(source.file, source.line, source.column)}`);
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
if (path) {
|
|
2572
|
+
lines.push(`path: ${path}`);
|
|
2573
|
+
}
|
|
2271
2574
|
if (target) {
|
|
2575
|
+
lines.push("");
|
|
2272
2576
|
lines.push("target:");
|
|
2273
2577
|
lines.push(target);
|
|
2274
2578
|
}
|
|
2275
2579
|
if (!options?.skipContext && context && context !== target) {
|
|
2580
|
+
lines.push("");
|
|
2276
2581
|
lines.push("context:");
|
|
2277
2582
|
lines.push(context);
|
|
2278
2583
|
}
|
|
2279
|
-
lines.push(`in ${formattedSource ?? "(file not available)"}`);
|
|
2280
|
-
if (selector) {
|
|
2281
|
-
lines.push(`selector: ${selector}`);
|
|
2282
|
-
}
|
|
2283
2584
|
if (text) {
|
|
2284
2585
|
lines.push(`text: ${text}`);
|
|
2285
2586
|
}
|
|
@@ -2980,7 +3281,7 @@ function buildExportInstruction(profile) {
|
|
|
2980
3281
|
return hasComments ? "Address this feedback on the UI. Use the provided source location and selector to find each element in the codebase." : "";
|
|
2981
3282
|
}
|
|
2982
3283
|
const parts = [];
|
|
2983
|
-
if (hasCssEdits) parts.push("Apply the CSS changes to the targeted elements using the project's existing styling approach (Tailwind, CSS modules, etc.).");
|
|
3284
|
+
if (hasCssEdits) parts.push("Apply the CSS changes to the targeted elements using the project's existing styling approach (Tailwind, CSS modules, etc.). Map values to existing CSS variables, design tokens, or utility classes already used in the project whenever possible.");
|
|
2984
3285
|
if (hasTextEdits) parts.push("Update the text content as specified.");
|
|
2985
3286
|
if (hasMoves) parts.push("Implement the move plan below directly in source code. For `structural_move`, reorder/reparent elements using the target anchors. For `layout_refactor`, apply the listed flex/grid refactor steps. Do NOT simulate movement with absolute positioning, left/top offsets, transform, or margin hacks.");
|
|
2986
3287
|
if (hasComments) parts.push("Address the comments on the relevant elements.");
|
|
@@ -3692,11 +3993,6 @@ function useStyleUpdaters({
|
|
|
3692
3993
|
var React3 = __toESM(require("react"));
|
|
3693
3994
|
|
|
3694
3995
|
// src/clipboard.ts
|
|
3695
|
-
function buildAgentClipboardText(markdown) {
|
|
3696
|
-
return `implement the visual edits
|
|
3697
|
-
|
|
3698
|
-
${markdown}`;
|
|
3699
|
-
}
|
|
3700
3996
|
function tryRestoreFocus(element) {
|
|
3701
3997
|
if (!(element instanceof HTMLElement)) return;
|
|
3702
3998
|
try {
|
|
@@ -4029,6 +4325,8 @@ function useSessionManager({
|
|
|
4029
4325
|
const originalStyles = options?.originalStyles ?? existingEdit?.originalStyles ?? getOriginalInlineStyles(nextSingleElement);
|
|
4030
4326
|
const pendingStyles = options?.pendingStyles ?? existingEdit?.pendingStyles ?? {};
|
|
4031
4327
|
const elementInfo = getElementInfo(nextSingleElement);
|
|
4328
|
+
const { frames, nearestComponentFiber, elementSourceFile } = getReactComponentInfo(nextSingleElement);
|
|
4329
|
+
const isPrimitive = classifyComponentFiber(nearestComponentFiber, frames, elementSourceFile).isComponentPrimitive;
|
|
4032
4330
|
setState((prev) => ({
|
|
4033
4331
|
comments: prev.activeCommentId ? prev.comments.filter((comment) => {
|
|
4034
4332
|
if (comment.id !== prev.activeCommentId) return true;
|
|
@@ -4047,6 +4345,7 @@ function useSessionManager({
|
|
|
4047
4345
|
computedColor: computed.color,
|
|
4048
4346
|
computedBoxShadow: computed.boxShadow,
|
|
4049
4347
|
computedTypography: computed.typography,
|
|
4348
|
+
isComponentPrimitive: isPrimitive,
|
|
4050
4349
|
originalStyles,
|
|
4051
4350
|
pendingStyles,
|
|
4052
4351
|
editModeActive: prev.editModeActive,
|
|
@@ -4077,6 +4376,7 @@ function useSessionManager({
|
|
|
4077
4376
|
computedColor: null,
|
|
4078
4377
|
computedBoxShadow: null,
|
|
4079
4378
|
computedTypography: null,
|
|
4379
|
+
isComponentPrimitive: false,
|
|
4080
4380
|
originalStyles: {},
|
|
4081
4381
|
pendingStyles: {},
|
|
4082
4382
|
activeCommentId: null,
|
|
@@ -4617,6 +4917,7 @@ function useSessionManager({
|
|
|
4617
4917
|
computedColor: computed.color,
|
|
4618
4918
|
computedBoxShadow: computed.boxShadow,
|
|
4619
4919
|
computedTypography: computed.typography,
|
|
4920
|
+
isComponentPrimitive: prev.isComponentPrimitive,
|
|
4620
4921
|
originalStyles: styleState.originalStyles,
|
|
4621
4922
|
pendingStyles: styleState.pendingStyles,
|
|
4622
4923
|
editModeActive: prev.editModeActive,
|
|
@@ -5394,7 +5695,15 @@ async function checkAgentConnection() {
|
|
|
5394
5695
|
}
|
|
5395
5696
|
|
|
5396
5697
|
// src/use-agent-comms.ts
|
|
5698
|
+
function withInstruction(profile, markdown) {
|
|
5699
|
+
const instruction = buildExportInstruction(profile);
|
|
5700
|
+
return instruction ? `${instruction}
|
|
5701
|
+
|
|
5702
|
+
${markdown}` : markdown;
|
|
5703
|
+
}
|
|
5397
5704
|
function buildLocatorPayload(locator) {
|
|
5705
|
+
const { componentLabel, formattedSource, formattedCallSite } = getLocatorHeader(locator);
|
|
5706
|
+
const reactTree = formatComponentTree(locator.reactStack);
|
|
5398
5707
|
return {
|
|
5399
5708
|
element: {
|
|
5400
5709
|
tagName: locator.tagName,
|
|
@@ -5402,10 +5711,22 @@ function buildLocatorPayload(locator) {
|
|
|
5402
5711
|
classList: locator.classList,
|
|
5403
5712
|
domSelector: locator.domSelector,
|
|
5404
5713
|
targetHtml: locator.targetHtml,
|
|
5714
|
+
contextHtml: locator.domContextHtml || null,
|
|
5405
5715
|
textPreview: locator.textPreview
|
|
5406
5716
|
},
|
|
5407
|
-
|
|
5408
|
-
|
|
5717
|
+
componentLabel,
|
|
5718
|
+
reactTree,
|
|
5719
|
+
reactStack: locator.reactStack,
|
|
5720
|
+
reactComponentName: locator.reactComponentName ?? null,
|
|
5721
|
+
authoredProps: locator.authoredProps ?? null,
|
|
5722
|
+
type: locator.isComponentPrimitive != null ? locator.isComponentPrimitive ? "component" : "instance" : null,
|
|
5723
|
+
isComponentPrimitive: locator.isComponentPrimitive ?? false,
|
|
5724
|
+
source: formattedSource,
|
|
5725
|
+
callSite: formattedCallSite,
|
|
5726
|
+
rawSource: locator.domSource || null,
|
|
5727
|
+
callSiteSource: locator.callSiteSource ?? null,
|
|
5728
|
+
definitionSource: locator.definitionSource ?? null,
|
|
5729
|
+
subElementSources: locator.subElementSources ?? null
|
|
5409
5730
|
};
|
|
5410
5731
|
}
|
|
5411
5732
|
function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrentToSession, removeSessionEdit, deleteComment }) {
|
|
@@ -5486,6 +5807,11 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
|
|
|
5486
5807
|
const movePlan = includeBatchMoveEnvelope ? resolvedPlanContext.movePlan : null;
|
|
5487
5808
|
const hasMeaningfulPayload = changes.length > 0 || sessionEdit.textEdit != null || moveIntent != null;
|
|
5488
5809
|
if (!hasMeaningfulPayload) return true;
|
|
5810
|
+
const profile = getExportContentProfile(
|
|
5811
|
+
[sessionEdit],
|
|
5812
|
+
[],
|
|
5813
|
+
resolvedPlanContext
|
|
5814
|
+
);
|
|
5489
5815
|
try {
|
|
5490
5816
|
const result = await sendEditToAgent({
|
|
5491
5817
|
...buildLocatorPayload(locator),
|
|
@@ -5493,7 +5819,7 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
|
|
|
5493
5819
|
textChange: sessionEdit.textEdit ?? null,
|
|
5494
5820
|
moveIntent,
|
|
5495
5821
|
...movePlan ? { movePlan } : {},
|
|
5496
|
-
exportMarkdown
|
|
5822
|
+
exportMarkdown: withInstruction(profile, exportMarkdown)
|
|
5497
5823
|
});
|
|
5498
5824
|
if (result.ok) {
|
|
5499
5825
|
removeSessionEdit(sessionEdit.element);
|
|
@@ -5505,12 +5831,13 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
|
|
|
5505
5831
|
}, [updateAgentAvailability, removeSessionEdit]);
|
|
5506
5832
|
const sendSessionCommentToAgent = React5.useCallback(async (comment) => {
|
|
5507
5833
|
const exportMarkdown = buildCommentExport(comment.locator, comment.text, comment.replies);
|
|
5834
|
+
const commentProfile = { hasCssEdits: false, hasTextEdits: false, hasMoves: false, hasComments: true };
|
|
5508
5835
|
try {
|
|
5509
5836
|
const result = await sendCommentToAgent({
|
|
5510
5837
|
...buildLocatorPayload(comment.locator),
|
|
5511
5838
|
commentText: comment.text,
|
|
5512
5839
|
replies: comment.replies,
|
|
5513
|
-
exportMarkdown
|
|
5840
|
+
exportMarkdown: withInstruction(commentProfile, exportMarkdown)
|
|
5514
5841
|
});
|
|
5515
5842
|
if (result.ok) {
|
|
5516
5843
|
deleteComment(comment.id);
|
|
@@ -5530,12 +5857,14 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
|
|
|
5530
5857
|
);
|
|
5531
5858
|
if (editsWithChanges.length === 0 && contextBlocks.length === 0) return false;
|
|
5532
5859
|
const markdownParts = [];
|
|
5860
|
+
let movePlanCtx = null;
|
|
5533
5861
|
if (editsWithChanges.length > 0) {
|
|
5534
|
-
|
|
5535
|
-
markdownParts.push(buildSessionExport(editsWithChanges, [], { movePlanContext }));
|
|
5862
|
+
movePlanCtx = buildMovePlanContext(editsWithChanges);
|
|
5863
|
+
markdownParts.push(buildSessionExport(editsWithChanges, [], { movePlanContext: movePlanCtx }));
|
|
5536
5864
|
}
|
|
5537
5865
|
markdownParts.push(...contextBlocks);
|
|
5538
5866
|
const exportMarkdown = markdownParts.join("\n\n");
|
|
5867
|
+
const multiProfile = getExportContentProfile(editsWithChanges, [], movePlanCtx);
|
|
5539
5868
|
const primaryEl = current.selectedElements.find((el) => el.isConnected);
|
|
5540
5869
|
if (!primaryEl) return false;
|
|
5541
5870
|
const primary = getElementLocator(primaryEl);
|
|
@@ -5545,7 +5874,7 @@ function useAgentComms({ stateRef, sessionEditsRef, getSessionItems, saveCurrent
|
|
|
5545
5874
|
changes: [],
|
|
5546
5875
|
textChange: null,
|
|
5547
5876
|
moveIntent: null,
|
|
5548
|
-
exportMarkdown
|
|
5877
|
+
exportMarkdown: withInstruction(multiProfile, exportMarkdown)
|
|
5549
5878
|
});
|
|
5550
5879
|
if (result.ok) {
|
|
5551
5880
|
for (const el of current.selectedElements) {
|
|
@@ -6373,6 +6702,7 @@ function DirectEditProvider({ children }) {
|
|
|
6373
6702
|
computedColor: null,
|
|
6374
6703
|
computedBoxShadow: null,
|
|
6375
6704
|
computedTypography: null,
|
|
6705
|
+
isComponentPrimitive: false,
|
|
6376
6706
|
originalStyles: {},
|
|
6377
6707
|
pendingStyles: {},
|
|
6378
6708
|
editModeActive: false,
|
|
@@ -6494,9 +6824,10 @@ function DirectEditProvider({ children }) {
|
|
|
6494
6824
|
enterCanvas();
|
|
6495
6825
|
}
|
|
6496
6826
|
if (wasActive) {
|
|
6827
|
+
clearSelection();
|
|
6497
6828
|
closePanel();
|
|
6498
6829
|
}
|
|
6499
|
-
}, [toggleEditModeBase, stateRef, exitCanvas, enterCanvas, closePanel]);
|
|
6830
|
+
}, [toggleEditModeBase, stateRef, exitCanvas, enterCanvas, clearSelection, closePanel]);
|
|
6500
6831
|
const toggleCanvasWithPreference = React8.useCallback(() => {
|
|
6501
6832
|
const willBeActive = !stateRef.current.canvas.active;
|
|
6502
6833
|
toggleCanvas();
|
|
@@ -8664,6 +8995,7 @@ function useSelectionResize({
|
|
|
8664
8995
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
8665
8996
|
var BLUE3 = "#0D99FF";
|
|
8666
8997
|
var MAGENTA = "#E11BB6";
|
|
8998
|
+
var COMPONENT_PURPLE = "#8B5CF6";
|
|
8667
8999
|
var DRAG_THRESHOLD = 4;
|
|
8668
9000
|
var DBLCLICK_DELAY = 300;
|
|
8669
9001
|
var HANDLE_SIZE = 12;
|
|
@@ -8707,9 +9039,11 @@ function SelectionOverlay({
|
|
|
8707
9039
|
onHoverElement,
|
|
8708
9040
|
onClickThrough,
|
|
8709
9041
|
onSelectPageFrame,
|
|
9042
|
+
isComponentPrimitive = false,
|
|
8710
9043
|
enableResizeHandles = false,
|
|
8711
9044
|
onResizeSizingChange
|
|
8712
9045
|
}) {
|
|
9046
|
+
const selectionColor = isComponentPrimitive ? COMPONENT_PURPLE : BLUE3;
|
|
8713
9047
|
const rectElement = isDragging && draggedElement ? draggedElement : selectedElement;
|
|
8714
9048
|
const [rect, setRect] = React19.useState(() => rectElement.getBoundingClientRect());
|
|
8715
9049
|
const [pageFrameRect, setPageFrameRect] = React19.useState(() => pageFrameElement ? pageFrameElement.getBoundingClientRect() : null);
|
|
@@ -9037,7 +9371,7 @@ function SelectionOverlay({
|
|
|
9037
9371
|
zIndex: 99997,
|
|
9038
9372
|
background: "transparent",
|
|
9039
9373
|
border: "none",
|
|
9040
|
-
color:
|
|
9374
|
+
color: selectionColor,
|
|
9041
9375
|
fontSize: `${pageLabelFontSize}px`,
|
|
9042
9376
|
lineHeight: `${pageLabelLineHeight}px`,
|
|
9043
9377
|
padding: 0,
|
|
@@ -9065,7 +9399,7 @@ function SelectionOverlay({
|
|
|
9065
9399
|
height: rect.height,
|
|
9066
9400
|
pointerEvents: "none",
|
|
9067
9401
|
zIndex: 99996,
|
|
9068
|
-
border: `1px solid ${
|
|
9402
|
+
border: `1px solid ${selectionColor}`,
|
|
9069
9403
|
borderRadius: "0px",
|
|
9070
9404
|
boxSizing: "border-box"
|
|
9071
9405
|
}
|
|
@@ -9082,18 +9416,28 @@ function SelectionOverlay({
|
|
|
9082
9416
|
transform: "translateX(-50%)",
|
|
9083
9417
|
pointerEvents: "none",
|
|
9084
9418
|
zIndex: 99992,
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
lineHeight: "20px",
|
|
9089
|
-
padding: "0 6px",
|
|
9090
|
-
borderRadius: "4px",
|
|
9091
|
-
whiteSpace: "nowrap",
|
|
9092
|
-
fontFamily: "system-ui, sans-serif",
|
|
9093
|
-
fontWeight: 500,
|
|
9094
|
-
letterSpacing: "-0.01em"
|
|
9419
|
+
display: "flex",
|
|
9420
|
+
alignItems: "center",
|
|
9421
|
+
gap: "4px"
|
|
9095
9422
|
},
|
|
9096
|
-
children:
|
|
9423
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
9424
|
+
"span",
|
|
9425
|
+
{
|
|
9426
|
+
style: {
|
|
9427
|
+
background: selectionColor,
|
|
9428
|
+
color: "white",
|
|
9429
|
+
fontSize: "11px",
|
|
9430
|
+
lineHeight: "20px",
|
|
9431
|
+
padding: "0 6px",
|
|
9432
|
+
borderRadius: "4px",
|
|
9433
|
+
whiteSpace: "nowrap",
|
|
9434
|
+
fontFamily: "system-ui, sans-serif",
|
|
9435
|
+
fontWeight: 500,
|
|
9436
|
+
letterSpacing: "-0.01em"
|
|
9437
|
+
},
|
|
9438
|
+
children: dimensionText
|
|
9439
|
+
}
|
|
9440
|
+
)
|
|
9097
9441
|
}
|
|
9098
9442
|
),
|
|
9099
9443
|
!isDragging && !isTextEditing && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
@@ -9149,7 +9493,7 @@ function SelectionOverlay({
|
|
|
9149
9493
|
position: "absolute",
|
|
9150
9494
|
width: RESIZE_CORNER_SIZE,
|
|
9151
9495
|
height: RESIZE_CORNER_SIZE,
|
|
9152
|
-
border: `1px solid ${
|
|
9496
|
+
border: `1px solid ${selectionColor}`,
|
|
9153
9497
|
background: "#fff",
|
|
9154
9498
|
borderRadius: 1,
|
|
9155
9499
|
boxSizing: "border-box",
|
|
@@ -12523,6 +12867,7 @@ function DirectEditPanelContent() {
|
|
|
12523
12867
|
computedColor,
|
|
12524
12868
|
computedBoxShadow,
|
|
12525
12869
|
computedTypography,
|
|
12870
|
+
isComponentPrimitive,
|
|
12526
12871
|
borderStyleControlPreference,
|
|
12527
12872
|
pendingStyles,
|
|
12528
12873
|
editModeActive,
|
|
@@ -12843,6 +13188,7 @@ function DirectEditPanelContent() {
|
|
|
12843
13188
|
selectElement(child);
|
|
12844
13189
|
}
|
|
12845
13190
|
},
|
|
13191
|
+
isComponentPrimitive,
|
|
12846
13192
|
enableResizeHandles: true,
|
|
12847
13193
|
onResizeSizingChange: updateSizingProperties
|
|
12848
13194
|
}
|
|
@@ -14821,7 +15167,10 @@ function DirectEditDemo() {
|
|
|
14821
15167
|
const handleExportEdits = async () => {
|
|
14822
15168
|
if (Object.keys(pendingStyles).length === 0) return false;
|
|
14823
15169
|
const exportMarkdown = buildEditExport(DEMO_LOCATOR, pendingStyles);
|
|
14824
|
-
|
|
15170
|
+
const instruction = buildExportInstruction({ hasCssEdits: true, hasTextEdits: false, hasMoves: false, hasComments: false });
|
|
15171
|
+
return copyText(`${instruction}
|
|
15172
|
+
|
|
15173
|
+
${exportMarkdown}`);
|
|
14825
15174
|
};
|
|
14826
15175
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "min-h-screen p-8", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "mx-auto max-w-4xl", children: [
|
|
14827
15176
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h1", { className: "mb-2 text-2xl font-bold", children: "Direct Edit Panel" }),
|