made-refine 0.2.17 → 0.2.19

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/utils.js CHANGED
@@ -135,1932 +135,1934 @@ function getZoomScale() {
135
135
  return snap.active ? snap.zoom : 1;
136
136
  }
137
137
 
138
- // src/utils/react-fiber.ts
139
- var EXCLUDED_PROP_KEYS = /* @__PURE__ */ new Set([
140
- "className",
141
- "style",
142
- "children",
143
- "ref",
144
- "key",
145
- "render"
146
- ]);
147
- function serializePropValue(value) {
148
- if (typeof value === "function") return "[function]";
149
- if (typeof value === "symbol") return void 0;
150
- if (value === void 0) return void 0;
151
- if (value !== null && typeof value === "object") {
152
- if ("$$typeof" in value) return "[element]";
153
- try {
154
- JSON.stringify(value);
155
- return value;
156
- } catch {
157
- return "[object]";
138
+ // src/utils/debug-stack.ts
139
+ var STACK_SOURCE_FILE_EXTENSION_REGEX = /\.(jsx|tsx|ts|js)$/;
140
+ var STACK_BUNDLED_FILE_PATTERN_REGEX = /(\.min|bundle|chunk|vendor|vendors|runtime|polyfill|polyfills)\.(js|mjs|cjs)$|(chunk|bundle|vendor|vendors|runtime|polyfill|polyfills|framework|app|main|index)[-_.][A-Za-z0-9_-]{4,}\.(js|mjs|cjs)$|[\da-f]{8,}\.(js|mjs|cjs)$|[-_.][\da-f]{20,}\.(js|mjs|cjs)$|\/dist\/|\/build\/|\/.next\/|\/out\/|\/node_modules\/|\.webpack\.|\.vite\.|\.turbopack\./i;
141
+ var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
142
+ var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code\])?$/;
143
+ var SERVER_FRAME_MARKER = "(at Server)";
144
+ var STACK_INTERNAL_SCHEME_PREFIXES = [
145
+ "rsc://",
146
+ "about://React/",
147
+ "React/Server/",
148
+ "file:///",
149
+ "webpack://",
150
+ "webpack-internal://",
151
+ "node:",
152
+ "turbopack://",
153
+ "/app-pages-browser/"
154
+ ];
155
+ function formatOwnerDebugStack(stack) {
156
+ if (!stack) return "";
157
+ const lines = stack.split("\n");
158
+ const filtered = [];
159
+ for (const line of lines) {
160
+ const trimmed = line.trim();
161
+ if (!trimmed) continue;
162
+ if (trimmed === "Error: react-stack-top-frame") continue;
163
+ if (trimmed.includes("react_stack_bottom_frame") || trimmed.includes("react-stack-bottom-frame")) {
164
+ continue;
158
165
  }
166
+ filtered.push(line);
159
167
  }
160
- return value;
161
- }
162
- function getComponentProps(fiber) {
163
- const props = fiber?.memoizedProps ?? fiber?.pendingProps;
164
- if (!props || typeof props !== "object") return {};
165
- const result = {};
166
- for (const [key, value] of Object.entries(props)) {
167
- if (EXCLUDED_PROP_KEYS.has(key)) continue;
168
- if (key.startsWith("data-")) continue;
169
- const serialized = serializePropValue(value);
170
- if (serialized !== void 0) {
171
- result[key] = serialized;
172
- }
168
+ if (filtered.length > 0 && filtered[0].includes("fakeJSXCallSite")) {
169
+ filtered.shift();
173
170
  }
174
- return result;
171
+ return filtered.join("\n");
175
172
  }
176
- function getCallSiteSource(fiber) {
177
- const source = fiber?._debugSource;
178
- if (source?.fileName) {
179
- return {
180
- file: source.fileName,
181
- line: typeof source.lineNumber === "number" ? source.lineNumber : void 0,
182
- column: typeof source.columnNumber === "number" ? source.columnNumber : void 0
183
- };
173
+ function extractStackLocation(urlLike) {
174
+ if (!urlLike.includes(":")) return [urlLike, void 0, void 0];
175
+ const isWrappedLocation = urlLike.startsWith("(") && /:\d+\)$/.test(urlLike);
176
+ const sanitizedResult = isWrappedLocation ? urlLike.slice(1, -1) : urlLike;
177
+ const parts = /(.+?)(?::(\d+))?(?::(\d+))?$/.exec(sanitizedResult);
178
+ if (!parts) return [sanitizedResult, void 0, void 0];
179
+ return [
180
+ parts[1],
181
+ parts[2] !== void 0 ? Number(parts[2]) : void 0,
182
+ parts[3] !== void 0 ? Number(parts[3]) : void 0
183
+ ];
184
+ }
185
+ function parseV8StackLine(line) {
186
+ let currentLine = line;
187
+ if (currentLine.includes("(eval ")) {
188
+ currentLine = currentLine.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
184
189
  }
185
- const pending = fiber?.pendingProps?.__source;
186
- if (pending?.fileName) {
190
+ let sanitizedLine = currentLine.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
191
+ const locationMatch = sanitizedLine.match(/ (\(.+\)$)/);
192
+ if (locationMatch) {
193
+ sanitizedLine = sanitizedLine.replace(locationMatch[0], "");
194
+ }
195
+ const [fileName, lineNumber, columnNumber] = extractStackLocation(
196
+ locationMatch ? locationMatch[1] : sanitizedLine
197
+ );
198
+ const functionName = locationMatch && sanitizedLine ? sanitizedLine : void 0;
199
+ if (fileName === "eval" || fileName === "<anonymous>") {
187
200
  return {
188
- file: pending.fileName,
189
- line: typeof pending.lineNumber === "number" ? pending.lineNumber : void 0,
190
- column: typeof pending.columnNumber === "number" ? pending.columnNumber : void 0
201
+ functionName
191
202
  };
192
203
  }
193
- return null;
204
+ return {
205
+ functionName,
206
+ fileName,
207
+ lineNumber,
208
+ columnNumber,
209
+ source: currentLine,
210
+ isServer: currentLine.includes(SERVER_FRAME_MARKER) || fileName.startsWith("rsc://")
211
+ };
194
212
  }
195
- function deriveDefinitionSource(frames) {
196
- for (const frame of frames) {
197
- if (frame.file && isComponentPrimitivePath(frame.file)) {
198
- return { file: frame.file, line: frame.line, column: frame.column };
199
- }
213
+ function parseFFOrSafariStackLine(line) {
214
+ let currentLine = line;
215
+ if (currentLine.includes(" > eval")) {
216
+ currentLine = currentLine.replace(
217
+ / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,
218
+ ":$1"
219
+ );
200
220
  }
201
- return null;
202
- }
203
- var PRIMITIVE_PATH_PATTERNS = [
204
- /(?:^|\/)components\/ui\//,
205
- /(?:^|\/)ui\/primitives\//,
206
- /(?:^|\/)design-system\//
207
- ];
208
- var PRIMITIVE_NPM_PATTERNS = [
209
- /@base-ui\//,
210
- /@radix-ui\//,
211
- /@headlessui\//,
212
- /@chakra-ui\//,
213
- /@mantine\//,
214
- /@mui\//,
215
- /@ark-ui\//
216
- ];
217
- var FRAMEWORK_EXCLUSION_PATTERNS = [
218
- /node_modules\/react\//,
219
- /node_modules\/react-dom\//,
220
- /node_modules\/next\/dist\//,
221
- /node_modules\/scheduler\//,
222
- /node_modules\/react-server\//
223
- ];
224
- function isComponentPrimitivePath(filePath) {
225
- const normalized = filePath.replace(/\\/g, "/");
226
- for (const pattern of FRAMEWORK_EXCLUSION_PATTERNS) {
227
- if (pattern.test(normalized)) return false;
221
+ const trimmed = currentLine.trim();
222
+ if (!trimmed || SAFARI_NATIVE_CODE_REGEXP.test(trimmed)) {
223
+ return null;
228
224
  }
229
- for (const pattern of PRIMITIVE_NPM_PATTERNS) {
230
- if (pattern.test(normalized)) return true;
225
+ if (!trimmed.includes("@") && !trimmed.includes(":")) {
226
+ return {
227
+ functionName: trimmed,
228
+ source: currentLine,
229
+ isServer: trimmed.includes(SERVER_FRAME_MARKER)
230
+ };
231
231
  }
232
- for (const pattern of PRIMITIVE_PATH_PATTERNS) {
233
- if (pattern.test(normalized)) return true;
232
+ const atIndex = trimmed.lastIndexOf("@");
233
+ if (atIndex === -1) {
234
+ return null;
234
235
  }
235
- return false;
236
+ const maybeFunctionName = trimmed.slice(0, atIndex);
237
+ const location = trimmed.slice(atIndex + 1);
238
+ const [fileName, lineNumber, columnNumber] = extractStackLocation(location);
239
+ return {
240
+ functionName: maybeFunctionName || void 0,
241
+ fileName,
242
+ lineNumber,
243
+ columnNumber,
244
+ source: currentLine,
245
+ isServer: currentLine.includes(SERVER_FRAME_MARKER) || fileName.startsWith("rsc://")
246
+ };
236
247
  }
237
- function classifyComponentFiber(fiber, frames, elementSourceFile) {
238
- if (elementSourceFile && isComponentPrimitivePath(elementSourceFile)) {
239
- return { isComponentPrimitive: true };
248
+ function parseInStackLine(line) {
249
+ const functionName = line.replace(/^\s*in\s+/, "").replace(/\s*\(at .*\)$/, "").trim();
250
+ if (!functionName) return null;
251
+ return {
252
+ functionName,
253
+ source: line,
254
+ isServer: line.includes(SERVER_FRAME_MARKER)
255
+ };
256
+ }
257
+ function parseDebugStack(stack) {
258
+ const frames = [];
259
+ for (const rawLine of stack.split("\n")) {
260
+ if (FIREFOX_SAFARI_STACK_REGEXP.test(rawLine)) {
261
+ const parsed = parseFFOrSafariStackLine(rawLine);
262
+ if (parsed) frames.push(parsed);
263
+ continue;
264
+ }
265
+ if (/^\s*at\s+/.test(rawLine)) {
266
+ const parsed = parseV8StackLine(rawLine);
267
+ if (parsed) frames.push(parsed);
268
+ continue;
269
+ }
270
+ if (/^\s*in\s+/.test(rawLine)) {
271
+ const parsed = parseInStackLine(rawLine);
272
+ if (parsed) frames.push(parsed);
273
+ }
240
274
  }
241
- if (!fiber) return { isComponentPrimitive: false };
242
- const callSite = getCallSiteSource(fiber);
243
- if (callSite?.file && isComponentPrimitivePath(callSite.file)) {
244
- return { isComponentPrimitive: true };
275
+ return frames;
276
+ }
277
+ function normalizeStackFileName(fileName) {
278
+ if (!fileName) return "";
279
+ let normalized = fileName;
280
+ const isHttpUrl = normalized.startsWith("http://") || normalized.startsWith("https://");
281
+ if (isHttpUrl) {
282
+ try {
283
+ normalized = new URL(normalized).pathname;
284
+ } catch {
285
+ }
245
286
  }
246
- for (const frame of frames) {
247
- if (frame.file && isComponentPrimitivePath(frame.file)) {
248
- return { isComponentPrimitive: true };
287
+ let didStripPrefix = true;
288
+ while (didStripPrefix) {
289
+ didStripPrefix = false;
290
+ for (const prefix of STACK_INTERNAL_SCHEME_PREFIXES) {
291
+ if (normalized.startsWith(prefix)) {
292
+ normalized = normalized.slice(prefix.length);
293
+ if (prefix === "file:///") {
294
+ normalized = `/${normalized.replace(/^\/+/, "")}`;
295
+ }
296
+ didStripPrefix = true;
297
+ break;
298
+ }
249
299
  }
250
300
  }
251
- if (!elementSourceFile && fiber._debugSource) {
252
- return { isComponentPrimitive: true };
301
+ normalized = normalized.replace(/^\/\(app-pages-browser\)\//, "/").replace(/^\/\.\//, "/").replace(/^\.\//, "");
302
+ const queryIndex = normalized.indexOf("?");
303
+ if (queryIndex !== -1) {
304
+ normalized = normalized.slice(0, queryIndex);
253
305
  }
254
- return { isComponentPrimitive: false };
255
- }
256
-
257
- // src/utils.ts
258
- function clamp(value, min, max) {
259
- if (!Number.isFinite(value)) return min;
260
- if (max < min) return min;
261
- return Math.max(min, Math.min(max, value));
306
+ return normalized;
262
307
  }
263
- function isInputFocused() {
264
- let active = document.activeElement;
265
- while (active?.shadowRoot?.activeElement) {
266
- active = active.shadowRoot.activeElement;
267
- }
268
- return active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable;
308
+ function isSourceStackFile(fileName) {
309
+ const normalizedFileName = normalizeStackFileName(fileName);
310
+ if (!normalizedFileName) return false;
311
+ if (!STACK_SOURCE_FILE_EXTENSION_REGEX.test(normalizedFileName)) return false;
312
+ return !STACK_BUNDLED_FILE_PATTERN_REGEX.test(normalizedFileName);
269
313
  }
270
- function getComputedStyles(element) {
271
- const computed = window.getComputedStyle(element);
272
- return {
273
- spacing: {
274
- paddingTop: parsePropertyValue(computed.paddingTop),
275
- paddingRight: parsePropertyValue(computed.paddingRight),
276
- paddingBottom: parsePropertyValue(computed.paddingBottom),
277
- paddingLeft: parsePropertyValue(computed.paddingLeft),
278
- marginTop: parsePropertyValue(computed.marginTop),
279
- marginRight: parsePropertyValue(computed.marginRight),
280
- marginBottom: parsePropertyValue(computed.marginBottom),
281
- marginLeft: parsePropertyValue(computed.marginLeft),
282
- gap: parsePropertyValue(computed.gap || "0px")
283
- },
284
- borderRadius: {
285
- borderTopLeftRadius: parsePropertyValue(computed.borderTopLeftRadius),
286
- borderTopRightRadius: parsePropertyValue(computed.borderTopRightRadius),
287
- borderBottomRightRadius: parsePropertyValue(computed.borderBottomRightRadius),
288
- borderBottomLeftRadius: parsePropertyValue(computed.borderBottomLeftRadius)
289
- },
290
- flex: {
291
- display: computed.display,
292
- flexDirection: computed.flexDirection,
293
- justifyContent: computed.justifyContent,
294
- alignItems: computed.alignItems
314
+ function buildFunctionNameToRscFramesMap(fiber) {
315
+ const functionNameToRscFrames = /* @__PURE__ */ new Map();
316
+ const visited = /* @__PURE__ */ new Set();
317
+ let current = fiber;
318
+ while (current && !visited.has(current)) {
319
+ visited.add(current);
320
+ const rawStack = current?._debugStack?.stack;
321
+ const stack = typeof rawStack === "string" ? formatOwnerDebugStack(rawStack) : "";
322
+ if (stack) {
323
+ const frames = parseDebugStack(stack);
324
+ for (const frame of frames) {
325
+ if (!frame.functionName || !frame.fileName) continue;
326
+ if (!frame.fileName.startsWith("rsc://")) continue;
327
+ const normalized = normalizeStackFileName(frame.fileName);
328
+ if (!normalized) continue;
329
+ const existing = functionNameToRscFrames.get(frame.functionName) ?? [];
330
+ const duplicate = existing.some(
331
+ (candidate) => candidate.fileName === normalized && candidate.lineNumber === frame.lineNumber && candidate.columnNumber === frame.columnNumber
332
+ );
333
+ if (!duplicate) {
334
+ existing.push({
335
+ fileName: normalized,
336
+ lineNumber: frame.lineNumber,
337
+ columnNumber: frame.columnNumber
338
+ });
339
+ functionNameToRscFrames.set(frame.functionName, existing);
340
+ }
341
+ }
295
342
  }
296
- };
343
+ current = current._debugOwner ?? current.return ?? null;
344
+ }
345
+ return functionNameToRscFrames;
297
346
  }
298
- function getComputedBorderStyles(element) {
299
- const computed = window.getComputedStyle(element);
300
- const topStyle = computed.borderTopStyle;
301
- const rightStyle = computed.borderRightStyle;
302
- const bottomStyle = computed.borderBottomStyle;
303
- const leftStyle = computed.borderLeftStyle;
304
- const topWidth = parsePropertyValue(computed.borderTopWidth);
305
- const rightWidth = parsePropertyValue(computed.borderRightWidth);
306
- const bottomWidth = parsePropertyValue(computed.borderBottomWidth);
307
- const leftWidth = parsePropertyValue(computed.borderLeftWidth);
347
+ function enrichServerFrame(frame, functionNameToRscFrames, functionNameToUsageIndex) {
348
+ if (!frame.functionName) return frame;
349
+ const available = functionNameToRscFrames.get(frame.functionName);
350
+ if (!available) return frame;
351
+ const usageIndex = functionNameToUsageIndex.get(frame.functionName) ?? 0;
352
+ const resolved = available[usageIndex % available.length];
353
+ functionNameToUsageIndex.set(frame.functionName, usageIndex + 1);
308
354
  return {
309
- borderTopStyle: topStyle,
310
- borderTopWidth: topWidth,
311
- borderRightStyle: rightStyle,
312
- borderRightWidth: rightWidth,
313
- borderBottomStyle: bottomStyle,
314
- borderBottomWidth: bottomWidth,
315
- borderLeftStyle: leftStyle,
316
- borderLeftWidth: leftWidth
355
+ ...frame,
356
+ fileName: resolved.fileName,
357
+ lineNumber: resolved.lineNumber,
358
+ columnNumber: resolved.columnNumber
317
359
  };
318
360
  }
319
- var ORIGINAL_STYLE_PROPS = [
320
- "padding-top",
321
- "padding-right",
322
- "padding-bottom",
323
- "padding-left",
324
- "padding",
325
- "margin-top",
326
- "margin-right",
327
- "margin-bottom",
328
- "margin-left",
329
- "margin",
330
- "gap",
331
- "border-radius",
332
- "border-top-left-radius",
333
- "border-top-right-radius",
334
- "border-bottom-right-radius",
335
- "border-bottom-left-radius",
336
- "border",
337
- "border-style",
338
- "border-width",
339
- "border-top-style",
340
- "border-top-width",
341
- "border-right-style",
342
- "border-right-width",
343
- "border-bottom-style",
344
- "border-bottom-width",
345
- "border-left-style",
346
- "border-left-width",
347
- "display",
348
- "flex-direction",
349
- "justify-content",
350
- "align-items",
351
- "width",
352
- "height",
353
- "background-color",
354
- "background",
355
- "color",
356
- "border-color",
357
- "outline-color",
358
- "outline-style",
359
- "outline-width",
360
- "box-shadow",
361
- "font-family",
362
- "font-weight",
363
- "font-size",
364
- "line-height",
365
- "letter-spacing",
366
- "text-align"
367
- ];
368
- function getOriginalInlineStyles(element) {
369
- const styles = {};
370
- for (const prop of ORIGINAL_STYLE_PROPS) {
371
- const value = element.style.getPropertyValue(prop);
372
- if (value) {
373
- styles[prop] = value;
361
+ function getSourceFromDebugStack(fiber) {
362
+ const rawStack = fiber?._debugStack?.stack;
363
+ if (typeof rawStack !== "string" || rawStack.length === 0) {
364
+ return null;
365
+ }
366
+ const formattedStack = formatOwnerDebugStack(rawStack);
367
+ if (!formattedStack) return null;
368
+ const stackFrames = parseDebugStack(formattedStack);
369
+ const functionNameToRscFrames = buildFunctionNameToRscFramesMap(fiber);
370
+ const functionNameToUsageIndex = /* @__PURE__ */ new Map();
371
+ for (const frame of stackFrames) {
372
+ const maybeEnriched = frame.isServer ? enrichServerFrame(frame, functionNameToRscFrames, functionNameToUsageIndex) : frame;
373
+ if (!maybeEnriched.fileName) continue;
374
+ const normalizedFileName = normalizeStackFileName(maybeEnriched.fileName);
375
+ if (!normalizedFileName) continue;
376
+ if (isSourceStackFile(normalizedFileName)) {
377
+ return {
378
+ fileName: normalizedFileName,
379
+ lineNumber: maybeEnriched.lineNumber,
380
+ columnNumber: maybeEnriched.columnNumber
381
+ };
374
382
  }
375
383
  }
376
- return styles;
384
+ return null;
377
385
  }
378
- var spacingScale = { 0: "0", 1: "px", 2: "0.5", 4: "1", 8: "2", 12: "3", 16: "4", 20: "5", 24: "6", 32: "8" };
379
- var tailwindClassMap = {
380
- padding: { prefix: "p", scale: spacingScale },
381
- "padding-inline": { prefix: "px", scale: spacingScale },
382
- "padding-block": { prefix: "py", scale: spacingScale },
383
- "padding-top": { prefix: "pt", scale: spacingScale },
384
- "padding-right": { prefix: "pr", scale: spacingScale },
385
- "padding-bottom": { prefix: "pb", scale: spacingScale },
386
- "padding-left": { prefix: "pl", scale: spacingScale },
387
- margin: { prefix: "m", scale: spacingScale },
388
- "margin-inline": { prefix: "mx", scale: spacingScale },
389
- "margin-block": { prefix: "my", scale: spacingScale },
390
- "margin-top": { prefix: "mt", scale: spacingScale },
391
- "margin-right": { prefix: "mr", scale: spacingScale },
392
- "margin-bottom": { prefix: "mb", scale: spacingScale },
393
- "margin-left": { prefix: "ml", scale: spacingScale },
394
- gap: { prefix: "gap", scale: spacingScale },
395
- "border-width": {
396
- prefix: "border",
397
- scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
398
- },
399
- "border-top-width": {
400
- prefix: "border-t",
401
- scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
402
- },
403
- "border-right-width": {
404
- prefix: "border-r",
405
- scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
406
- },
407
- "border-bottom-width": {
408
- prefix: "border-b",
409
- scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
410
- },
411
- "border-left-width": {
412
- prefix: "border-l",
413
- scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
414
- },
415
- "border-radius": {
416
- prefix: "rounded",
417
- scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
418
- },
419
- "border-top-left-radius": {
420
- prefix: "rounded-tl",
421
- scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
422
- },
423
- "border-top-right-radius": {
424
- prefix: "rounded-tr",
425
- scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
426
- },
427
- "border-bottom-right-radius": {
428
- prefix: "rounded-br",
429
- scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
430
- },
431
- "border-bottom-left-radius": {
432
- prefix: "rounded-bl",
433
- scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
434
- }
435
- };
436
- var flexDirectionMap = {
437
- row: "flex-row",
438
- "row-reverse": "flex-row-reverse",
439
- column: "flex-col",
440
- "column-reverse": "flex-col-reverse"
441
- };
442
- var justifyContentMap = {
443
- "flex-start": "justify-start",
444
- "flex-end": "justify-end",
445
- center: "justify-center",
446
- "space-between": "justify-between",
447
- "space-around": "justify-around",
448
- "space-evenly": "justify-evenly",
449
- start: "justify-start",
450
- end: "justify-end"
451
- };
452
- var alignItemsMap = {
453
- "flex-start": "items-start",
454
- "flex-end": "items-end",
455
- center: "items-center",
456
- baseline: "items-baseline",
457
- stretch: "items-stretch",
458
- start: "items-start",
459
- end: "items-end"
460
- };
461
- function getExactScaleValue(value, scale) {
462
- if (Object.prototype.hasOwnProperty.call(scale, value)) {
463
- return scale[value];
386
+
387
+ // src/utils/react-fiber.ts
388
+ function getFiberForElement(element) {
389
+ if (typeof window !== "undefined") {
390
+ const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
391
+ if (devtools?.getFiberForElement) {
392
+ const fiber = devtools.getFiberForElement(element);
393
+ if (fiber) return fiber;
394
+ }
464
395
  }
396
+ const fiberKey = Object.keys(element).find(
397
+ (key) => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")
398
+ );
399
+ if (!fiberKey) return null;
400
+ return element[fiberKey] || null;
401
+ }
402
+ function getSourceFromFiber(fiber) {
403
+ const debugSource = fiber?._debugSource;
404
+ if (debugSource?.fileName) return debugSource;
405
+ const owner = fiber?._debugOwner;
406
+ const ownerPending = owner?.pendingProps?.__source;
407
+ if (ownerPending?.fileName) return ownerPending;
408
+ const ownerMemo = owner?.memoizedProps?.__source;
409
+ if (ownerMemo?.fileName) return ownerMemo;
410
+ const pending = fiber?.pendingProps?.__source;
411
+ if (pending?.fileName) return pending;
412
+ const memo = fiber?.memoizedProps?.__source;
413
+ if (memo?.fileName) return memo;
414
+ const fromDebugStack = getSourceFromDebugStack(fiber);
415
+ if (fromDebugStack?.fileName) return fromDebugStack;
465
416
  return null;
466
417
  }
467
- function normalizeTailwindArbitraryValue(value) {
468
- return value.trim().replace(/\s+/g, "_");
418
+ function buildFrame(fiber) {
419
+ const type = fiber?.type;
420
+ if (typeof type !== "function" && typeof type !== "object") return null;
421
+ const name = type?.displayName || type?.name || null;
422
+ if (!name || name === "Fragment") return null;
423
+ const frame = { name };
424
+ const source = getSourceFromFiber(fiber);
425
+ if (source?.fileName) {
426
+ frame.file = source.fileName;
427
+ if (typeof source.lineNumber === "number") {
428
+ frame.line = source.lineNumber;
429
+ }
430
+ if (typeof source.columnNumber === "number") {
431
+ frame.column = source.columnNumber;
432
+ }
433
+ }
434
+ return frame;
469
435
  }
470
- function normalizeShadowForComparison(value) {
471
- return value.trim().toLowerCase().replace(/\s*\/\s*/g, "/").replace(/\(\s+/g, "(").replace(/\s+\)/g, ")").replace(/\s*,\s*/g, ",").replace(/\s+/g, " ");
436
+ function shouldIncludeFrame(frame, lastFrame) {
437
+ if (!lastFrame) return true;
438
+ if (frame.name !== lastFrame.name) return true;
439
+ if (!lastFrame.file && frame.file) return true;
440
+ if (lastFrame.file && frame.file && lastFrame.line == null && frame.line != null) return true;
441
+ if (lastFrame.file && frame.file && lastFrame.line != null && frame.line != null && lastFrame.column == null && frame.column != null) {
442
+ return true;
443
+ }
444
+ return false;
472
445
  }
473
- var tailwindShadowClassValues = [
474
- { className: "shadow-2xs", css: "0 1px rgb(0 0 0 / 0.05)" },
475
- { className: "shadow-xs", css: "0 1px 2px 0 rgb(0 0 0 / 0.05)" },
476
- { className: "shadow", css: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)" },
477
- { className: "shadow-sm", css: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)" },
478
- { className: "shadow-md", css: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)" },
479
- { className: "shadow-lg", css: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)" },
480
- { className: "shadow-xl", css: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)" },
481
- { className: "shadow-2xl", css: "0 25px 50px -12px rgb(0 0 0 / 0.25)" },
482
- { className: "shadow-inner", css: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)" }
483
- ];
484
- function stylesToTailwind(styles) {
485
- const classes = [];
486
- for (const [prop, value] of Object.entries(styles)) {
487
- if (tailwindClassMap[prop]) {
488
- const parsed = parsePropertyValue(value);
489
- const mapping = tailwindClassMap[prop];
490
- if (value === "auto") {
491
- classes.push(`${mapping.prefix}-auto`);
492
- continue;
493
- }
494
- if (parsed.unit === "px") {
495
- const exactScale = getExactScaleValue(parsed.numericValue, mapping.scale);
496
- if (exactScale !== null) {
497
- if (exactScale === "") {
498
- classes.push(mapping.prefix);
499
- } else {
500
- classes.push(`${mapping.prefix}-${exactScale}`);
501
- }
502
- continue;
503
- }
446
+ function getOwnerStack(fiber) {
447
+ const frames = [];
448
+ let current = fiber;
449
+ let lastFrame = null;
450
+ let nearestComponentFiber = null;
451
+ while (current) {
452
+ const frame = buildFrame(current);
453
+ if (frame && shouldIncludeFrame(frame, lastFrame)) {
454
+ frames.push(frame);
455
+ lastFrame = frame;
456
+ if (!nearestComponentFiber) {
457
+ nearestComponentFiber = current;
504
458
  }
505
- classes.push(`${mapping.prefix}-[${value}]`);
506
- continue;
507
- }
508
- if (prop === "flex-direction" && flexDirectionMap[value]) {
509
- classes.push(flexDirectionMap[value]);
510
- continue;
511
- }
512
- if (prop === "justify-content" && justifyContentMap[value]) {
513
- classes.push(justifyContentMap[value]);
514
- continue;
515
- }
516
- if (prop === "align-items" && alignItemsMap[value]) {
517
- classes.push(alignItemsMap[value]);
518
- continue;
519
- }
520
- if (prop === "display") {
521
- if (value === "flex") classes.push("flex");
522
- else if (value === "inline-flex") classes.push("inline-flex");
523
- else if (value === "grid") classes.push("grid");
524
- else if (value === "block") classes.push("block");
525
- else if (value === "inline-block") classes.push("inline-block");
526
- else if (value === "none") classes.push("hidden");
527
- continue;
528
459
  }
529
- if (prop === "width") {
530
- if (value === "100%") classes.push("w-full");
531
- else if (value === "fit-content") classes.push("w-fit");
532
- else if (value === "auto") classes.push("w-auto");
533
- else classes.push(`w-[${value}]`);
534
- continue;
535
- }
536
- if (prop === "height") {
537
- if (value === "100%") classes.push("h-full");
538
- else if (value === "fit-content") classes.push("h-fit");
539
- else if (value === "auto") classes.push("h-auto");
540
- else classes.push(`h-[${value}]`);
541
- continue;
542
- }
543
- if (prop === "background-color") {
544
- const colorValue = parseColorValue(value);
545
- classes.push(colorToTailwind("backgroundColor", colorValue));
546
- continue;
460
+ current = current._debugOwner;
461
+ }
462
+ return { frames, nearestComponentFiber };
463
+ }
464
+ function getRenderStack(fiber) {
465
+ const frames = [];
466
+ let current = fiber;
467
+ let lastFrame = null;
468
+ let nearestComponentFiber = null;
469
+ while (current) {
470
+ const frame = buildFrame(current);
471
+ if (frame && shouldIncludeFrame(frame, lastFrame)) {
472
+ frames.push(frame);
473
+ lastFrame = frame;
474
+ if (!nearestComponentFiber) {
475
+ nearestComponentFiber = current;
476
+ }
547
477
  }
548
- if (prop === "color") {
549
- const colorValue = parseColorValue(value);
550
- classes.push(colorToTailwind("color", colorValue));
551
- continue;
478
+ current = current.return;
479
+ }
480
+ return { frames, nearestComponentFiber };
481
+ }
482
+ function getReactComponentInfo(element) {
483
+ const fiber = getFiberForElement(element);
484
+ if (!fiber) return { frames: [], nearestComponentFiber: null };
485
+ const elementSource = getSourceFromFiber(fiber);
486
+ const elementSourceFile = elementSource?.fileName || void 0;
487
+ const ownerResult = getOwnerStack(fiber);
488
+ if (ownerResult.frames.length > 0) {
489
+ return { ...ownerResult, elementSourceFile };
490
+ }
491
+ return { ...getRenderStack(fiber), elementSourceFile };
492
+ }
493
+ var EXCLUDED_PROP_KEYS = /* @__PURE__ */ new Set([
494
+ "className",
495
+ "style",
496
+ "children",
497
+ "ref",
498
+ "key",
499
+ "render"
500
+ ]);
501
+ function serializePropValue(value) {
502
+ if (typeof value === "function") return "[function]";
503
+ if (typeof value === "symbol") return void 0;
504
+ if (value === void 0) return void 0;
505
+ if (value !== null && typeof value === "object") {
506
+ if ("$$typeof" in value) return "[element]";
507
+ try {
508
+ JSON.stringify(value);
509
+ return value;
510
+ } catch {
511
+ return "[object]";
552
512
  }
553
- if (prop === "border-color") {
554
- const colorValue = parseColorValue(value);
555
- classes.push(colorToTailwind("borderColor", colorValue));
556
- continue;
513
+ }
514
+ return value;
515
+ }
516
+ function getComponentProps(fiber) {
517
+ const props = fiber?.memoizedProps ?? fiber?.pendingProps;
518
+ if (!props || typeof props !== "object") return {};
519
+ const result = {};
520
+ for (const [key, value] of Object.entries(props)) {
521
+ if (EXCLUDED_PROP_KEYS.has(key)) continue;
522
+ if (key.startsWith("data-")) continue;
523
+ const serialized = serializePropValue(value);
524
+ if (serialized !== void 0) {
525
+ result[key] = serialized;
557
526
  }
558
- if (prop === "border-style") {
559
- const styleMap = {
560
- none: "border-none",
561
- solid: "border-solid",
562
- dashed: "border-dashed",
563
- dotted: "border-dotted",
564
- double: "border-double"
565
- };
566
- classes.push(styleMap[value] || `[border-style:${value}]`);
567
- continue;
568
- }
569
- if (prop === "border-top-style" || prop === "border-right-style" || prop === "border-bottom-style" || prop === "border-left-style") {
570
- const allPresent = "border-top-style" in styles && "border-right-style" in styles && "border-bottom-style" in styles && "border-left-style" in styles;
571
- if (allPresent) {
572
- if (prop === "border-top-style") {
573
- const allSame = styles["border-top-style"] === styles["border-right-style"] && styles["border-top-style"] === styles["border-bottom-style"] && styles["border-top-style"] === styles["border-left-style"];
574
- if (allSame) {
575
- const styleMap = {
576
- none: "border-none",
577
- solid: "border-solid",
578
- dashed: "border-dashed",
579
- dotted: "border-dotted",
580
- double: "border-double"
581
- };
582
- classes.push(styleMap[value] || `[border-style:${value}]`);
583
- } else {
584
- classes.push(`[border-top-style:${styles["border-top-style"]}]`);
585
- classes.push(`[border-right-style:${styles["border-right-style"]}]`);
586
- classes.push(`[border-bottom-style:${styles["border-bottom-style"]}]`);
587
- classes.push(`[border-left-style:${styles["border-left-style"]}]`);
588
- }
589
- }
590
- } else {
591
- classes.push(`[${prop}:${value}]`);
592
- }
593
- continue;
594
- }
595
- if (prop === "outline-color") {
596
- const colorValue = parseColorValue(value);
597
- classes.push(colorToTailwind("outlineColor", colorValue));
598
- continue;
599
- }
600
- if (prop === "box-shadow") {
601
- const trimmed = value.trim();
602
- if (trimmed === "none" || trimmed === "") {
603
- classes.push("shadow-none");
604
- } else {
605
- const normalized = normalizeShadowForComparison(trimmed);
606
- const preset = tailwindShadowClassValues.find(
607
- (entry) => normalizeShadowForComparison(entry.css) === normalized
608
- );
609
- if (preset) classes.push(preset.className);
610
- else classes.push(`shadow-[${normalizeTailwindArbitraryValue(value)}]`);
611
- }
612
- continue;
613
- }
614
- if (prop === "font-size") {
615
- classes.push(`text-[${value}]`);
616
- continue;
617
- }
618
- if (prop === "font-weight") {
619
- const weightMap = {
620
- "100": "font-thin",
621
- "200": "font-extralight",
622
- "300": "font-light",
623
- "400": "font-normal",
624
- "500": "font-medium",
625
- "600": "font-semibold",
626
- "700": "font-bold",
627
- "800": "font-extrabold",
628
- "900": "font-black"
629
- };
630
- classes.push(weightMap[value] || `font-[${value}]`);
631
- continue;
632
- }
633
- if (prop === "line-height") {
634
- classes.push(`leading-[${value}]`);
635
- continue;
636
- }
637
- if (prop === "letter-spacing") {
638
- classes.push(`tracking-[${value}]`);
639
- continue;
640
- }
641
- if (prop === "text-align") {
642
- const alignMap = {
643
- left: "text-left",
644
- center: "text-center",
645
- right: "text-right",
646
- justify: "text-justify"
647
- };
648
- if (alignMap[value]) classes.push(alignMap[value]);
649
- continue;
650
- }
651
- if (prop === "font-family") {
652
- classes.push(`font-[${value.replace(/\s+/g, "_")}]`);
653
- continue;
527
+ }
528
+ return result;
529
+ }
530
+ function getCallSiteSource(fiber) {
531
+ const source = fiber?._debugSource;
532
+ if (source?.fileName) {
533
+ return {
534
+ file: source.fileName,
535
+ line: typeof source.lineNumber === "number" ? source.lineNumber : void 0,
536
+ column: typeof source.columnNumber === "number" ? source.columnNumber : void 0
537
+ };
538
+ }
539
+ const pending = fiber?.pendingProps?.__source;
540
+ if (pending?.fileName) {
541
+ return {
542
+ file: pending.fileName,
543
+ line: typeof pending.lineNumber === "number" ? pending.lineNumber : void 0,
544
+ column: typeof pending.columnNumber === "number" ? pending.columnNumber : void 0
545
+ };
546
+ }
547
+ return null;
548
+ }
549
+ function deriveDefinitionSource(frames) {
550
+ for (const frame of frames) {
551
+ if (frame.file && isComponentPrimitivePath(frame.file)) {
552
+ return { file: frame.file, line: frame.line, column: frame.column };
654
553
  }
655
554
  }
656
- return classes.join(" ");
657
- }
658
- var propertyToCSSMap = {
659
- paddingTop: "padding-top",
660
- paddingRight: "padding-right",
661
- paddingBottom: "padding-bottom",
662
- paddingLeft: "padding-left",
663
- marginTop: "margin-top",
664
- marginRight: "margin-right",
665
- marginBottom: "margin-bottom",
666
- marginLeft: "margin-left",
667
- gap: "gap"
668
- };
669
- var borderRadiusPropertyToCSSMap = {
670
- borderTopLeftRadius: "border-top-left-radius",
671
- borderTopRightRadius: "border-top-right-radius",
672
- borderBottomRightRadius: "border-bottom-right-radius",
673
- borderBottomLeftRadius: "border-bottom-left-radius"
674
- };
675
- var borderPropertyToCSSMap = {
676
- borderTopStyle: "border-top-style",
677
- borderTopWidth: "border-top-width",
678
- borderRightStyle: "border-right-style",
679
- borderRightWidth: "border-right-width",
680
- borderBottomStyle: "border-bottom-style",
681
- borderBottomWidth: "border-bottom-width",
682
- borderLeftStyle: "border-left-style",
683
- borderLeftWidth: "border-left-width"
684
- };
685
- var flexPropertyToCSSMap = {
686
- display: "display",
687
- flexDirection: "flex-direction",
688
- justifyContent: "justify-content",
689
- alignItems: "align-items"
690
- };
691
- var sizingPropertyToCSSMap = {
692
- width: "width",
693
- height: "height"
694
- };
695
- var typographyPropertyToCSSMap = {
696
- fontFamily: "font-family",
697
- fontWeight: "font-weight",
698
- fontSize: "font-size",
699
- lineHeight: "line-height",
700
- letterSpacing: "letter-spacing",
701
- textAlign: "text-align",
702
- textVerticalAlign: "align-items"
703
- };
704
- var TEXT_ELEMENT_TAGS = /* @__PURE__ */ new Set([
705
- "p",
706
- "h1",
707
- "h2",
708
- "h3",
709
- "h4",
710
- "h5",
711
- "h6",
712
- "span",
713
- "label",
714
- "a",
715
- "strong",
716
- "em",
717
- "small",
718
- "blockquote",
719
- "li",
720
- "td",
721
- "th",
722
- "caption",
723
- "figcaption",
724
- "legend",
725
- "dt",
726
- "dd",
727
- "abbr",
728
- "cite",
729
- "code",
730
- "pre"
731
- ]);
732
- function hasDirectNonWhitespaceText(element) {
733
- return Array.from(element.childNodes).some(
734
- (node) => node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim())
735
- );
555
+ return null;
736
556
  }
737
- function isTextElement2(element) {
738
- const tagName = element.tagName.toLowerCase();
739
- if (TEXT_ELEMENT_TAGS.has(tagName)) {
740
- return true;
557
+ var PRIMITIVE_PATH_PATTERNS = [
558
+ /(?:^|\/)components\/ui\//,
559
+ /(?:^|\/)ui\/primitives\//,
560
+ /(?:^|\/)design-system\//
561
+ ];
562
+ var PRIMITIVE_NPM_PATTERNS = [
563
+ /@base-ui\//,
564
+ /@radix-ui\//,
565
+ /@headlessui\//,
566
+ /@chakra-ui\//,
567
+ /@mantine\//,
568
+ /@mui\//,
569
+ /@ark-ui\//
570
+ ];
571
+ var FRAMEWORK_EXCLUSION_PATTERNS = [
572
+ /node_modules\/react\//,
573
+ /node_modules\/react-dom\//,
574
+ /node_modules\/next\/dist\//,
575
+ /node_modules\/scheduler\//,
576
+ /node_modules\/react-server\//
577
+ ];
578
+ function isComponentPrimitivePath(filePath) {
579
+ const normalized = filePath.replace(/\\/g, "/");
580
+ for (const pattern of FRAMEWORK_EXCLUSION_PATTERNS) {
581
+ if (pattern.test(normalized)) return false;
741
582
  }
742
- if (hasDirectNonWhitespaceText(element)) {
743
- return true;
583
+ for (const pattern of PRIMITIVE_NPM_PATTERNS) {
584
+ if (pattern.test(normalized)) return true;
744
585
  }
745
- if (element.children.length === 0 && element.textContent?.trim()) {
746
- return true;
586
+ for (const pattern of PRIMITIVE_PATH_PATTERNS) {
587
+ if (pattern.test(normalized)) return true;
747
588
  }
748
589
  return false;
749
590
  }
750
- function getComputedTypography(element) {
751
- const computed = window.getComputedStyle(element);
752
- let textVerticalAlign = "flex-start";
753
- if (computed.display === "flex" || computed.display === "inline-flex") {
754
- const alignItems = computed.alignItems;
755
- if (alignItems === "center") textVerticalAlign = "center";
756
- else if (alignItems === "flex-end" || alignItems === "end") textVerticalAlign = "flex-end";
591
+ function classifyComponentFiber(fiber, frames, elementSourceFile) {
592
+ if (elementSourceFile && isComponentPrimitivePath(elementSourceFile)) {
593
+ return { isComponentPrimitive: true };
757
594
  }
758
- const lineHeight = computed.lineHeight === "normal" ? { numericValue: parseFloat(computed.fontSize) * 1.2, unit: "px", raw: `${Math.round(parseFloat(computed.fontSize) * 1.2)}px` } : parsePropertyValue(computed.lineHeight);
759
- const fontSize = parseFloat(computed.fontSize);
760
- let letterSpacing;
761
- if (computed.letterSpacing === "normal") {
762
- letterSpacing = { numericValue: 0, unit: "em", raw: "0em" };
763
- } else {
764
- const parsed = parsePropertyValue(computed.letterSpacing);
765
- if (parsed.unit === "px" && fontSize > 0) {
766
- const emValue = Math.round(parsed.numericValue / fontSize * 100) / 100;
767
- letterSpacing = { numericValue: emValue, unit: "em", raw: `${emValue}em` };
768
- } else {
769
- letterSpacing = parsed;
595
+ if (!fiber) return { isComponentPrimitive: false };
596
+ const callSite = getCallSiteSource(fiber);
597
+ if (callSite?.file && isComponentPrimitivePath(callSite.file)) {
598
+ return { isComponentPrimitive: true };
599
+ }
600
+ for (const frame of frames) {
601
+ if (frame.file && isComponentPrimitivePath(frame.file)) {
602
+ return { isComponentPrimitive: true };
770
603
  }
771
604
  }
772
- return {
773
- fontFamily: computed.fontFamily,
774
- fontWeight: computed.fontWeight,
775
- fontSize: parsePropertyValue(computed.fontSize),
776
- lineHeight,
777
- letterSpacing,
778
- textAlign: computed.textAlign,
779
- textVerticalAlign
780
- };
781
- }
782
- function detectSizingMode(element, dimension) {
783
- const computed = window.getComputedStyle(element);
784
- const inlineValue = element.style[dimension];
785
- if (inlineValue === "100%") return "fill";
786
- if (inlineValue === "auto" || inlineValue === "fit-content") return "fit";
787
- const computedValue = computed[dimension];
788
- if (computedValue === "100%") return "fill";
789
- if (computedValue === "auto" || computedValue === "fit-content" || computedValue === "max-content") {
790
- return "fit";
605
+ if (!elementSourceFile && fiber._debugSource) {
606
+ return { isComponentPrimitive: true };
791
607
  }
792
- const parent = element.parentElement;
793
- if (parent) {
794
- const parentComputed = window.getComputedStyle(parent);
795
- if (parentComputed.display === "flex" || parentComputed.display === "inline-flex") {
796
- const flexGrow = computed.flexGrow;
797
- if (flexGrow !== "0") {
798
- return "fill";
799
- }
800
- }
801
- }
802
- if (dimension === "width") {
803
- if (computed.display === "block" && !inlineValue) {
804
- return "fill";
805
- }
806
- if (computed.display === "inline-block" || computed.display === "inline-flex" || computed.display === "inline") {
807
- return "fit";
808
- }
809
- }
810
- if (dimension === "height") {
811
- if (!inlineValue) {
812
- return "fit";
813
- }
608
+ return { isComponentPrimitive: false };
609
+ }
610
+
611
+ // src/utils.ts
612
+ function clamp(value, min, max) {
613
+ if (!Number.isFinite(value)) return min;
614
+ if (max < min) return min;
615
+ return Math.max(min, Math.min(max, value));
616
+ }
617
+ function isInputFocused() {
618
+ let active = document.activeElement;
619
+ while (active?.shadowRoot?.activeElement) {
620
+ active = active.shadowRoot.activeElement;
814
621
  }
815
- return "fixed";
622
+ return active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement || active instanceof HTMLElement && active.isContentEditable;
816
623
  }
817
- function getSizingValue(element, dimension) {
818
- const mode = detectSizingMode(element, dimension);
819
- const numericValue = Math.round(dimension === "width" ? element.offsetWidth : element.offsetHeight);
624
+ function getComputedStyles(element) {
625
+ const computed = window.getComputedStyle(element);
820
626
  return {
821
- mode,
822
- value: {
823
- numericValue,
824
- unit: "px",
825
- raw: `${numericValue}px`
627
+ spacing: {
628
+ paddingTop: parsePropertyValue(computed.paddingTop),
629
+ paddingRight: parsePropertyValue(computed.paddingRight),
630
+ paddingBottom: parsePropertyValue(computed.paddingBottom),
631
+ paddingLeft: parsePropertyValue(computed.paddingLeft),
632
+ marginTop: parsePropertyValue(computed.marginTop),
633
+ marginRight: parsePropertyValue(computed.marginRight),
634
+ marginBottom: parsePropertyValue(computed.marginBottom),
635
+ marginLeft: parsePropertyValue(computed.marginLeft),
636
+ gap: parsePropertyValue(computed.gap || "0px")
637
+ },
638
+ borderRadius: {
639
+ borderTopLeftRadius: parsePropertyValue(computed.borderTopLeftRadius),
640
+ borderTopRightRadius: parsePropertyValue(computed.borderTopRightRadius),
641
+ borderBottomRightRadius: parsePropertyValue(computed.borderBottomRightRadius),
642
+ borderBottomLeftRadius: parsePropertyValue(computed.borderBottomLeftRadius)
643
+ },
644
+ flex: {
645
+ display: computed.display,
646
+ flexDirection: computed.flexDirection,
647
+ justifyContent: computed.justifyContent,
648
+ alignItems: computed.alignItems
826
649
  }
827
650
  };
828
651
  }
829
- function getComputedSizing(element) {
652
+ function getComputedBorderStyles(element) {
653
+ const computed = window.getComputedStyle(element);
654
+ const topStyle = computed.borderTopStyle;
655
+ const rightStyle = computed.borderRightStyle;
656
+ const bottomStyle = computed.borderBottomStyle;
657
+ const leftStyle = computed.borderLeftStyle;
658
+ const topWidth = parsePropertyValue(computed.borderTopWidth);
659
+ const rightWidth = parsePropertyValue(computed.borderRightWidth);
660
+ const bottomWidth = parsePropertyValue(computed.borderBottomWidth);
661
+ const leftWidth = parsePropertyValue(computed.borderLeftWidth);
830
662
  return {
831
- width: getSizingValue(element, "width"),
832
- height: getSizingValue(element, "height")
663
+ borderTopStyle: topStyle,
664
+ borderTopWidth: topWidth,
665
+ borderRightStyle: rightStyle,
666
+ borderRightWidth: rightWidth,
667
+ borderBottomStyle: bottomStyle,
668
+ borderBottomWidth: bottomWidth,
669
+ borderLeftStyle: leftStyle,
670
+ borderLeftWidth: leftWidth
833
671
  };
834
672
  }
835
- function sizingValueToCSS(sizing) {
836
- switch (sizing.mode) {
837
- case "fill":
838
- return "100%";
839
- case "fit":
840
- return "fit-content";
841
- case "fixed":
842
- return `${sizing.value.numericValue}${sizing.value.unit}`;
843
- }
844
- }
845
- function sizingToTailwind(dimension, sizing) {
846
- const prefix = dimension === "width" ? "w" : "h";
847
- switch (sizing.mode) {
848
- case "fill":
849
- return `${prefix}-full`;
850
- case "fit":
851
- return `${prefix}-fit`;
852
- case "fixed":
853
- return `${prefix}-[${sizing.value.numericValue}${sizing.value.unit}]`;
673
+ var ORIGINAL_STYLE_PROPS = [
674
+ "padding-top",
675
+ "padding-right",
676
+ "padding-bottom",
677
+ "padding-left",
678
+ "padding",
679
+ "margin-top",
680
+ "margin-right",
681
+ "margin-bottom",
682
+ "margin-left",
683
+ "margin",
684
+ "gap",
685
+ "border-radius",
686
+ "border-top-left-radius",
687
+ "border-top-right-radius",
688
+ "border-bottom-right-radius",
689
+ "border-bottom-left-radius",
690
+ "border",
691
+ "border-style",
692
+ "border-width",
693
+ "border-top-style",
694
+ "border-top-width",
695
+ "border-right-style",
696
+ "border-right-width",
697
+ "border-bottom-style",
698
+ "border-bottom-width",
699
+ "border-left-style",
700
+ "border-left-width",
701
+ "display",
702
+ "flex-direction",
703
+ "justify-content",
704
+ "align-items",
705
+ "width",
706
+ "height",
707
+ "background-color",
708
+ "background",
709
+ "color",
710
+ "border-color",
711
+ "outline-color",
712
+ "outline-style",
713
+ "outline-width",
714
+ "box-shadow",
715
+ "font-family",
716
+ "font-weight",
717
+ "font-size",
718
+ "line-height",
719
+ "letter-spacing",
720
+ "text-align"
721
+ ];
722
+ function getOriginalInlineStyles(element) {
723
+ const styles = {};
724
+ for (const prop of ORIGINAL_STYLE_PROPS) {
725
+ const value = element.style.getPropertyValue(prop);
726
+ if (value) {
727
+ styles[prop] = value;
728
+ }
854
729
  }
730
+ return styles;
855
731
  }
856
- function parseHexColor(hex) {
857
- const raw = hex;
858
- let h = hex.replace("#", "");
859
- if (h.length === 3) {
860
- h = h.split("").map((c) => c + c).join("");
732
+ var spacingScale = { 0: "0", 1: "px", 2: "0.5", 4: "1", 8: "2", 12: "3", 16: "4", 20: "5", 24: "6", 32: "8" };
733
+ var tailwindClassMap = {
734
+ padding: { prefix: "p", scale: spacingScale },
735
+ "padding-inline": { prefix: "px", scale: spacingScale },
736
+ "padding-block": { prefix: "py", scale: spacingScale },
737
+ "padding-top": { prefix: "pt", scale: spacingScale },
738
+ "padding-right": { prefix: "pr", scale: spacingScale },
739
+ "padding-bottom": { prefix: "pb", scale: spacingScale },
740
+ "padding-left": { prefix: "pl", scale: spacingScale },
741
+ margin: { prefix: "m", scale: spacingScale },
742
+ "margin-inline": { prefix: "mx", scale: spacingScale },
743
+ "margin-block": { prefix: "my", scale: spacingScale },
744
+ "margin-top": { prefix: "mt", scale: spacingScale },
745
+ "margin-right": { prefix: "mr", scale: spacingScale },
746
+ "margin-bottom": { prefix: "mb", scale: spacingScale },
747
+ "margin-left": { prefix: "ml", scale: spacingScale },
748
+ gap: { prefix: "gap", scale: spacingScale },
749
+ "border-width": {
750
+ prefix: "border",
751
+ scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
752
+ },
753
+ "border-top-width": {
754
+ prefix: "border-t",
755
+ scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
756
+ },
757
+ "border-right-width": {
758
+ prefix: "border-r",
759
+ scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
760
+ },
761
+ "border-bottom-width": {
762
+ prefix: "border-b",
763
+ scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
764
+ },
765
+ "border-left-width": {
766
+ prefix: "border-l",
767
+ scale: { 0: "0", 1: "", 2: "2", 4: "4", 8: "8" }
768
+ },
769
+ "border-radius": {
770
+ prefix: "rounded",
771
+ scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
772
+ },
773
+ "border-top-left-radius": {
774
+ prefix: "rounded-tl",
775
+ scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
776
+ },
777
+ "border-top-right-radius": {
778
+ prefix: "rounded-tr",
779
+ scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
780
+ },
781
+ "border-bottom-right-radius": {
782
+ prefix: "rounded-br",
783
+ scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
784
+ },
785
+ "border-bottom-left-radius": {
786
+ prefix: "rounded-bl",
787
+ scale: { 0: "none", 2: "sm", 4: "", 6: "md", 8: "lg", 12: "xl", 16: "2xl", 24: "3xl", 9999: "full" }
861
788
  }
862
- if (h.length === 8) {
863
- const alpha = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100);
864
- return { hex: h.slice(0, 6).toUpperCase(), alpha, raw };
789
+ };
790
+ var flexDirectionMap = {
791
+ row: "flex-row",
792
+ "row-reverse": "flex-row-reverse",
793
+ column: "flex-col",
794
+ "column-reverse": "flex-col-reverse"
795
+ };
796
+ var justifyContentMap = {
797
+ "flex-start": "justify-start",
798
+ "flex-end": "justify-end",
799
+ center: "justify-center",
800
+ "space-between": "justify-between",
801
+ "space-around": "justify-around",
802
+ "space-evenly": "justify-evenly",
803
+ start: "justify-start",
804
+ end: "justify-end"
805
+ };
806
+ var alignItemsMap = {
807
+ "flex-start": "items-start",
808
+ "flex-end": "items-end",
809
+ center: "items-center",
810
+ baseline: "items-baseline",
811
+ stretch: "items-stretch",
812
+ start: "items-start",
813
+ end: "items-end"
814
+ };
815
+ function getExactScaleValue(value, scale) {
816
+ if (Object.prototype.hasOwnProperty.call(scale, value)) {
817
+ return scale[value];
865
818
  }
866
- return { hex: h.toUpperCase(), alpha: 100, raw };
819
+ return null;
867
820
  }
868
- function parseRgbChannel(value) {
869
- const token = value.trim();
870
- if (!token) return null;
871
- if (token.endsWith("%")) {
872
- const numeric2 = parseFloat(token.slice(0, -1));
873
- if (!Number.isFinite(numeric2)) return null;
874
- return Math.round(Math.max(0, Math.min(100, numeric2)) / 100 * 255);
875
- }
876
- const numeric = parseFloat(token);
877
- if (!Number.isFinite(numeric)) return null;
878
- return Math.round(Math.max(0, Math.min(255, numeric)));
821
+ function normalizeTailwindArbitraryValue(value) {
822
+ return value.trim().replace(/\s+/g, "_");
879
823
  }
880
- function parseRgbAlpha(value) {
881
- if (value == null || value.trim() === "") return 1;
882
- const token = value.trim();
883
- if (token.endsWith("%")) {
884
- const numeric2 = parseFloat(token.slice(0, -1));
885
- if (!Number.isFinite(numeric2)) return null;
886
- return Math.max(0, Math.min(100, numeric2)) / 100;
887
- }
888
- const numeric = parseFloat(token);
889
- if (!Number.isFinite(numeric)) return null;
890
- return Math.max(0, Math.min(1, numeric));
824
+ function normalizeShadowForComparison(value) {
825
+ return value.trim().toLowerCase().replace(/\s*\/\s*/g, "/").replace(/\(\s+/g, "(").replace(/\s+\)/g, ")").replace(/\s*,\s*/g, ",").replace(/\s+/g, " ");
891
826
  }
892
- function parseRgbaColor(rgba) {
893
- const raw = rgba.trim();
894
- const fnMatch = raw.match(/^rgba?\((.*)\)$/i);
895
- if (!fnMatch) {
896
- return { hex: "000000", alpha: 100, raw: rgba };
897
- }
898
- const body = fnMatch[1].trim();
899
- let channelTokens = null;
900
- let alphaToken;
901
- const commaParts = body.split(",").map((part) => part.trim()).filter(Boolean);
902
- if (commaParts.length === 3 || commaParts.length === 4) {
903
- channelTokens = [commaParts[0], commaParts[1], commaParts[2]];
904
- alphaToken = commaParts[3];
905
- } else {
906
- const slashParts = body.split("/");
907
- if (slashParts.length === 1 || slashParts.length === 2) {
908
- const channels = slashParts[0].trim().split(/\s+/).filter(Boolean);
909
- if (channels.length === 3) {
910
- channelTokens = [channels[0], channels[1], channels[2]];
911
- alphaToken = slashParts[1]?.trim();
827
+ var tailwindShadowClassValues = [
828
+ { className: "shadow-2xs", css: "0 1px rgb(0 0 0 / 0.05)" },
829
+ { className: "shadow-xs", css: "0 1px 2px 0 rgb(0 0 0 / 0.05)" },
830
+ { className: "shadow", css: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)" },
831
+ { className: "shadow-sm", css: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)" },
832
+ { className: "shadow-md", css: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)" },
833
+ { className: "shadow-lg", css: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)" },
834
+ { className: "shadow-xl", css: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)" },
835
+ { className: "shadow-2xl", css: "0 25px 50px -12px rgb(0 0 0 / 0.25)" },
836
+ { className: "shadow-inner", css: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)" }
837
+ ];
838
+ function stylesToTailwind(styles) {
839
+ const classes = [];
840
+ for (const [prop, value] of Object.entries(styles)) {
841
+ if (tailwindClassMap[prop]) {
842
+ const parsed = parsePropertyValue(value);
843
+ const mapping = tailwindClassMap[prop];
844
+ if (value === "auto") {
845
+ classes.push(`${mapping.prefix}-auto`);
846
+ continue;
847
+ }
848
+ if (parsed.unit === "px") {
849
+ const exactScale = getExactScaleValue(parsed.numericValue, mapping.scale);
850
+ if (exactScale !== null) {
851
+ if (exactScale === "") {
852
+ classes.push(mapping.prefix);
853
+ } else {
854
+ classes.push(`${mapping.prefix}-${exactScale}`);
855
+ }
856
+ continue;
857
+ }
912
858
  }
859
+ classes.push(`${mapping.prefix}-[${value}]`);
860
+ continue;
913
861
  }
914
- }
915
- if (!channelTokens) {
916
- return { hex: "000000", alpha: 100, raw: rgba };
917
- }
918
- const r = parseRgbChannel(channelTokens[0]);
919
- const g = parseRgbChannel(channelTokens[1]);
920
- const b = parseRgbChannel(channelTokens[2]);
921
- const a = parseRgbAlpha(alphaToken);
922
- if (r === null || g === null || b === null || a === null) {
923
- return { hex: "000000", alpha: 100, raw: rgba };
924
- }
925
- const hex = [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("").toUpperCase();
926
- const alpha = Math.round(a * 100);
927
- return { hex, alpha, raw: rgba };
928
- }
929
- function parseNamedColor(name) {
930
- const ctx = document.createElement("canvas").getContext("2d");
931
- if (!ctx) {
932
- return { hex: "000000", alpha: 100, raw: name };
933
- }
934
- ctx.fillStyle = name;
935
- const computed = ctx.fillStyle;
936
- if (computed.startsWith("#")) {
937
- return parseHexColor(computed);
938
- }
939
- return parseRgbaColor(computed);
940
- }
941
- function parseColorValue(cssValue) {
942
- const raw = cssValue.trim();
943
- if (raw === "transparent") {
944
- return { hex: "000000", alpha: 0, raw };
945
- }
946
- if (raw.startsWith("#")) {
947
- return parseHexColor(raw);
948
- }
949
- if (raw.startsWith("rgb")) {
950
- return parseRgbaColor(raw);
951
- }
952
- return parseNamedColor(raw);
953
- }
954
- var TRANSPARENT_COLOR = { hex: "000000", alpha: 0, raw: "transparent" };
955
- function isVisibleBorderSide(side) {
956
- return side.style !== "none" && side.style !== "hidden" && parseFloat(side.width) > 0;
957
- }
958
- function hasVisibleOutline(computed) {
959
- return computed.outlineStyle !== "none" && parseFloat(computed.outlineWidth) > 0;
960
- }
961
- function parseVisibleColor(value, fallbackCurrentColor) {
962
- const raw = value.trim();
963
- const lowered = raw.toLowerCase();
964
- if (!raw || lowered === "none" || lowered === "transparent") {
965
- return null;
966
- }
967
- const resolved = /^currentcolor$/i.test(raw) ? fallbackCurrentColor ?? raw : raw;
968
- const parsed = parseColorValue(resolved);
969
- if (parsed.alpha <= 0) {
970
- return null;
971
- }
972
- return parsed;
973
- }
974
- function addUniqueColor(colors, color) {
975
- if (!color) return;
976
- colors.set(`${color.hex}:${color.alpha}`, color);
977
- }
978
- function isTextRenderingFormControl(element) {
979
- if (element instanceof HTMLTextAreaElement) return true;
980
- if (element instanceof HTMLSelectElement) return true;
981
- if (element instanceof HTMLButtonElement) return true;
982
- if (element instanceof HTMLInputElement) {
983
- const textlessInputTypes = /* @__PURE__ */ new Set([
984
- "hidden",
985
- "checkbox",
986
- "radio",
987
- "range",
988
- "color",
989
- "file",
990
- "image"
991
- ]);
992
- return !textlessInputTypes.has(element.type.toLowerCase());
993
- }
994
- return false;
995
- }
996
- function hasRenderableTextNode(element) {
997
- if (element.isContentEditable) return true;
998
- if (isTextRenderingFormControl(element)) return true;
999
- if (!element.textContent?.trim()) return false;
1000
- if (hasDirectNonWhitespaceText(element)) return true;
1001
- const tagName = element.tagName.toLowerCase();
1002
- return TEXT_ELEMENT_TAGS.has(tagName) || element.children.length === 0;
1003
- }
1004
- function getComputedBoxShadow(element) {
1005
- const computed = window.getComputedStyle(element);
1006
- const value = computed.boxShadow.trim();
1007
- return value || "none";
1008
- }
1009
- function getComputedColorStyles(element) {
1010
- const computed = window.getComputedStyle(element);
1011
- const borderSides = [
1012
- { style: computed.borderTopStyle, width: computed.borderTopWidth, color: computed.borderTopColor },
1013
- { style: computed.borderRightStyle, width: computed.borderRightWidth, color: computed.borderRightColor },
1014
- { style: computed.borderBottomStyle, width: computed.borderBottomWidth, color: computed.borderBottomColor },
1015
- { style: computed.borderLeftStyle, width: computed.borderLeftWidth, color: computed.borderLeftColor }
1016
- ];
1017
- const visibleBorderSide = borderSides.find((side) => isVisibleBorderSide(side));
1018
- const hasBorder = Boolean(visibleBorderSide);
1019
- const hasOutline = hasVisibleOutline(computed);
1020
- return {
1021
- backgroundColor: parseColorValue(computed.backgroundColor),
1022
- color: parseColorValue(computed.color),
1023
- borderColor: hasBorder && visibleBorderSide ? parseColorValue(visibleBorderSide.color) : TRANSPARENT_COLOR,
1024
- outlineColor: hasOutline ? parseColorValue(computed.outlineColor) : TRANSPARENT_COLOR
1025
- };
1026
- }
1027
- function getSelectionColors(element) {
1028
- const uniqueColors = /* @__PURE__ */ new Map();
1029
- const queue = [element];
1030
- for (let index = 0; index < queue.length; index++) {
1031
- const node = queue[index];
1032
- const computed = window.getComputedStyle(node);
1033
- if (computed.display === "none") {
862
+ if (prop === "flex-direction" && flexDirectionMap[value]) {
863
+ classes.push(flexDirectionMap[value]);
1034
864
  continue;
1035
865
  }
1036
- const isVisibilityHidden = computed.visibility === "hidden" || computed.visibility === "collapse";
1037
- const currentTextColor = computed.color;
1038
- if (!isVisibilityHidden) {
1039
- addUniqueColor(uniqueColors, parseVisibleColor(computed.backgroundColor));
1040
- if (node instanceof HTMLElement && hasRenderableTextNode(node)) {
1041
- addUniqueColor(uniqueColors, parseVisibleColor(currentTextColor));
1042
- }
1043
- const borderSides = [
1044
- { style: computed.borderTopStyle, width: computed.borderTopWidth, color: computed.borderTopColor },
1045
- { style: computed.borderRightStyle, width: computed.borderRightWidth, color: computed.borderRightColor },
1046
- { style: computed.borderBottomStyle, width: computed.borderBottomWidth, color: computed.borderBottomColor },
1047
- { style: computed.borderLeftStyle, width: computed.borderLeftWidth, color: computed.borderLeftColor }
1048
- ];
1049
- for (const side of borderSides) {
1050
- if (!isVisibleBorderSide(side)) continue;
1051
- addUniqueColor(uniqueColors, parseVisibleColor(side.color, currentTextColor));
1052
- }
1053
- if (hasVisibleOutline(computed)) {
1054
- addUniqueColor(uniqueColors, parseVisibleColor(computed.outlineColor, currentTextColor));
866
+ if (prop === "justify-content" && justifyContentMap[value]) {
867
+ classes.push(justifyContentMap[value]);
868
+ continue;
869
+ }
870
+ if (prop === "align-items" && alignItemsMap[value]) {
871
+ classes.push(alignItemsMap[value]);
872
+ continue;
873
+ }
874
+ if (prop === "display") {
875
+ if (value === "flex") classes.push("flex");
876
+ else if (value === "inline-flex") classes.push("inline-flex");
877
+ else if (value === "grid") classes.push("grid");
878
+ else if (value === "block") classes.push("block");
879
+ else if (value === "inline-block") classes.push("inline-block");
880
+ else if (value === "none") classes.push("hidden");
881
+ continue;
882
+ }
883
+ if (prop === "width") {
884
+ if (value === "100%") classes.push("w-full");
885
+ else if (value === "fit-content") classes.push("w-fit");
886
+ else if (value === "auto") classes.push("w-auto");
887
+ else classes.push(`w-[${value}]`);
888
+ continue;
889
+ }
890
+ if (prop === "height") {
891
+ if (value === "100%") classes.push("h-full");
892
+ else if (value === "fit-content") classes.push("h-fit");
893
+ else if (value === "auto") classes.push("h-auto");
894
+ else classes.push(`h-[${value}]`);
895
+ continue;
896
+ }
897
+ if (prop === "background-color") {
898
+ const colorValue = parseColorValue(value);
899
+ classes.push(colorToTailwind("backgroundColor", colorValue));
900
+ continue;
901
+ }
902
+ if (prop === "color") {
903
+ const colorValue = parseColorValue(value);
904
+ classes.push(colorToTailwind("color", colorValue));
905
+ continue;
906
+ }
907
+ if (prop === "border-color") {
908
+ const colorValue = parseColorValue(value);
909
+ classes.push(colorToTailwind("borderColor", colorValue));
910
+ continue;
911
+ }
912
+ if (prop === "border-style") {
913
+ const styleMap = {
914
+ none: "border-none",
915
+ solid: "border-solid",
916
+ dashed: "border-dashed",
917
+ dotted: "border-dotted",
918
+ double: "border-double"
919
+ };
920
+ classes.push(styleMap[value] || `[border-style:${value}]`);
921
+ continue;
922
+ }
923
+ if (prop === "border-top-style" || prop === "border-right-style" || prop === "border-bottom-style" || prop === "border-left-style") {
924
+ const allPresent = "border-top-style" in styles && "border-right-style" in styles && "border-bottom-style" in styles && "border-left-style" in styles;
925
+ if (allPresent) {
926
+ if (prop === "border-top-style") {
927
+ const allSame = styles["border-top-style"] === styles["border-right-style"] && styles["border-top-style"] === styles["border-bottom-style"] && styles["border-top-style"] === styles["border-left-style"];
928
+ if (allSame) {
929
+ const styleMap = {
930
+ none: "border-none",
931
+ solid: "border-solid",
932
+ dashed: "border-dashed",
933
+ dotted: "border-dotted",
934
+ double: "border-double"
935
+ };
936
+ classes.push(styleMap[value] || `[border-style:${value}]`);
937
+ } else {
938
+ classes.push(`[border-top-style:${styles["border-top-style"]}]`);
939
+ classes.push(`[border-right-style:${styles["border-right-style"]}]`);
940
+ classes.push(`[border-bottom-style:${styles["border-bottom-style"]}]`);
941
+ classes.push(`[border-left-style:${styles["border-left-style"]}]`);
942
+ }
943
+ }
944
+ } else {
945
+ classes.push(`[${prop}:${value}]`);
1055
946
  }
1056
- if (node instanceof SVGElement) {
1057
- const fillColor = parseVisibleColor(computed.getPropertyValue("fill"), currentTextColor) ?? parseVisibleColor(node.getAttribute("fill") ?? "", currentTextColor);
1058
- const strokeColor = parseVisibleColor(computed.getPropertyValue("stroke"), currentTextColor) ?? parseVisibleColor(node.getAttribute("stroke") ?? "", currentTextColor);
1059
- addUniqueColor(uniqueColors, fillColor);
1060
- addUniqueColor(uniqueColors, strokeColor);
947
+ continue;
948
+ }
949
+ if (prop === "outline-color") {
950
+ const colorValue = parseColorValue(value);
951
+ classes.push(colorToTailwind("outlineColor", colorValue));
952
+ continue;
953
+ }
954
+ if (prop === "box-shadow") {
955
+ const trimmed = value.trim();
956
+ if (trimmed === "none" || trimmed === "") {
957
+ classes.push("shadow-none");
958
+ } else {
959
+ const normalized = normalizeShadowForComparison(trimmed);
960
+ const preset = tailwindShadowClassValues.find(
961
+ (entry) => normalizeShadowForComparison(entry.css) === normalized
962
+ );
963
+ if (preset) classes.push(preset.className);
964
+ else classes.push(`shadow-[${normalizeTailwindArbitraryValue(value)}]`);
1061
965
  }
966
+ continue;
1062
967
  }
1063
- for (const child of node.children) {
1064
- queue.push(child);
968
+ if (prop === "font-size") {
969
+ classes.push(`text-[${value}]`);
970
+ continue;
971
+ }
972
+ if (prop === "font-weight") {
973
+ const weightMap = {
974
+ "100": "font-thin",
975
+ "200": "font-extralight",
976
+ "300": "font-light",
977
+ "400": "font-normal",
978
+ "500": "font-medium",
979
+ "600": "font-semibold",
980
+ "700": "font-bold",
981
+ "800": "font-extrabold",
982
+ "900": "font-black"
983
+ };
984
+ classes.push(weightMap[value] || `font-[${value}]`);
985
+ continue;
986
+ }
987
+ if (prop === "line-height") {
988
+ classes.push(`leading-[${value}]`);
989
+ continue;
990
+ }
991
+ if (prop === "letter-spacing") {
992
+ classes.push(`tracking-[${value}]`);
993
+ continue;
994
+ }
995
+ if (prop === "text-align") {
996
+ const alignMap = {
997
+ left: "text-left",
998
+ center: "text-center",
999
+ right: "text-right",
1000
+ justify: "text-justify"
1001
+ };
1002
+ if (alignMap[value]) classes.push(alignMap[value]);
1003
+ continue;
1004
+ }
1005
+ if (prop === "font-family") {
1006
+ classes.push(`font-[${value.replace(/\s+/g, "_")}]`);
1007
+ continue;
1065
1008
  }
1066
1009
  }
1067
- return Array.from(uniqueColors.values());
1068
- }
1069
- function getAllComputedStyles(element) {
1070
- const { spacing, borderRadius, flex } = getComputedStyles(element);
1071
- return {
1072
- spacing,
1073
- borderRadius,
1074
- border: getComputedBorderStyles(element),
1075
- flex,
1076
- sizing: getComputedSizing(element),
1077
- color: getComputedColorStyles(element),
1078
- boxShadow: getComputedBoxShadow(element),
1079
- typography: getComputedTypography(element)
1080
- };
1010
+ return classes.join(" ");
1081
1011
  }
1082
- var colorPropertyToCSSMap = {
1083
- backgroundColor: "background-color",
1084
- color: "color",
1085
- borderColor: "border-color",
1086
- outlineColor: "outline-color"
1012
+ var propertyToCSSMap = {
1013
+ paddingTop: "padding-top",
1014
+ paddingRight: "padding-right",
1015
+ paddingBottom: "padding-bottom",
1016
+ paddingLeft: "padding-left",
1017
+ marginTop: "margin-top",
1018
+ marginRight: "margin-right",
1019
+ marginBottom: "margin-bottom",
1020
+ marginLeft: "margin-left",
1021
+ gap: "gap"
1087
1022
  };
1088
- var colorTailwindPrefixMap = {
1089
- backgroundColor: "bg",
1090
- color: "text",
1091
- borderColor: "border",
1092
- outlineColor: "outline"
1023
+ var borderRadiusPropertyToCSSMap = {
1024
+ borderTopLeftRadius: "border-top-left-radius",
1025
+ borderTopRightRadius: "border-top-right-radius",
1026
+ borderBottomRightRadius: "border-bottom-right-radius",
1027
+ borderBottomLeftRadius: "border-bottom-left-radius"
1028
+ };
1029
+ var borderPropertyToCSSMap = {
1030
+ borderTopStyle: "border-top-style",
1031
+ borderTopWidth: "border-top-width",
1032
+ borderRightStyle: "border-right-style",
1033
+ borderRightWidth: "border-right-width",
1034
+ borderBottomStyle: "border-bottom-style",
1035
+ borderBottomWidth: "border-bottom-width",
1036
+ borderLeftStyle: "border-left-style",
1037
+ borderLeftWidth: "border-left-width"
1038
+ };
1039
+ var flexPropertyToCSSMap = {
1040
+ display: "display",
1041
+ flexDirection: "flex-direction",
1042
+ justifyContent: "justify-content",
1043
+ alignItems: "align-items"
1044
+ };
1045
+ var sizingPropertyToCSSMap = {
1046
+ width: "width",
1047
+ height: "height"
1048
+ };
1049
+ var typographyPropertyToCSSMap = {
1050
+ fontFamily: "font-family",
1051
+ fontWeight: "font-weight",
1052
+ fontSize: "font-size",
1053
+ lineHeight: "line-height",
1054
+ letterSpacing: "letter-spacing",
1055
+ textAlign: "text-align",
1056
+ textVerticalAlign: "align-items"
1093
1057
  };
1094
- function colorToTailwind(property, colorValue) {
1095
- const prefix = colorTailwindPrefixMap[property];
1096
- if (colorValue.alpha === 100) {
1097
- return `${prefix}-[#${colorValue.hex}]`;
1098
- }
1099
- return `${prefix}-[#${colorValue.hex}]/${colorValue.alpha}`;
1058
+ var TEXT_ELEMENT_TAGS = /* @__PURE__ */ new Set([
1059
+ "p",
1060
+ "h1",
1061
+ "h2",
1062
+ "h3",
1063
+ "h4",
1064
+ "h5",
1065
+ "h6",
1066
+ "span",
1067
+ "label",
1068
+ "a",
1069
+ "strong",
1070
+ "em",
1071
+ "small",
1072
+ "blockquote",
1073
+ "li",
1074
+ "td",
1075
+ "th",
1076
+ "caption",
1077
+ "figcaption",
1078
+ "legend",
1079
+ "dt",
1080
+ "dd",
1081
+ "abbr",
1082
+ "cite",
1083
+ "code",
1084
+ "pre"
1085
+ ]);
1086
+ function hasDirectNonWhitespaceText(element) {
1087
+ return Array.from(element.childNodes).some(
1088
+ (node) => node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim())
1089
+ );
1100
1090
  }
1101
- function getElementInfo(element) {
1102
- const computed = window.getComputedStyle(element);
1103
- const parentElement = element === document.body ? null : element.parentElement;
1104
- const isFlexContainer2 = computed.display === "flex" || computed.display === "inline-flex";
1105
- let isFlexItem = false;
1106
- if (parentElement) {
1107
- const parentComputed = window.getComputedStyle(parentElement);
1108
- isFlexItem = parentComputed.display === "flex" || parentComputed.display === "inline-flex";
1091
+ function isTextElement2(element) {
1092
+ const tagName = element.tagName.toLowerCase();
1093
+ if (TEXT_ELEMENT_TAGS.has(tagName)) {
1094
+ return true;
1109
1095
  }
1110
- return {
1111
- tagName: element.tagName.toLowerCase(),
1112
- id: element.id || null,
1113
- classList: Array.from(element.classList),
1114
- isFlexContainer: isFlexContainer2,
1115
- isFlexItem,
1116
- isTextElement: isTextElement2(element),
1117
- parentElement,
1118
- hasChildren: element.children.length > 0
1119
- };
1120
- }
1121
- function isFitSizing(element, dimension) {
1122
- const computed = window.getComputedStyle(element);
1123
- const inlineValue = element.style[dimension];
1124
- if (inlineValue === "auto") return true;
1125
- const computedValue = computed[dimension];
1126
- if (!inlineValue) {
1127
- const parent = element.parentElement;
1128
- if (parent) {
1129
- const parentComputed = window.getComputedStyle(parent);
1130
- if (parentComputed.display === "flex" || parentComputed.display === "inline-flex") {
1131
- const flexBasis = computed.flexBasis;
1132
- const flexGrow = computed.flexGrow;
1133
- if (flexBasis === "auto" && flexGrow === "0") {
1134
- return true;
1135
- }
1136
- }
1137
- }
1138
- if (dimension === "width") {
1139
- if (computed.display === "block" && !inlineValue) {
1140
- return false;
1141
- }
1142
- if (computed.display === "inline-block" || computed.display === "inline-flex" || computed.display === "inline") {
1143
- return true;
1144
- }
1145
- }
1146
- if (dimension === "height") {
1147
- return !inlineValue;
1148
- }
1096
+ if (hasDirectNonWhitespaceText(element)) {
1097
+ return true;
1149
1098
  }
1150
- if (computedValue.includes("fit-content") || computedValue.includes("max-content")) {
1099
+ if (element.children.length === 0 && element.textContent?.trim()) {
1151
1100
  return true;
1152
1101
  }
1153
1102
  return false;
1154
1103
  }
1155
- function getDimensionDisplay(element) {
1156
- const width = Math.round(element.offsetWidth);
1157
- const height = Math.round(element.offsetHeight);
1158
- const widthIsFit = isFitSizing(element, "width");
1159
- const heightIsFit = isFitSizing(element, "height");
1104
+ function getComputedTypography(element) {
1105
+ const computed = window.getComputedStyle(element);
1106
+ let textVerticalAlign = "flex-start";
1107
+ if (computed.display === "flex" || computed.display === "inline-flex") {
1108
+ const alignItems = computed.alignItems;
1109
+ if (alignItems === "center") textVerticalAlign = "center";
1110
+ else if (alignItems === "flex-end" || alignItems === "end") textVerticalAlign = "flex-end";
1111
+ }
1112
+ const lineHeight = computed.lineHeight === "normal" ? { numericValue: parseFloat(computed.fontSize) * 1.2, unit: "px", raw: `${Math.round(parseFloat(computed.fontSize) * 1.2)}px` } : parsePropertyValue(computed.lineHeight);
1113
+ const fontSize = parseFloat(computed.fontSize);
1114
+ let letterSpacing;
1115
+ if (computed.letterSpacing === "normal") {
1116
+ letterSpacing = { numericValue: 0, unit: "em", raw: "0em" };
1117
+ } else {
1118
+ const parsed = parsePropertyValue(computed.letterSpacing);
1119
+ if (parsed.unit === "px" && fontSize > 0) {
1120
+ const emValue = Math.round(parsed.numericValue / fontSize * 100) / 100;
1121
+ letterSpacing = { numericValue: emValue, unit: "em", raw: `${emValue}em` };
1122
+ } else {
1123
+ letterSpacing = parsed;
1124
+ }
1125
+ }
1160
1126
  return {
1161
- width: widthIsFit ? `Fit ${width}` : `${width}`,
1162
- height: heightIsFit ? `Fit ${height}` : `${height}`
1127
+ fontFamily: computed.fontFamily,
1128
+ fontWeight: computed.fontWeight,
1129
+ fontSize: parsePropertyValue(computed.fontSize),
1130
+ lineHeight,
1131
+ letterSpacing,
1132
+ textAlign: computed.textAlign,
1133
+ textVerticalAlign
1163
1134
  };
1164
1135
  }
1165
- function calculateParentMeasurements(element, container) {
1166
- const parent = container ?? element.parentElement;
1167
- if (!parent) return [];
1168
- const elementRect = element.getBoundingClientRect();
1169
- const parentRect = parent.getBoundingClientRect();
1170
- const paddingBoxLeft = parentRect.left + parent.clientLeft;
1171
- const paddingBoxTop = parentRect.top + parent.clientTop;
1172
- const paddingBoxRight = parentRect.left + parent.clientLeft + parent.clientWidth;
1173
- const paddingBoxBottom = parentRect.top + parent.clientTop + parent.clientHeight;
1174
- let parentInnerLeft;
1175
- let parentInnerTop;
1176
- let parentInnerRight;
1177
- let parentInnerBottom;
1178
- if (container) {
1179
- parentInnerLeft = paddingBoxLeft;
1180
- parentInnerTop = paddingBoxTop;
1181
- parentInnerRight = paddingBoxRight;
1182
- parentInnerBottom = paddingBoxBottom;
1183
- } else {
1184
- const parentStyles = window.getComputedStyle(parent);
1185
- parentInnerLeft = paddingBoxLeft + (parseFloat(parentStyles.paddingLeft) || 0);
1186
- parentInnerTop = paddingBoxTop + (parseFloat(parentStyles.paddingTop) || 0);
1187
- parentInnerRight = paddingBoxRight - (parseFloat(parentStyles.paddingRight) || 0);
1188
- parentInnerBottom = paddingBoxBottom - (parseFloat(parentStyles.paddingBottom) || 0);
1189
- }
1190
- const zoom = getZoomScale();
1191
- const measurements = [];
1192
- const topDistance = Math.round((elementRect.top - parentInnerTop) / zoom);
1193
- if (topDistance > 0) {
1194
- const midX = elementRect.left + elementRect.width / 2;
1195
- measurements.push({
1196
- direction: "vertical",
1197
- x1: midX,
1198
- y1: parentInnerTop,
1199
- x2: midX,
1200
- y2: elementRect.top,
1201
- distance: topDistance,
1202
- labelPosition: { x: midX, y: (parentInnerTop + elementRect.top) / 2 }
1203
- });
1204
- }
1205
- const bottomDistance = Math.round((parentInnerBottom - elementRect.bottom) / zoom);
1206
- if (bottomDistance > 0) {
1207
- const midX = elementRect.left + elementRect.width / 2;
1208
- measurements.push({
1209
- direction: "vertical",
1210
- x1: midX,
1211
- y1: elementRect.bottom,
1212
- x2: midX,
1213
- y2: parentInnerBottom,
1214
- distance: bottomDistance,
1215
- labelPosition: { x: midX, y: (elementRect.bottom + parentInnerBottom) / 2 }
1216
- });
1217
- }
1218
- const leftDistance = Math.round((elementRect.left - parentInnerLeft) / zoom);
1219
- if (leftDistance > 0) {
1220
- const midY = elementRect.top + elementRect.height / 2;
1221
- measurements.push({
1222
- direction: "horizontal",
1223
- x1: parentInnerLeft,
1224
- y1: midY,
1225
- x2: elementRect.left,
1226
- y2: midY,
1227
- distance: leftDistance,
1228
- labelPosition: { x: (parentInnerLeft + elementRect.left) / 2, y: midY }
1229
- });
1230
- }
1231
- const rightDistance = Math.round((parentInnerRight - elementRect.right) / zoom);
1232
- if (rightDistance > 0) {
1233
- const midY = elementRect.top + elementRect.height / 2;
1234
- measurements.push({
1235
- direction: "horizontal",
1236
- x1: elementRect.right,
1237
- y1: midY,
1238
- x2: parentInnerRight,
1239
- y2: midY,
1240
- distance: rightDistance,
1241
- labelPosition: { x: (elementRect.right + parentInnerRight) / 2, y: midY }
1242
- });
1136
+ function detectSizingMode(element, dimension) {
1137
+ const computed = window.getComputedStyle(element);
1138
+ const inlineValue = element.style[dimension];
1139
+ if (inlineValue === "100%") return "fill";
1140
+ if (inlineValue === "auto" || inlineValue === "fit-content") return "fit";
1141
+ const computedValue = computed[dimension];
1142
+ if (computedValue === "100%") return "fill";
1143
+ if (computedValue === "auto" || computedValue === "fit-content" || computedValue === "max-content") {
1144
+ return "fit";
1243
1145
  }
1244
- return measurements;
1245
- }
1246
- function calculateElementMeasurements(from, to) {
1247
- const fromRect = from.getBoundingClientRect();
1248
- const toRect = to.getBoundingClientRect();
1249
- const zoom = getZoomScale();
1250
- const measurements = [];
1251
- const horizontalOverlap = fromRect.left < toRect.right && fromRect.right > toRect.left;
1252
- const verticalOverlap = fromRect.top < toRect.bottom && fromRect.bottom > toRect.top;
1253
- if (verticalOverlap) {
1254
- const overlapTop = Math.max(fromRect.top, toRect.top);
1255
- const overlapBottom = Math.min(fromRect.bottom, toRect.bottom);
1256
- const midY = (overlapTop + overlapBottom) / 2;
1257
- if (fromRect.right <= toRect.left) {
1258
- const distance = Math.round((toRect.left - fromRect.right) / zoom);
1259
- measurements.push({
1260
- direction: "horizontal",
1261
- x1: fromRect.right,
1262
- y1: midY,
1263
- x2: toRect.left,
1264
- y2: midY,
1265
- distance,
1266
- labelPosition: { x: (fromRect.right + toRect.left) / 2, y: midY }
1267
- });
1268
- } else if (fromRect.left >= toRect.right) {
1269
- const distance = Math.round((fromRect.left - toRect.right) / zoom);
1270
- measurements.push({
1271
- direction: "horizontal",
1272
- x1: toRect.right,
1273
- y1: midY,
1274
- x2: fromRect.left,
1275
- y2: midY,
1276
- distance,
1277
- labelPosition: { x: (toRect.right + fromRect.left) / 2, y: midY }
1278
- });
1146
+ const parent = element.parentElement;
1147
+ if (parent) {
1148
+ const parentComputed = window.getComputedStyle(parent);
1149
+ if (parentComputed.display === "flex" || parentComputed.display === "inline-flex") {
1150
+ const flexGrow = computed.flexGrow;
1151
+ if (flexGrow !== "0") {
1152
+ return "fill";
1153
+ }
1279
1154
  }
1280
1155
  }
1281
- if (horizontalOverlap) {
1282
- const overlapLeft = Math.max(fromRect.left, toRect.left);
1283
- const overlapRight = Math.min(fromRect.right, toRect.right);
1284
- const midX = (overlapLeft + overlapRight) / 2;
1285
- if (fromRect.bottom <= toRect.top) {
1286
- const distance = Math.round((toRect.top - fromRect.bottom) / zoom);
1287
- measurements.push({
1288
- direction: "vertical",
1289
- x1: midX,
1290
- y1: fromRect.bottom,
1291
- x2: midX,
1292
- y2: toRect.top,
1293
- distance,
1294
- labelPosition: { x: midX, y: (fromRect.bottom + toRect.top) / 2 }
1295
- });
1296
- } else if (fromRect.top >= toRect.bottom) {
1297
- const distance = Math.round((fromRect.top - toRect.bottom) / zoom);
1298
- measurements.push({
1299
- direction: "vertical",
1300
- x1: midX,
1301
- y1: toRect.bottom,
1302
- x2: midX,
1303
- y2: fromRect.top,
1304
- distance,
1305
- labelPosition: { x: midX, y: (toRect.bottom + fromRect.top) / 2 }
1306
- });
1156
+ if (dimension === "width") {
1157
+ if (computed.display === "block" && !inlineValue) {
1158
+ return "fill";
1307
1159
  }
1308
- }
1309
- if (!horizontalOverlap && !verticalOverlap) {
1310
- const fromCenterX = fromRect.left + fromRect.width / 2;
1311
- const fromCenterY = fromRect.top + fromRect.height / 2;
1312
- const toCenterX = toRect.left + toRect.width / 2;
1313
- const toCenterY = toRect.top + toRect.height / 2;
1314
- const hDistance = toCenterX > fromCenterX ? Math.round((toRect.left - fromRect.right) / zoom) : Math.round((fromRect.left - toRect.right) / zoom);
1315
- if (hDistance > 0) {
1316
- const startX = toCenterX > fromCenterX ? fromRect.right : fromRect.left;
1317
- const endX = toCenterX > fromCenterX ? toRect.left : toRect.right;
1318
- const y = (fromCenterY + toCenterY) / 2;
1319
- measurements.push({
1320
- direction: "horizontal",
1321
- x1: startX,
1322
- y1: y,
1323
- x2: endX,
1324
- y2: y,
1325
- distance: hDistance,
1326
- labelPosition: { x: (startX + endX) / 2, y }
1327
- });
1160
+ if (computed.display === "inline-block" || computed.display === "inline-flex" || computed.display === "inline") {
1161
+ return "fit";
1328
1162
  }
1329
- const vDistance = toCenterY > fromCenterY ? Math.round((toRect.top - fromRect.bottom) / zoom) : Math.round((fromRect.top - toRect.bottom) / zoom);
1330
- if (vDistance > 0) {
1331
- const x = (fromCenterX + toCenterX) / 2;
1332
- const startY = toCenterY > fromCenterY ? fromRect.bottom : fromRect.top;
1333
- const endY = toCenterY > fromCenterY ? toRect.top : toRect.bottom;
1334
- measurements.push({
1335
- direction: "vertical",
1336
- x1: x,
1337
- y1: startY,
1338
- x2: x,
1339
- y2: endY,
1340
- distance: vDistance,
1341
- labelPosition: { x, y: (startY + endY) / 2 }
1342
- });
1163
+ }
1164
+ if (dimension === "height") {
1165
+ if (!inlineValue) {
1166
+ return "fit";
1343
1167
  }
1344
1168
  }
1345
- return measurements;
1169
+ return "fixed";
1346
1170
  }
1347
- var GUIDELINE_PROXIMITY = 80;
1348
- function calculateGuidelineMeasurements(element, guidelines, mousePosition) {
1349
- if (guidelines.length === 0) return [];
1350
- const snap = getCanvasSnapshot();
1351
- const zoom = snap.active ? snap.zoom : 1;
1352
- const rect = element.getBoundingClientRect();
1353
- const measurements = [];
1354
- for (const g of guidelines) {
1355
- let viewportPos;
1356
- if (snap.active) {
1357
- const pan = g.orientation === "horizontal" ? snap.panY : snap.panX;
1358
- const bo = g.orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
1359
- viewportPos = bo + (g.position - bo + pan) * zoom;
1360
- } else {
1361
- const scroll = g.orientation === "horizontal" ? window.scrollY : window.scrollX;
1362
- viewportPos = g.position - scroll;
1171
+ function getSizingValue(element, dimension) {
1172
+ const mode = detectSizingMode(element, dimension);
1173
+ const numericValue = Math.round(dimension === "width" ? element.offsetWidth : element.offsetHeight);
1174
+ return {
1175
+ mode,
1176
+ value: {
1177
+ numericValue,
1178
+ unit: "px",
1179
+ raw: `${numericValue}px`
1363
1180
  }
1364
- if (g.orientation === "horizontal") {
1365
- const midX = rect.left + rect.width / 2;
1366
- if (mousePosition && Math.abs(mousePosition.y - viewportPos) > GUIDELINE_PROXIMITY) continue;
1367
- if (viewportPos < rect.top) {
1368
- const distance = Math.round((rect.top - viewportPos) / zoom);
1369
- if (distance > 0) {
1370
- measurements.push({
1371
- direction: "vertical",
1372
- x1: midX,
1373
- y1: viewportPos,
1374
- x2: midX,
1375
- y2: rect.top,
1376
- distance,
1377
- labelPosition: { x: midX, y: (viewportPos + rect.top) / 2 }
1378
- });
1379
- }
1380
- } else if (viewportPos > rect.bottom) {
1381
- const distance = Math.round((viewportPos - rect.bottom) / zoom);
1382
- if (distance > 0) {
1383
- measurements.push({
1384
- direction: "vertical",
1385
- x1: midX,
1386
- y1: rect.bottom,
1387
- x2: midX,
1388
- y2: viewportPos,
1389
- distance,
1390
- labelPosition: { x: midX, y: (rect.bottom + viewportPos) / 2 }
1391
- });
1392
- }
1393
- }
1394
- } else {
1395
- const midY = rect.top + rect.height / 2;
1396
- if (mousePosition && Math.abs(mousePosition.x - viewportPos) > GUIDELINE_PROXIMITY) continue;
1397
- if (viewportPos < rect.left) {
1398
- const distance = Math.round((rect.left - viewportPos) / zoom);
1399
- if (distance > 0) {
1400
- measurements.push({
1401
- direction: "horizontal",
1402
- x1: viewportPos,
1403
- y1: midY,
1404
- x2: rect.left,
1405
- y2: midY,
1406
- distance,
1407
- labelPosition: { x: (viewportPos + rect.left) / 2, y: midY }
1408
- });
1409
- }
1410
- } else if (viewportPos > rect.right) {
1411
- const distance = Math.round((viewportPos - rect.right) / zoom);
1412
- if (distance > 0) {
1413
- measurements.push({
1414
- direction: "horizontal",
1415
- x1: rect.right,
1416
- y1: midY,
1417
- x2: viewportPos,
1418
- y2: midY,
1419
- distance,
1420
- labelPosition: { x: (rect.right + viewportPos) / 2, y: midY }
1421
- });
1422
- }
1181
+ };
1182
+ }
1183
+ function getComputedSizing(element) {
1184
+ return {
1185
+ width: getSizingValue(element, "width"),
1186
+ height: getSizingValue(element, "height")
1187
+ };
1188
+ }
1189
+ function sizingValueToCSS(sizing) {
1190
+ switch (sizing.mode) {
1191
+ case "fill":
1192
+ return "100%";
1193
+ case "fit":
1194
+ return "fit-content";
1195
+ case "fixed":
1196
+ return `${sizing.value.numericValue}${sizing.value.unit}`;
1197
+ }
1198
+ }
1199
+ function sizingToTailwind(dimension, sizing) {
1200
+ const prefix = dimension === "width" ? "w" : "h";
1201
+ switch (sizing.mode) {
1202
+ case "fill":
1203
+ return `${prefix}-full`;
1204
+ case "fit":
1205
+ return `${prefix}-fit`;
1206
+ case "fixed":
1207
+ return `${prefix}-[${sizing.value.numericValue}${sizing.value.unit}]`;
1208
+ }
1209
+ }
1210
+ function parseHexColor(hex) {
1211
+ const raw = hex;
1212
+ let h = hex.replace("#", "");
1213
+ if (h.length === 3) {
1214
+ h = h.split("").map((c) => c + c).join("");
1215
+ }
1216
+ if (h.length === 8) {
1217
+ const alpha = Math.round(parseInt(h.slice(6, 8), 16) / 255 * 100);
1218
+ return { hex: h.slice(0, 6).toUpperCase(), alpha, raw };
1219
+ }
1220
+ return { hex: h.toUpperCase(), alpha: 100, raw };
1221
+ }
1222
+ function parseRgbChannel(value) {
1223
+ const token = value.trim();
1224
+ if (!token) return null;
1225
+ if (token.endsWith("%")) {
1226
+ const numeric2 = parseFloat(token.slice(0, -1));
1227
+ if (!Number.isFinite(numeric2)) return null;
1228
+ return Math.round(Math.max(0, Math.min(100, numeric2)) / 100 * 255);
1229
+ }
1230
+ const numeric = parseFloat(token);
1231
+ if (!Number.isFinite(numeric)) return null;
1232
+ return Math.round(Math.max(0, Math.min(255, numeric)));
1233
+ }
1234
+ function parseRgbAlpha(value) {
1235
+ if (value == null || value.trim() === "") return 1;
1236
+ const token = value.trim();
1237
+ if (token.endsWith("%")) {
1238
+ const numeric2 = parseFloat(token.slice(0, -1));
1239
+ if (!Number.isFinite(numeric2)) return null;
1240
+ return Math.max(0, Math.min(100, numeric2)) / 100;
1241
+ }
1242
+ const numeric = parseFloat(token);
1243
+ if (!Number.isFinite(numeric)) return null;
1244
+ return Math.max(0, Math.min(1, numeric));
1245
+ }
1246
+ function parseRgbaColor(rgba) {
1247
+ const raw = rgba.trim();
1248
+ const fnMatch = raw.match(/^rgba?\((.*)\)$/i);
1249
+ if (!fnMatch) {
1250
+ return { hex: "000000", alpha: 100, raw: rgba };
1251
+ }
1252
+ const body = fnMatch[1].trim();
1253
+ let channelTokens = null;
1254
+ let alphaToken;
1255
+ const commaParts = body.split(",").map((part) => part.trim()).filter(Boolean);
1256
+ if (commaParts.length === 3 || commaParts.length === 4) {
1257
+ channelTokens = [commaParts[0], commaParts[1], commaParts[2]];
1258
+ alphaToken = commaParts[3];
1259
+ } else {
1260
+ const slashParts = body.split("/");
1261
+ if (slashParts.length === 1 || slashParts.length === 2) {
1262
+ const channels = slashParts[0].trim().split(/\s+/).filter(Boolean);
1263
+ if (channels.length === 3) {
1264
+ channelTokens = [channels[0], channels[1], channels[2]];
1265
+ alphaToken = slashParts[1]?.trim();
1423
1266
  }
1424
1267
  }
1425
1268
  }
1426
- return measurements;
1269
+ if (!channelTokens) {
1270
+ return { hex: "000000", alpha: 100, raw: rgba };
1271
+ }
1272
+ const r = parseRgbChannel(channelTokens[0]);
1273
+ const g = parseRgbChannel(channelTokens[1]);
1274
+ const b = parseRgbChannel(channelTokens[2]);
1275
+ const a = parseRgbAlpha(alphaToken);
1276
+ if (r === null || g === null || b === null || a === null) {
1277
+ return { hex: "000000", alpha: 100, raw: rgba };
1278
+ }
1279
+ const hex = [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("").toUpperCase();
1280
+ const alpha = Math.round(a * 100);
1281
+ return { hex, alpha, raw: rgba };
1282
+ }
1283
+ function parseNamedColor(name) {
1284
+ const ctx = document.createElement("canvas").getContext("2d");
1285
+ if (!ctx) {
1286
+ return { hex: "000000", alpha: 100, raw: name };
1287
+ }
1288
+ ctx.fillStyle = name;
1289
+ const computed = ctx.fillStyle;
1290
+ if (computed.startsWith("#")) {
1291
+ return parseHexColor(computed);
1292
+ }
1293
+ return parseRgbaColor(computed);
1427
1294
  }
1428
- function isFlexContainer(element) {
1429
- const computed = window.getComputedStyle(element);
1430
- return computed.display === "flex" || computed.display === "inline-flex";
1295
+ function parseColorValue(cssValue) {
1296
+ const raw = cssValue.trim();
1297
+ if (raw === "transparent") {
1298
+ return { hex: "000000", alpha: 0, raw };
1299
+ }
1300
+ if (raw.startsWith("#")) {
1301
+ return parseHexColor(raw);
1302
+ }
1303
+ if (raw.startsWith("rgb")) {
1304
+ return parseRgbaColor(raw);
1305
+ }
1306
+ return parseNamedColor(raw);
1431
1307
  }
1432
- function getFlexDirection(element) {
1433
- const computed = window.getComputedStyle(element);
1434
- return computed.flexDirection;
1308
+ var TRANSPARENT_COLOR = { hex: "000000", alpha: 0, raw: "transparent" };
1309
+ function isVisibleBorderSide(side) {
1310
+ return side.style !== "none" && side.style !== "hidden" && parseFloat(side.width) > 0;
1435
1311
  }
1436
- function isInFlowChild(el) {
1437
- const cs = window.getComputedStyle(el);
1438
- return cs.display !== "none" && cs.position !== "absolute" && cs.position !== "fixed";
1312
+ function hasVisibleOutline(computed) {
1313
+ return computed.outlineStyle !== "none" && parseFloat(computed.outlineWidth) > 0;
1439
1314
  }
1440
- function detectChildrenDirection(container, exclude) {
1441
- const computed = window.getComputedStyle(container);
1442
- if (computed.display === "flex" || computed.display === "inline-flex") {
1443
- const dir = computed.flexDirection;
1444
- return {
1445
- axis: dir === "row" || dir === "row-reverse" ? "horizontal" : "vertical",
1446
- reversed: dir === "row-reverse" || dir === "column-reverse"
1447
- };
1315
+ function parseVisibleColor(value, fallbackCurrentColor) {
1316
+ const raw = value.trim();
1317
+ const lowered = raw.toLowerCase();
1318
+ if (!raw || lowered === "none" || lowered === "transparent") {
1319
+ return null;
1448
1320
  }
1449
- const visible = [];
1450
- for (const c of container.children) {
1451
- if (!(c instanceof HTMLElement) || c === exclude) continue;
1452
- if (!isInFlowChild(c)) continue;
1453
- visible.push(c);
1454
- if (visible.length === 2) break;
1321
+ const resolved = /^currentcolor$/i.test(raw) ? fallbackCurrentColor ?? raw : raw;
1322
+ const parsed = parseColorValue(resolved);
1323
+ if (parsed.alpha <= 0) {
1324
+ return null;
1455
1325
  }
1456
- if (visible.length < 2) return { axis: "vertical", reversed: false };
1457
- const first = visible[0].getBoundingClientRect();
1458
- const second = visible[1].getBoundingClientRect();
1459
- const yOverlap = first.bottom - 2 > second.top && second.bottom - 2 > first.top;
1460
- if (yOverlap) {
1461
- return { axis: "horizontal", reversed: second.right < first.left };
1326
+ return parsed;
1327
+ }
1328
+ function addUniqueColor(colors, color) {
1329
+ if (!color) return;
1330
+ colors.set(`${color.hex}:${color.alpha}`, color);
1331
+ }
1332
+ function isTextRenderingFormControl(element) {
1333
+ if (element instanceof HTMLTextAreaElement) return true;
1334
+ if (element instanceof HTMLSelectElement) return true;
1335
+ if (element instanceof HTMLButtonElement) return true;
1336
+ if (element instanceof HTMLInputElement) {
1337
+ const textlessInputTypes = /* @__PURE__ */ new Set([
1338
+ "hidden",
1339
+ "checkbox",
1340
+ "radio",
1341
+ "range",
1342
+ "color",
1343
+ "file",
1344
+ "image"
1345
+ ]);
1346
+ return !textlessInputTypes.has(element.type.toLowerCase());
1462
1347
  }
1463
- return { axis: "vertical", reversed: second.bottom < first.top };
1348
+ return false;
1464
1349
  }
1465
- function computeIntendedIndex(parent, draggedElement) {
1466
- const { axis } = detectChildrenDirection(parent, draggedElement);
1467
- const isHorizontal = axis === "horizontal";
1468
- const draggedRect = draggedElement.getBoundingClientRect();
1469
- const intendedCenter = isHorizontal ? draggedRect.left + draggedRect.width / 2 : draggedRect.top + draggedRect.height / 2;
1470
- const siblings = [];
1471
- for (const c of parent.children) {
1472
- if (!(c instanceof HTMLElement) || c === draggedElement) continue;
1473
- if (!isInFlowChild(c)) continue;
1474
- siblings.push(c);
1350
+ function hasRenderableTextNode(element) {
1351
+ if (element.isContentEditable) return true;
1352
+ if (isTextRenderingFormControl(element)) return true;
1353
+ if (!element.textContent?.trim()) return false;
1354
+ if (hasDirectNonWhitespaceText(element)) return true;
1355
+ const tagName = element.tagName.toLowerCase();
1356
+ return TEXT_ELEMENT_TAGS.has(tagName) || element.children.length === 0;
1357
+ }
1358
+ function getComputedBoxShadow(element) {
1359
+ const computed = window.getComputedStyle(element);
1360
+ const value = computed.boxShadow.trim();
1361
+ return value || "none";
1362
+ }
1363
+ function getComputedColorStyles(element) {
1364
+ const computed = window.getComputedStyle(element);
1365
+ const borderSides = [
1366
+ { style: computed.borderTopStyle, width: computed.borderTopWidth, color: computed.borderTopColor },
1367
+ { style: computed.borderRightStyle, width: computed.borderRightWidth, color: computed.borderRightColor },
1368
+ { style: computed.borderBottomStyle, width: computed.borderBottomWidth, color: computed.borderBottomColor },
1369
+ { style: computed.borderLeftStyle, width: computed.borderLeftWidth, color: computed.borderLeftColor }
1370
+ ];
1371
+ const visibleBorderSide = borderSides.find((side) => isVisibleBorderSide(side));
1372
+ const hasBorder = Boolean(visibleBorderSide);
1373
+ const hasOutline = hasVisibleOutline(computed);
1374
+ return {
1375
+ backgroundColor: parseColorValue(computed.backgroundColor),
1376
+ color: parseColorValue(computed.color),
1377
+ borderColor: hasBorder && visibleBorderSide ? parseColorValue(visibleBorderSide.color) : TRANSPARENT_COLOR,
1378
+ outlineColor: hasOutline ? parseColorValue(computed.outlineColor) : TRANSPARENT_COLOR
1379
+ };
1380
+ }
1381
+ function getSelectionColors(element) {
1382
+ const uniqueColors = /* @__PURE__ */ new Map();
1383
+ const queue = [element];
1384
+ for (let index = 0; index < queue.length; index++) {
1385
+ const node = queue[index];
1386
+ const computed = window.getComputedStyle(node);
1387
+ if (computed.display === "none") {
1388
+ continue;
1389
+ }
1390
+ const isVisibilityHidden = computed.visibility === "hidden" || computed.visibility === "collapse";
1391
+ const currentTextColor = computed.color;
1392
+ if (!isVisibilityHidden) {
1393
+ addUniqueColor(uniqueColors, parseVisibleColor(computed.backgroundColor));
1394
+ if (node instanceof HTMLElement && hasRenderableTextNode(node)) {
1395
+ addUniqueColor(uniqueColors, parseVisibleColor(currentTextColor));
1396
+ }
1397
+ const borderSides = [
1398
+ { style: computed.borderTopStyle, width: computed.borderTopWidth, color: computed.borderTopColor },
1399
+ { style: computed.borderRightStyle, width: computed.borderRightWidth, color: computed.borderRightColor },
1400
+ { style: computed.borderBottomStyle, width: computed.borderBottomWidth, color: computed.borderBottomColor },
1401
+ { style: computed.borderLeftStyle, width: computed.borderLeftWidth, color: computed.borderLeftColor }
1402
+ ];
1403
+ for (const side of borderSides) {
1404
+ if (!isVisibleBorderSide(side)) continue;
1405
+ addUniqueColor(uniqueColors, parseVisibleColor(side.color, currentTextColor));
1406
+ }
1407
+ if (hasVisibleOutline(computed)) {
1408
+ addUniqueColor(uniqueColors, parseVisibleColor(computed.outlineColor, currentTextColor));
1409
+ }
1410
+ if (node instanceof SVGElement) {
1411
+ const fillColor = parseVisibleColor(computed.getPropertyValue("fill"), currentTextColor) ?? parseVisibleColor(node.getAttribute("fill") ?? "", currentTextColor);
1412
+ const strokeColor = parseVisibleColor(computed.getPropertyValue("stroke"), currentTextColor) ?? parseVisibleColor(node.getAttribute("stroke") ?? "", currentTextColor);
1413
+ addUniqueColor(uniqueColors, fillColor);
1414
+ addUniqueColor(uniqueColors, strokeColor);
1415
+ }
1416
+ }
1417
+ for (const child of node.children) {
1418
+ queue.push(child);
1419
+ }
1475
1420
  }
1476
- if (siblings.length === 0) {
1477
- return { index: 0, siblingBefore: null, siblingAfter: null };
1421
+ return Array.from(uniqueColors.values());
1422
+ }
1423
+ function getAllComputedStyles(element) {
1424
+ const { spacing, borderRadius, flex } = getComputedStyles(element);
1425
+ return {
1426
+ spacing,
1427
+ borderRadius,
1428
+ border: getComputedBorderStyles(element),
1429
+ flex,
1430
+ sizing: getComputedSizing(element),
1431
+ color: getComputedColorStyles(element),
1432
+ boxShadow: getComputedBoxShadow(element),
1433
+ typography: getComputedTypography(element)
1434
+ };
1435
+ }
1436
+ var colorPropertyToCSSMap = {
1437
+ backgroundColor: "background-color",
1438
+ color: "color",
1439
+ borderColor: "border-color",
1440
+ outlineColor: "outline-color"
1441
+ };
1442
+ var colorTailwindPrefixMap = {
1443
+ backgroundColor: "bg",
1444
+ color: "text",
1445
+ borderColor: "border",
1446
+ outlineColor: "outline"
1447
+ };
1448
+ function colorToTailwind(property, colorValue) {
1449
+ const prefix = colorTailwindPrefixMap[property];
1450
+ if (colorValue.alpha === 100) {
1451
+ return `${prefix}-[#${colorValue.hex}]`;
1478
1452
  }
1479
- for (let i = 0; i < siblings.length; i++) {
1480
- const rect = siblings[i].getBoundingClientRect();
1481
- const midpoint = isHorizontal ? rect.left + rect.width / 2 : rect.top + rect.height / 2;
1482
- if (intendedCenter < midpoint) {
1483
- return { index: i, siblingBefore: i > 0 ? siblings[i - 1] : null, siblingAfter: siblings[i] };
1453
+ return `${prefix}-[#${colorValue.hex}]/${colorValue.alpha}`;
1454
+ }
1455
+ function getElementInfo(element) {
1456
+ const computed = window.getComputedStyle(element);
1457
+ const parentElement = element === document.body ? null : element.parentElement;
1458
+ const isFlexContainer2 = computed.display === "flex" || computed.display === "inline-flex";
1459
+ let isFlexItem = false;
1460
+ if (parentElement) {
1461
+ const parentComputed = window.getComputedStyle(parentElement);
1462
+ isFlexItem = parentComputed.display === "flex" || parentComputed.display === "inline-flex";
1463
+ }
1464
+ return {
1465
+ tagName: element.tagName.toLowerCase(),
1466
+ id: element.id || null,
1467
+ classList: Array.from(element.classList),
1468
+ isFlexContainer: isFlexContainer2,
1469
+ isFlexItem,
1470
+ isTextElement: isTextElement2(element),
1471
+ parentElement,
1472
+ hasChildren: element.children.length > 0
1473
+ };
1474
+ }
1475
+ function isFitSizing(element, dimension) {
1476
+ const computed = window.getComputedStyle(element);
1477
+ const inlineValue = element.style[dimension];
1478
+ if (inlineValue === "auto") return true;
1479
+ const computedValue = computed[dimension];
1480
+ if (!inlineValue) {
1481
+ const parent = element.parentElement;
1482
+ if (parent) {
1483
+ const parentComputed = window.getComputedStyle(parent);
1484
+ if (parentComputed.display === "flex" || parentComputed.display === "inline-flex") {
1485
+ const flexBasis = computed.flexBasis;
1486
+ const flexGrow = computed.flexGrow;
1487
+ if (flexBasis === "auto" && flexGrow === "0") {
1488
+ return true;
1489
+ }
1490
+ }
1491
+ }
1492
+ if (dimension === "width") {
1493
+ if (computed.display === "block" && !inlineValue) {
1494
+ return false;
1495
+ }
1496
+ if (computed.display === "inline-block" || computed.display === "inline-flex" || computed.display === "inline") {
1497
+ return true;
1498
+ }
1499
+ }
1500
+ if (dimension === "height") {
1501
+ return !inlineValue;
1484
1502
  }
1485
1503
  }
1486
- return { index: siblings.length, siblingBefore: siblings[siblings.length - 1], siblingAfter: null };
1487
- }
1488
- function htmlChildren(el) {
1489
- return Array.from(el.children).filter(
1490
- (child) => child instanceof HTMLElement
1491
- );
1492
- }
1493
- function findFlexAncestor(element, boundary) {
1494
- let current = element;
1495
- while (current && current !== document.body) {
1496
- const parent = current.parentElement;
1497
- if (!parent) break;
1498
- const display = getComputedStyle(parent).display;
1499
- if (display === "flex" || display === "inline-flex") {
1500
- return { flexParent: parent, child: current };
1501
- }
1502
- if (boundary && parent === boundary) break;
1503
- current = parent;
1504
+ if (computedValue.includes("fit-content") || computedValue.includes("max-content")) {
1505
+ return true;
1504
1506
  }
1505
- return null;
1507
+ return false;
1506
1508
  }
1507
- function computeHoverHighlight(elementUnder, selectedElement) {
1508
- if (!elementUnder || elementUnder === document.body || elementUnder === document.documentElement || elementUnder.closest("[data-direct-edit]") || elementUnder.closest("[data-direct-edit-host]") || elementUnder === selectedElement) {
1509
- return null;
1510
- }
1511
- const boundary = selectedElement?.contains(elementUnder) ? selectedElement : null;
1512
- const ownDisplay = getComputedStyle(elementUnder).display;
1513
- if (ownDisplay === "flex" || ownDisplay === "inline-flex") {
1514
- return { flexContainer: elementUnder, children: htmlChildren(elementUnder) };
1509
+ function getDimensionDisplay(element) {
1510
+ const width = Math.round(element.offsetWidth);
1511
+ const height = Math.round(element.offsetHeight);
1512
+ const widthIsFit = isFitSizing(element, "width");
1513
+ const heightIsFit = isFitSizing(element, "height");
1514
+ return {
1515
+ width: widthIsFit ? `Fit ${width}` : `${width}`,
1516
+ height: heightIsFit ? `Fit ${height}` : `${height}`
1517
+ };
1518
+ }
1519
+ function calculateParentMeasurements(element, container) {
1520
+ const parent = container ?? element.parentElement;
1521
+ if (!parent) return [];
1522
+ const elementRect = element.getBoundingClientRect();
1523
+ const parentRect = parent.getBoundingClientRect();
1524
+ const paddingBoxLeft = parentRect.left + parent.clientLeft;
1525
+ const paddingBoxTop = parentRect.top + parent.clientTop;
1526
+ const paddingBoxRight = parentRect.left + parent.clientLeft + parent.clientWidth;
1527
+ const paddingBoxBottom = parentRect.top + parent.clientTop + parent.clientHeight;
1528
+ let parentInnerLeft;
1529
+ let parentInnerTop;
1530
+ let parentInnerRight;
1531
+ let parentInnerBottom;
1532
+ if (container) {
1533
+ parentInnerLeft = paddingBoxLeft;
1534
+ parentInnerTop = paddingBoxTop;
1535
+ parentInnerRight = paddingBoxRight;
1536
+ parentInnerBottom = paddingBoxBottom;
1537
+ } else {
1538
+ const parentStyles = window.getComputedStyle(parent);
1539
+ parentInnerLeft = paddingBoxLeft + (parseFloat(parentStyles.paddingLeft) || 0);
1540
+ parentInnerTop = paddingBoxTop + (parseFloat(parentStyles.paddingTop) || 0);
1541
+ parentInnerRight = paddingBoxRight - (parseFloat(parentStyles.paddingRight) || 0);
1542
+ parentInnerBottom = paddingBoxBottom - (parseFloat(parentStyles.paddingBottom) || 0);
1515
1543
  }
1516
- const found = findFlexAncestor(elementUnder, boundary);
1517
- if (found) {
1518
- return { flexContainer: found.flexParent, children: htmlChildren(found.flexParent) };
1544
+ const zoom = getZoomScale();
1545
+ const measurements = [];
1546
+ const topDistance = Math.round((elementRect.top - parentInnerTop) / zoom);
1547
+ if (topDistance > 0) {
1548
+ const midX = elementRect.left + elementRect.width / 2;
1549
+ measurements.push({
1550
+ direction: "vertical",
1551
+ x1: midX,
1552
+ y1: parentInnerTop,
1553
+ x2: midX,
1554
+ y2: elementRect.top,
1555
+ distance: topDistance,
1556
+ labelPosition: { x: midX, y: (parentInnerTop + elementRect.top) / 2 }
1557
+ });
1519
1558
  }
1520
- return { flexContainer: elementUnder, children: [] };
1521
- }
1522
- function resolveElementTarget(elementUnder, selectedElement) {
1523
- const boundary = selectedElement?.contains(elementUnder) ? selectedElement : null;
1524
- const found = findFlexAncestor(elementUnder, boundary);
1525
- if (found && found.flexParent === boundary) return elementUnder;
1526
- return found?.child ?? elementUnder;
1527
- }
1528
- function findTextOwnerAtPoint(boundary, clientX, clientY) {
1529
- const doc = document;
1530
- const caretNode = doc.caretPositionFromPoint?.(clientX, clientY)?.offsetNode ?? doc.caretRangeFromPoint?.(clientX, clientY)?.startContainer ?? null;
1531
- if (!caretNode || caretNode.nodeType !== Node.TEXT_NODE) return null;
1532
- const textNode = caretNode;
1533
- if (!(textNode.nodeValue ?? "").trim()) return null;
1534
- const owner = textNode.parentElement;
1535
- if (!owner || !boundary.contains(owner)) return null;
1536
- if (owner.closest("[data-direct-edit]") || owner.closest("[data-direct-edit-host]")) return null;
1537
- const range = document.createRange();
1538
- range.selectNodeContents(textNode);
1539
- const hitsText = Array.from(range.getClientRects()).some(
1540
- (r) => clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom
1541
- );
1542
- range.detach?.();
1543
- return hitsText ? owner : null;
1544
- }
1545
- function findTextOwnerByRangeScan(boundary, clientX, clientY) {
1546
- const walker = document.createTreeWalker(boundary, NodeFilter.SHOW_TEXT);
1547
- let current = walker.nextNode();
1548
- while (current) {
1549
- const textNode = current;
1550
- if ((textNode.nodeValue ?? "").trim()) {
1551
- const owner = textNode.parentElement;
1552
- if (owner && boundary.contains(owner) && !owner.closest("[data-direct-edit]") && !owner.closest("[data-direct-edit-host]")) {
1553
- const range = document.createRange();
1554
- range.selectNodeContents(textNode);
1555
- const hitsText = Array.from(range.getClientRects()).some(
1556
- (r) => clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom
1557
- );
1558
- range.detach?.();
1559
- if (hitsText) return owner;
1560
- }
1561
- }
1562
- current = walker.nextNode();
1559
+ const bottomDistance = Math.round((parentInnerBottom - elementRect.bottom) / zoom);
1560
+ if (bottomDistance > 0) {
1561
+ const midX = elementRect.left + elementRect.width / 2;
1562
+ measurements.push({
1563
+ direction: "vertical",
1564
+ x1: midX,
1565
+ y1: elementRect.bottom,
1566
+ x2: midX,
1567
+ y2: parentInnerBottom,
1568
+ distance: bottomDistance,
1569
+ labelPosition: { x: midX, y: (elementRect.bottom + parentInnerBottom) / 2 }
1570
+ });
1563
1571
  }
1564
- return null;
1565
- }
1566
- function ensureDirectTextSpanAtPoint(parent, clientX, clientY) {
1567
- const directTextNodes = Array.from(parent.childNodes).filter(
1568
- (node) => node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim())
1569
- );
1570
- for (const textNode of directTextNodes) {
1571
- const range = document.createRange();
1572
- range.selectNodeContents(textNode);
1573
- const hitsText = Array.from(range.getClientRects()).some(
1574
- (r) => clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom
1575
- );
1576
- range.detach?.();
1577
- if (!hitsText) continue;
1578
- const span = document.createElement("span");
1579
- span.setAttribute("data-direct-edit-generated", "text-span");
1580
- span.textContent = textNode.textContent ?? "";
1581
- parent.replaceChild(span, textNode);
1582
- return span;
1572
+ const leftDistance = Math.round((elementRect.left - parentInnerLeft) / zoom);
1573
+ if (leftDistance > 0) {
1574
+ const midY = elementRect.top + elementRect.height / 2;
1575
+ measurements.push({
1576
+ direction: "horizontal",
1577
+ x1: parentInnerLeft,
1578
+ y1: midY,
1579
+ x2: elementRect.left,
1580
+ y2: midY,
1581
+ distance: leftDistance,
1582
+ labelPosition: { x: (parentInnerLeft + elementRect.left) / 2, y: midY }
1583
+ });
1583
1584
  }
1584
- return null;
1585
- }
1586
- function findChildAtPoint(parent, clientX, clientY) {
1587
- const children = htmlChildren(parent);
1588
- if (children.length === 0) return null;
1589
- const hit = children.find((child) => {
1590
- const r = child.getBoundingClientRect();
1591
- return clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom;
1592
- });
1593
- if (hit) return hit;
1594
- if (children.length === 1 && !hasDirectNonWhitespaceText(parent)) return children[0];
1595
- return null;
1596
- }
1597
- function elementFromPointWithoutOverlays(x, y) {
1598
- const host = document.querySelector("[data-direct-edit-host]");
1599
- if (host) host.style.display = "none";
1600
- const el = document.elementFromPoint(x, y);
1601
- if (host) host.style.display = "";
1602
- return el;
1603
- }
1604
- function isLayoutContainer(element) {
1605
- const display = window.getComputedStyle(element).display;
1606
- return display === "flex" || display === "inline-flex" || display === "grid" || display === "inline-grid";
1607
- }
1608
- function isBlockContainer(element) {
1609
- const display = window.getComputedStyle(element).display;
1610
- return display === "block" || display === "flow-root" || display === "inline-block" || display === "list-item";
1611
- }
1612
- function skipElement(el, exclude) {
1613
- if (exclude && exclude.contains(el)) return true;
1614
- if (el === document.body || el === document.documentElement) return true;
1615
- if (el.closest("[data-direct-edit]") || el.closest("[data-direct-edit-host]")) return true;
1616
- return false;
1617
- }
1618
- function findContainerViaTraversal(x, y, exclude) {
1619
- const el = elementFromPointWithoutOverlays(x, y);
1620
- if (!el) return null;
1621
- let current = el;
1622
- while (current) {
1623
- if (!skipElement(current, exclude)) {
1624
- if (isLayoutContainer(current) || isBlockContainer(current)) return current;
1625
- }
1626
- current = current.parentElement;
1585
+ const rightDistance = Math.round((parentInnerRight - elementRect.right) / zoom);
1586
+ if (rightDistance > 0) {
1587
+ const midY = elementRect.top + elementRect.height / 2;
1588
+ measurements.push({
1589
+ direction: "horizontal",
1590
+ x1: elementRect.right,
1591
+ y1: midY,
1592
+ x2: parentInnerRight,
1593
+ y2: midY,
1594
+ distance: rightDistance,
1595
+ labelPosition: { x: (elementRect.right + parentInnerRight) / 2, y: midY }
1596
+ });
1627
1597
  }
1628
- return null;
1598
+ return measurements;
1629
1599
  }
1630
- function findContainerAtPoint(x, y, exclude, preferredParent) {
1631
- const host = document.querySelector("[data-direct-edit-host]");
1632
- if (host) host.style.display = "none";
1633
- const elements = document.elementsFromPoint(x, y);
1634
- if (host) host.style.display = "";
1635
- for (const el of elements) {
1636
- if (skipElement(el, exclude)) continue;
1637
- if (isLayoutContainer(el) || isBlockContainer(el)) return el;
1638
- }
1639
- if (preferredParent && (isLayoutContainer(preferredParent) || isBlockContainer(preferredParent))) {
1640
- for (const el of elements) {
1641
- if (el === preferredParent) return preferredParent;
1600
+ function calculateElementMeasurements(from, to) {
1601
+ const fromRect = from.getBoundingClientRect();
1602
+ const toRect = to.getBoundingClientRect();
1603
+ const zoom = getZoomScale();
1604
+ const measurements = [];
1605
+ const horizontalOverlap = fromRect.left < toRect.right && fromRect.right > toRect.left;
1606
+ const verticalOverlap = fromRect.top < toRect.bottom && fromRect.bottom > toRect.top;
1607
+ if (verticalOverlap) {
1608
+ const overlapTop = Math.max(fromRect.top, toRect.top);
1609
+ const overlapBottom = Math.min(fromRect.bottom, toRect.bottom);
1610
+ const midY = (overlapTop + overlapBottom) / 2;
1611
+ if (fromRect.right <= toRect.left) {
1612
+ const distance = Math.round((toRect.left - fromRect.right) / zoom);
1613
+ measurements.push({
1614
+ direction: "horizontal",
1615
+ x1: fromRect.right,
1616
+ y1: midY,
1617
+ x2: toRect.left,
1618
+ y2: midY,
1619
+ distance,
1620
+ labelPosition: { x: (fromRect.right + toRect.left) / 2, y: midY }
1621
+ });
1622
+ } else if (fromRect.left >= toRect.right) {
1623
+ const distance = Math.round((fromRect.left - toRect.right) / zoom);
1624
+ measurements.push({
1625
+ direction: "horizontal",
1626
+ x1: toRect.right,
1627
+ y1: midY,
1628
+ x2: fromRect.left,
1629
+ y2: midY,
1630
+ distance,
1631
+ labelPosition: { x: (toRect.right + fromRect.left) / 2, y: midY }
1632
+ });
1642
1633
  }
1643
1634
  }
1644
- return findContainerViaTraversal(x, y, exclude);
1645
- }
1646
- function findLayoutContainerAtPoint(x, y, exclude, preferredParent) {
1647
- const host = document.querySelector("[data-direct-edit-host]");
1648
- if (host) host.style.display = "none";
1649
- const elements = document.elementsFromPoint(x, y);
1650
- if (host) host.style.display = "";
1651
- for (const el of elements) {
1652
- if (skipElement(el, exclude)) continue;
1653
- if (isLayoutContainer(el)) return el;
1654
- }
1655
- if (preferredParent && isLayoutContainer(preferredParent)) {
1656
- for (const el of elements) {
1657
- if (el === preferredParent) return preferredParent;
1635
+ if (horizontalOverlap) {
1636
+ const overlapLeft = Math.max(fromRect.left, toRect.left);
1637
+ const overlapRight = Math.min(fromRect.right, toRect.right);
1638
+ const midX = (overlapLeft + overlapRight) / 2;
1639
+ if (fromRect.bottom <= toRect.top) {
1640
+ const distance = Math.round((toRect.top - fromRect.bottom) / zoom);
1641
+ measurements.push({
1642
+ direction: "vertical",
1643
+ x1: midX,
1644
+ y1: fromRect.bottom,
1645
+ x2: midX,
1646
+ y2: toRect.top,
1647
+ distance,
1648
+ labelPosition: { x: midX, y: (fromRect.bottom + toRect.top) / 2 }
1649
+ });
1650
+ } else if (fromRect.top >= toRect.bottom) {
1651
+ const distance = Math.round((fromRect.top - toRect.bottom) / zoom);
1652
+ measurements.push({
1653
+ direction: "vertical",
1654
+ x1: midX,
1655
+ y1: toRect.bottom,
1656
+ x2: midX,
1657
+ y2: fromRect.top,
1658
+ distance,
1659
+ labelPosition: { x: midX, y: (toRect.bottom + fromRect.top) / 2 }
1660
+ });
1658
1661
  }
1659
1662
  }
1660
- return null;
1661
- }
1662
- function calculateDropPosition(container, pointerX, pointerY, draggedElement) {
1663
- const { axis, reversed: isReversed } = detectChildrenDirection(container, draggedElement);
1664
- const isHorizontal = axis === "horizontal";
1665
- const children = Array.from(container.children).filter(
1666
- (child) => child !== draggedElement && child instanceof HTMLElement
1667
- );
1668
- if (children.length === 0) {
1669
- const containerRect2 = container.getBoundingClientRect();
1670
- return {
1671
- insertBefore: null,
1672
- indicator: {
1673
- x: containerRect2.left + 4,
1674
- y: containerRect2.top + 4,
1675
- width: isHorizontal ? 1 : containerRect2.width - 8,
1676
- height: isHorizontal ? containerRect2.height - 8 : 1
1677
- }
1678
- };
1679
- }
1680
- const containerRect = container.getBoundingClientRect();
1681
- let insertBefore = null;
1682
- let indicatorPosition = 0;
1683
- for (let i = 0; i < children.length; i++) {
1684
- const child = children[i];
1685
- const rect = child.getBoundingClientRect();
1686
- const midpoint = isHorizontal ? rect.left + rect.width / 2 : rect.top + rect.height / 2;
1687
- const pointer = isHorizontal ? pointerX : pointerY;
1688
- const beforeMidpoint = isReversed ? pointer > midpoint : pointer < midpoint;
1689
- if (beforeMidpoint) {
1690
- insertBefore = child;
1691
- indicatorPosition = isHorizontal ? rect.left : rect.top;
1692
- break;
1663
+ if (!horizontalOverlap && !verticalOverlap) {
1664
+ const fromCenterX = fromRect.left + fromRect.width / 2;
1665
+ const fromCenterY = fromRect.top + fromRect.height / 2;
1666
+ const toCenterX = toRect.left + toRect.width / 2;
1667
+ const toCenterY = toRect.top + toRect.height / 2;
1668
+ const hDistance = toCenterX > fromCenterX ? Math.round((toRect.left - fromRect.right) / zoom) : Math.round((fromRect.left - toRect.right) / zoom);
1669
+ if (hDistance > 0) {
1670
+ const startX = toCenterX > fromCenterX ? fromRect.right : fromRect.left;
1671
+ const endX = toCenterX > fromCenterX ? toRect.left : toRect.right;
1672
+ const y = (fromCenterY + toCenterY) / 2;
1673
+ measurements.push({
1674
+ direction: "horizontal",
1675
+ x1: startX,
1676
+ y1: y,
1677
+ x2: endX,
1678
+ y2: y,
1679
+ distance: hDistance,
1680
+ labelPosition: { x: (startX + endX) / 2, y }
1681
+ });
1693
1682
  }
1694
- }
1695
- if (!insertBefore) {
1696
- const lastChild = children[children.length - 1];
1697
- const lastRect = lastChild.getBoundingClientRect();
1698
- indicatorPosition = isHorizontal ? lastRect.right : lastRect.bottom;
1699
- }
1700
- const indicator = isHorizontal ? {
1701
- x: indicatorPosition,
1702
- y: containerRect.top + 4,
1703
- width: 2,
1704
- height: containerRect.height - 8
1705
- } : {
1706
- x: containerRect.left + 4,
1707
- y: indicatorPosition,
1708
- width: containerRect.width - 8,
1709
- height: 2
1710
- };
1711
- return { insertBefore, indicator };
1712
- }
1713
- function getFiberForElement(element) {
1714
- if (typeof window !== "undefined") {
1715
- const devtools = window.__DIRECT_EDIT_DEVTOOLS__;
1716
- if (devtools?.getFiberForElement) {
1717
- const fiber = devtools.getFiberForElement(element);
1718
- if (fiber) return fiber;
1683
+ const vDistance = toCenterY > fromCenterY ? Math.round((toRect.top - fromRect.bottom) / zoom) : Math.round((fromRect.top - toRect.bottom) / zoom);
1684
+ if (vDistance > 0) {
1685
+ const x = (fromCenterX + toCenterX) / 2;
1686
+ const startY = toCenterY > fromCenterY ? fromRect.bottom : fromRect.top;
1687
+ const endY = toCenterY > fromCenterY ? toRect.top : toRect.bottom;
1688
+ measurements.push({
1689
+ direction: "vertical",
1690
+ x1: x,
1691
+ y1: startY,
1692
+ x2: x,
1693
+ y2: endY,
1694
+ distance: vDistance,
1695
+ labelPosition: { x, y: (startY + endY) / 2 }
1696
+ });
1719
1697
  }
1720
1698
  }
1721
- const fiberKey = Object.keys(element).find(
1722
- (key) => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")
1723
- );
1724
- if (!fiberKey) return null;
1725
- return element[fiberKey] || null;
1699
+ return measurements;
1726
1700
  }
1727
- var STACK_SOURCE_FILE_EXTENSION_REGEX = /\.(jsx|tsx|ts|js)$/;
1728
- var STACK_BUNDLED_FILE_PATTERN_REGEX = /(\.min|bundle|chunk|vendor|vendors|runtime|polyfill|polyfills)\.(js|mjs|cjs)$|(chunk|bundle|vendor|vendors|runtime|polyfill|polyfills|framework|app|main|index)[-_.][A-Za-z0-9_-]{4,}\.(js|mjs|cjs)$|[\da-f]{8,}\.(js|mjs|cjs)$|[-_.][\da-f]{20,}\.(js|mjs|cjs)$|\/dist\/|\/build\/|\/.next\/|\/out\/|\/node_modules\/|\.webpack\.|\.vite\.|\.turbopack\./i;
1729
- var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
1730
- var SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code\])?$/;
1731
- var SERVER_FRAME_MARKER = "(at Server)";
1732
- var STACK_INTERNAL_SCHEME_PREFIXES = [
1733
- "rsc://",
1734
- "about://React/",
1735
- "React/Server/",
1736
- "file:///",
1737
- "webpack://",
1738
- "webpack-internal://",
1739
- "node:",
1740
- "turbopack://",
1741
- "/app-pages-browser/"
1742
- ];
1743
- function formatOwnerDebugStack(stack) {
1744
- if (!stack) return "";
1745
- const lines = stack.split("\n");
1746
- const filtered = [];
1747
- for (const line of lines) {
1748
- const trimmed = line.trim();
1749
- if (!trimmed) continue;
1750
- if (trimmed === "Error: react-stack-top-frame") continue;
1751
- if (trimmed.includes("react_stack_bottom_frame") || trimmed.includes("react-stack-bottom-frame")) {
1752
- continue;
1701
+ var GUIDELINE_PROXIMITY = 80;
1702
+ function calculateGuidelineMeasurements(element, guidelines, mousePosition) {
1703
+ if (guidelines.length === 0) return [];
1704
+ const snap = getCanvasSnapshot();
1705
+ const zoom = snap.active ? snap.zoom : 1;
1706
+ const rect = element.getBoundingClientRect();
1707
+ const measurements = [];
1708
+ for (const g of guidelines) {
1709
+ let viewportPos;
1710
+ if (snap.active) {
1711
+ const pan = g.orientation === "horizontal" ? snap.panY : snap.panX;
1712
+ const bo = g.orientation === "horizontal" ? getBodyOffset().y : getBodyOffset().x;
1713
+ viewportPos = bo + (g.position - bo + pan) * zoom;
1714
+ } else {
1715
+ const scroll = g.orientation === "horizontal" ? window.scrollY : window.scrollX;
1716
+ viewportPos = g.position - scroll;
1717
+ }
1718
+ if (g.orientation === "horizontal") {
1719
+ const midX = rect.left + rect.width / 2;
1720
+ if (mousePosition && Math.abs(mousePosition.y - viewportPos) > GUIDELINE_PROXIMITY) continue;
1721
+ if (viewportPos < rect.top) {
1722
+ const distance = Math.round((rect.top - viewportPos) / zoom);
1723
+ if (distance > 0) {
1724
+ measurements.push({
1725
+ direction: "vertical",
1726
+ x1: midX,
1727
+ y1: viewportPos,
1728
+ x2: midX,
1729
+ y2: rect.top,
1730
+ distance,
1731
+ labelPosition: { x: midX, y: (viewportPos + rect.top) / 2 }
1732
+ });
1733
+ }
1734
+ } else if (viewportPos > rect.bottom) {
1735
+ const distance = Math.round((viewportPos - rect.bottom) / zoom);
1736
+ if (distance > 0) {
1737
+ measurements.push({
1738
+ direction: "vertical",
1739
+ x1: midX,
1740
+ y1: rect.bottom,
1741
+ x2: midX,
1742
+ y2: viewportPos,
1743
+ distance,
1744
+ labelPosition: { x: midX, y: (rect.bottom + viewportPos) / 2 }
1745
+ });
1746
+ }
1747
+ }
1748
+ } else {
1749
+ const midY = rect.top + rect.height / 2;
1750
+ if (mousePosition && Math.abs(mousePosition.x - viewportPos) > GUIDELINE_PROXIMITY) continue;
1751
+ if (viewportPos < rect.left) {
1752
+ const distance = Math.round((rect.left - viewportPos) / zoom);
1753
+ if (distance > 0) {
1754
+ measurements.push({
1755
+ direction: "horizontal",
1756
+ x1: viewportPos,
1757
+ y1: midY,
1758
+ x2: rect.left,
1759
+ y2: midY,
1760
+ distance,
1761
+ labelPosition: { x: (viewportPos + rect.left) / 2, y: midY }
1762
+ });
1763
+ }
1764
+ } else if (viewportPos > rect.right) {
1765
+ const distance = Math.round((viewportPos - rect.right) / zoom);
1766
+ if (distance > 0) {
1767
+ measurements.push({
1768
+ direction: "horizontal",
1769
+ x1: rect.right,
1770
+ y1: midY,
1771
+ x2: viewportPos,
1772
+ y2: midY,
1773
+ distance,
1774
+ labelPosition: { x: (rect.right + viewportPos) / 2, y: midY }
1775
+ });
1776
+ }
1777
+ }
1753
1778
  }
1754
- filtered.push(line);
1755
- }
1756
- if (filtered.length > 0 && filtered[0].includes("fakeJSXCallSite")) {
1757
- filtered.shift();
1758
1779
  }
1759
- return filtered.join("\n");
1780
+ return measurements;
1760
1781
  }
1761
- function extractStackLocation(urlLike) {
1762
- if (!urlLike.includes(":")) return [urlLike, void 0, void 0];
1763
- const isWrappedLocation = urlLike.startsWith("(") && /:\d+\)$/.test(urlLike);
1764
- const sanitizedResult = isWrappedLocation ? urlLike.slice(1, -1) : urlLike;
1765
- const parts = /(.+?)(?::(\d+))?(?::(\d+))?$/.exec(sanitizedResult);
1766
- if (!parts) return [sanitizedResult, void 0, void 0];
1767
- return [
1768
- parts[1],
1769
- parts[2] !== void 0 ? Number(parts[2]) : void 0,
1770
- parts[3] !== void 0 ? Number(parts[3]) : void 0
1771
- ];
1782
+ function isFlexContainer(element) {
1783
+ const computed = window.getComputedStyle(element);
1784
+ return computed.display === "flex" || computed.display === "inline-flex";
1772
1785
  }
1773
- function parseV8StackLine(line) {
1774
- let currentLine = line;
1775
- if (currentLine.includes("(eval ")) {
1776
- currentLine = currentLine.replace(/eval code/g, "eval").replace(/(\(eval at [^()]*)|(,.*$)/g, "");
1777
- }
1778
- let sanitizedLine = currentLine.replace(/^\s+/, "").replace(/\(eval code/g, "(").replace(/^.*?\s+/, "");
1779
- const locationMatch = sanitizedLine.match(/ (\(.+\)$)/);
1780
- if (locationMatch) {
1781
- sanitizedLine = sanitizedLine.replace(locationMatch[0], "");
1782
- }
1783
- const [fileName, lineNumber, columnNumber] = extractStackLocation(
1784
- locationMatch ? locationMatch[1] : sanitizedLine
1785
- );
1786
- const functionName = locationMatch && sanitizedLine ? sanitizedLine : void 0;
1787
- if (fileName === "eval" || fileName === "<anonymous>") {
1786
+ function getFlexDirection(element) {
1787
+ const computed = window.getComputedStyle(element);
1788
+ return computed.flexDirection;
1789
+ }
1790
+ function isInFlowChild(el) {
1791
+ const cs = window.getComputedStyle(el);
1792
+ return cs.display !== "none" && cs.position !== "absolute" && cs.position !== "fixed";
1793
+ }
1794
+ function detectChildrenDirection(container, exclude) {
1795
+ const computed = window.getComputedStyle(container);
1796
+ if (computed.display === "flex" || computed.display === "inline-flex") {
1797
+ const dir = computed.flexDirection;
1788
1798
  return {
1789
- functionName
1799
+ axis: dir === "row" || dir === "row-reverse" ? "horizontal" : "vertical",
1800
+ reversed: dir === "row-reverse" || dir === "column-reverse"
1790
1801
  };
1791
1802
  }
1792
- return {
1793
- functionName,
1794
- fileName,
1795
- lineNumber,
1796
- columnNumber,
1797
- source: currentLine,
1798
- isServer: currentLine.includes(SERVER_FRAME_MARKER) || fileName.startsWith("rsc://")
1799
- };
1800
- }
1801
- function parseFFOrSafariStackLine(line) {
1802
- let currentLine = line;
1803
- if (currentLine.includes(" > eval")) {
1804
- currentLine = currentLine.replace(
1805
- / line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,
1806
- ":$1"
1807
- );
1803
+ const visible = [];
1804
+ for (const c of container.children) {
1805
+ if (!(c instanceof HTMLElement) || c === exclude) continue;
1806
+ if (!isInFlowChild(c)) continue;
1807
+ visible.push(c);
1808
+ if (visible.length === 2) break;
1808
1809
  }
1809
- const trimmed = currentLine.trim();
1810
- if (!trimmed || SAFARI_NATIVE_CODE_REGEXP.test(trimmed)) {
1811
- return null;
1810
+ if (visible.length < 2) return { axis: "vertical", reversed: false };
1811
+ const first = visible[0].getBoundingClientRect();
1812
+ const second = visible[1].getBoundingClientRect();
1813
+ const yOverlap = first.bottom - 2 > second.top && second.bottom - 2 > first.top;
1814
+ if (yOverlap) {
1815
+ return { axis: "horizontal", reversed: second.right < first.left };
1812
1816
  }
1813
- if (!trimmed.includes("@") && !trimmed.includes(":")) {
1814
- return {
1815
- functionName: trimmed,
1816
- source: currentLine,
1817
- isServer: trimmed.includes(SERVER_FRAME_MARKER)
1818
- };
1817
+ return { axis: "vertical", reversed: second.bottom < first.top };
1818
+ }
1819
+ function computeIntendedIndex(parent, draggedElement) {
1820
+ const { axis } = detectChildrenDirection(parent, draggedElement);
1821
+ const isHorizontal = axis === "horizontal";
1822
+ const draggedRect = draggedElement.getBoundingClientRect();
1823
+ const intendedCenter = isHorizontal ? draggedRect.left + draggedRect.width / 2 : draggedRect.top + draggedRect.height / 2;
1824
+ const siblings = [];
1825
+ for (const c of parent.children) {
1826
+ if (!(c instanceof HTMLElement) || c === draggedElement) continue;
1827
+ if (!isInFlowChild(c)) continue;
1828
+ siblings.push(c);
1819
1829
  }
1820
- const atIndex = trimmed.lastIndexOf("@");
1821
- if (atIndex === -1) {
1822
- return null;
1830
+ if (siblings.length === 0) {
1831
+ return { index: 0, siblingBefore: null, siblingAfter: null };
1823
1832
  }
1824
- const maybeFunctionName = trimmed.slice(0, atIndex);
1825
- const location = trimmed.slice(atIndex + 1);
1826
- const [fileName, lineNumber, columnNumber] = extractStackLocation(location);
1827
- return {
1828
- functionName: maybeFunctionName || void 0,
1829
- fileName,
1830
- lineNumber,
1831
- columnNumber,
1832
- source: currentLine,
1833
- isServer: currentLine.includes(SERVER_FRAME_MARKER) || fileName.startsWith("rsc://")
1834
- };
1833
+ for (let i = 0; i < siblings.length; i++) {
1834
+ const rect = siblings[i].getBoundingClientRect();
1835
+ const midpoint = isHorizontal ? rect.left + rect.width / 2 : rect.top + rect.height / 2;
1836
+ if (intendedCenter < midpoint) {
1837
+ return { index: i, siblingBefore: i > 0 ? siblings[i - 1] : null, siblingAfter: siblings[i] };
1838
+ }
1839
+ }
1840
+ return { index: siblings.length, siblingBefore: siblings[siblings.length - 1], siblingAfter: null };
1835
1841
  }
1836
- function parseInStackLine(line) {
1837
- const functionName = line.replace(/^\s*in\s+/, "").replace(/\s*\(at .*\)$/, "").trim();
1838
- if (!functionName) return null;
1839
- return {
1840
- functionName,
1841
- source: line,
1842
- isServer: line.includes(SERVER_FRAME_MARKER)
1843
- };
1842
+ function htmlChildren(el) {
1843
+ return Array.from(el.children).filter(
1844
+ (child) => child instanceof HTMLElement
1845
+ );
1844
1846
  }
1845
- function parseDebugStack(stack) {
1846
- const frames = [];
1847
- for (const rawLine of stack.split("\n")) {
1848
- if (FIREFOX_SAFARI_STACK_REGEXP.test(rawLine)) {
1849
- const parsed = parseFFOrSafariStackLine(rawLine);
1850
- if (parsed) frames.push(parsed);
1851
- continue;
1852
- }
1853
- if (/^\s*at\s+/.test(rawLine)) {
1854
- const parsed = parseV8StackLine(rawLine);
1855
- if (parsed) frames.push(parsed);
1856
- continue;
1857
- }
1858
- if (/^\s*in\s+/.test(rawLine)) {
1859
- const parsed = parseInStackLine(rawLine);
1860
- if (parsed) frames.push(parsed);
1847
+ function findFlexAncestor(element, boundary) {
1848
+ let current = element;
1849
+ while (current && current !== document.body) {
1850
+ const parent = current.parentElement;
1851
+ if (!parent) break;
1852
+ const display = getComputedStyle(parent).display;
1853
+ if (display === "flex" || display === "inline-flex") {
1854
+ return { flexParent: parent, child: current };
1861
1855
  }
1856
+ if (boundary && parent === boundary) break;
1857
+ current = parent;
1862
1858
  }
1863
- return frames;
1859
+ return null;
1864
1860
  }
1865
- function normalizeStackFileName(fileName) {
1866
- if (!fileName) return "";
1867
- let normalized = fileName;
1868
- const isHttpUrl = normalized.startsWith("http://") || normalized.startsWith("https://");
1869
- if (isHttpUrl) {
1870
- try {
1871
- normalized = new URL(normalized).pathname;
1872
- } catch {
1873
- }
1861
+ function computeHoverHighlight(elementUnder, selectedElement) {
1862
+ if (!elementUnder || elementUnder === document.body || elementUnder === document.documentElement || elementUnder.closest("[data-direct-edit]") || elementUnder.closest("[data-direct-edit-host]") || elementUnder === selectedElement) {
1863
+ return null;
1874
1864
  }
1875
- let didStripPrefix = true;
1876
- while (didStripPrefix) {
1877
- didStripPrefix = false;
1878
- for (const prefix of STACK_INTERNAL_SCHEME_PREFIXES) {
1879
- if (normalized.startsWith(prefix)) {
1880
- normalized = normalized.slice(prefix.length);
1881
- if (prefix === "file:///") {
1882
- normalized = `/${normalized.replace(/^\/+/, "")}`;
1883
- }
1884
- didStripPrefix = true;
1885
- break;
1886
- }
1887
- }
1865
+ const boundary = selectedElement?.contains(elementUnder) ? selectedElement : null;
1866
+ const ownDisplay = getComputedStyle(elementUnder).display;
1867
+ if (ownDisplay === "flex" || ownDisplay === "inline-flex") {
1868
+ return { flexContainer: elementUnder, children: htmlChildren(elementUnder) };
1888
1869
  }
1889
- normalized = normalized.replace(/^\/\(app-pages-browser\)\//, "/").replace(/^\/\.\//, "/").replace(/^\.\//, "");
1890
- const queryIndex = normalized.indexOf("?");
1891
- if (queryIndex !== -1) {
1892
- normalized = normalized.slice(0, queryIndex);
1870
+ const found = findFlexAncestor(elementUnder, boundary);
1871
+ if (found) {
1872
+ return { flexContainer: found.flexParent, children: htmlChildren(found.flexParent) };
1893
1873
  }
1894
- return normalized;
1874
+ return { flexContainer: elementUnder, children: [] };
1895
1875
  }
1896
- function isSourceStackFile(fileName) {
1897
- const normalizedFileName = normalizeStackFileName(fileName);
1898
- if (!normalizedFileName) return false;
1899
- if (!STACK_SOURCE_FILE_EXTENSION_REGEX.test(normalizedFileName)) return false;
1900
- return !STACK_BUNDLED_FILE_PATTERN_REGEX.test(normalizedFileName);
1876
+ function resolveElementTarget(elementUnder, selectedElement) {
1877
+ const boundary = selectedElement?.contains(elementUnder) ? selectedElement : null;
1878
+ const found = findFlexAncestor(elementUnder, boundary);
1879
+ if (found && found.flexParent === boundary) return elementUnder;
1880
+ return found?.child ?? elementUnder;
1901
1881
  }
1902
- function buildFunctionNameToRscFramesMap(fiber) {
1903
- const functionNameToRscFrames = /* @__PURE__ */ new Map();
1904
- const visited = /* @__PURE__ */ new Set();
1905
- let current = fiber;
1906
- while (current && !visited.has(current)) {
1907
- visited.add(current);
1908
- const rawStack = current?._debugStack?.stack;
1909
- const stack = typeof rawStack === "string" ? formatOwnerDebugStack(rawStack) : "";
1910
- if (stack) {
1911
- const frames = parseDebugStack(stack);
1912
- for (const frame of frames) {
1913
- if (!frame.functionName || !frame.fileName) continue;
1914
- if (!frame.fileName.startsWith("rsc://")) continue;
1915
- const normalized = normalizeStackFileName(frame.fileName);
1916
- if (!normalized) continue;
1917
- const existing = functionNameToRscFrames.get(frame.functionName) ?? [];
1918
- const duplicate = existing.some(
1919
- (candidate) => candidate.fileName === normalized && candidate.lineNumber === frame.lineNumber && candidate.columnNumber === frame.columnNumber
1882
+ function findTextOwnerAtPoint(boundary, clientX, clientY) {
1883
+ const doc = document;
1884
+ const caretNode = doc.caretPositionFromPoint?.(clientX, clientY)?.offsetNode ?? doc.caretRangeFromPoint?.(clientX, clientY)?.startContainer ?? null;
1885
+ if (!caretNode || caretNode.nodeType !== Node.TEXT_NODE) return null;
1886
+ const textNode = caretNode;
1887
+ if (!(textNode.nodeValue ?? "").trim()) return null;
1888
+ const owner = textNode.parentElement;
1889
+ if (!owner || !boundary.contains(owner)) return null;
1890
+ if (owner.closest("[data-direct-edit]") || owner.closest("[data-direct-edit-host]")) return null;
1891
+ const range = document.createRange();
1892
+ range.selectNodeContents(textNode);
1893
+ const hitsText = Array.from(range.getClientRects()).some(
1894
+ (r) => clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom
1895
+ );
1896
+ range.detach?.();
1897
+ return hitsText ? owner : null;
1898
+ }
1899
+ function findTextOwnerByRangeScan(boundary, clientX, clientY) {
1900
+ const walker = document.createTreeWalker(boundary, NodeFilter.SHOW_TEXT);
1901
+ let current = walker.nextNode();
1902
+ while (current) {
1903
+ const textNode = current;
1904
+ if ((textNode.nodeValue ?? "").trim()) {
1905
+ const owner = textNode.parentElement;
1906
+ if (owner && boundary.contains(owner) && !owner.closest("[data-direct-edit]") && !owner.closest("[data-direct-edit-host]")) {
1907
+ const range = document.createRange();
1908
+ range.selectNodeContents(textNode);
1909
+ const hitsText = Array.from(range.getClientRects()).some(
1910
+ (r) => clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom
1920
1911
  );
1921
- if (!duplicate) {
1922
- existing.push({
1923
- fileName: normalized,
1924
- lineNumber: frame.lineNumber,
1925
- columnNumber: frame.columnNumber
1926
- });
1927
- functionNameToRscFrames.set(frame.functionName, existing);
1928
- }
1912
+ range.detach?.();
1913
+ if (hitsText) return owner;
1929
1914
  }
1930
1915
  }
1931
- current = current._debugOwner ?? current.return ?? null;
1916
+ current = walker.nextNode();
1932
1917
  }
1933
- return functionNameToRscFrames;
1934
- }
1935
- function enrichServerFrame(frame, functionNameToRscFrames, functionNameToUsageIndex) {
1936
- if (!frame.functionName) return frame;
1937
- const available = functionNameToRscFrames.get(frame.functionName);
1938
- if (!available) return frame;
1939
- const usageIndex = functionNameToUsageIndex.get(frame.functionName) ?? 0;
1940
- const resolved = available[usageIndex % available.length];
1941
- functionNameToUsageIndex.set(frame.functionName, usageIndex + 1);
1942
- return {
1943
- ...frame,
1944
- fileName: resolved.fileName,
1945
- lineNumber: resolved.lineNumber,
1946
- columnNumber: resolved.columnNumber
1947
- };
1918
+ return null;
1948
1919
  }
1949
- function getSourceFromDebugStack(fiber) {
1950
- const rawStack = fiber?._debugStack?.stack;
1951
- if (typeof rawStack !== "string" || rawStack.length === 0) {
1952
- return null;
1953
- }
1954
- const formattedStack = formatOwnerDebugStack(rawStack);
1955
- if (!formattedStack) return null;
1956
- const stackFrames = parseDebugStack(formattedStack);
1957
- const functionNameToRscFrames = buildFunctionNameToRscFramesMap(fiber);
1958
- const functionNameToUsageIndex = /* @__PURE__ */ new Map();
1959
- for (const frame of stackFrames) {
1960
- const maybeEnriched = frame.isServer ? enrichServerFrame(frame, functionNameToRscFrames, functionNameToUsageIndex) : frame;
1961
- if (!maybeEnriched.fileName) continue;
1962
- const normalizedFileName = normalizeStackFileName(maybeEnriched.fileName);
1963
- if (!normalizedFileName) continue;
1964
- if (isSourceStackFile(normalizedFileName)) {
1965
- return {
1966
- fileName: normalizedFileName,
1967
- lineNumber: maybeEnriched.lineNumber,
1968
- columnNumber: maybeEnriched.columnNumber
1969
- };
1970
- }
1920
+ function ensureDirectTextSpanAtPoint(parent, clientX, clientY) {
1921
+ const directTextNodes = Array.from(parent.childNodes).filter(
1922
+ (node) => node.nodeType === Node.TEXT_NODE && Boolean(node.textContent?.trim())
1923
+ );
1924
+ for (const textNode of directTextNodes) {
1925
+ const range = document.createRange();
1926
+ range.selectNodeContents(textNode);
1927
+ const hitsText = Array.from(range.getClientRects()).some(
1928
+ (r) => clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom
1929
+ );
1930
+ range.detach?.();
1931
+ if (!hitsText) continue;
1932
+ const span = document.createElement("span");
1933
+ span.setAttribute("data-direct-edit-generated", "text-span");
1934
+ span.textContent = textNode.textContent ?? "";
1935
+ parent.replaceChild(span, textNode);
1936
+ return span;
1971
1937
  }
1972
1938
  return null;
1973
1939
  }
1974
- function getSourceFromFiber(fiber) {
1975
- const debugSource = fiber?._debugSource;
1976
- if (debugSource?.fileName) return debugSource;
1977
- const owner = fiber?._debugOwner;
1978
- const ownerPending = owner?.pendingProps?.__source;
1979
- if (ownerPending?.fileName) return ownerPending;
1980
- const ownerMemo = owner?.memoizedProps?.__source;
1981
- if (ownerMemo?.fileName) return ownerMemo;
1982
- const pending = fiber?.pendingProps?.__source;
1983
- if (pending?.fileName) return pending;
1984
- const memo = fiber?.memoizedProps?.__source;
1985
- if (memo?.fileName) return memo;
1986
- const fromDebugStack = getSourceFromDebugStack(fiber);
1987
- if (fromDebugStack?.fileName) return fromDebugStack;
1940
+ function findChildAtPoint(parent, clientX, clientY) {
1941
+ const children = htmlChildren(parent);
1942
+ if (children.length === 0) return null;
1943
+ const hit = children.find((child) => {
1944
+ const r = child.getBoundingClientRect();
1945
+ return clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom;
1946
+ });
1947
+ if (hit) return hit;
1948
+ if (children.length === 1 && !hasDirectNonWhitespaceText(parent)) return children[0];
1988
1949
  return null;
1989
1950
  }
1990
- function buildFrame(fiber) {
1991
- const type = fiber?.type;
1992
- if (typeof type !== "function" && typeof type !== "object") return null;
1993
- const name = type?.displayName || type?.name || null;
1994
- if (!name || name === "Fragment") return null;
1995
- const frame = { name };
1996
- const source = getSourceFromFiber(fiber);
1997
- if (source?.fileName) {
1998
- frame.file = source.fileName;
1999
- if (typeof source.lineNumber === "number") {
2000
- frame.line = source.lineNumber;
2001
- }
2002
- if (typeof source.columnNumber === "number") {
2003
- frame.column = source.columnNumber;
1951
+ function elementFromPointWithoutOverlays(x, y) {
1952
+ const host = document.querySelector("[data-direct-edit-host]");
1953
+ if (host) host.style.display = "none";
1954
+ const el = document.elementFromPoint(x, y);
1955
+ if (host) host.style.display = "";
1956
+ return el;
1957
+ }
1958
+ function isLayoutContainer(element) {
1959
+ const display = window.getComputedStyle(element).display;
1960
+ return display === "flex" || display === "inline-flex" || display === "grid" || display === "inline-grid";
1961
+ }
1962
+ function isBlockContainer(element) {
1963
+ const display = window.getComputedStyle(element).display;
1964
+ return display === "block" || display === "flow-root" || display === "inline-block" || display === "list-item";
1965
+ }
1966
+ function skipElement(el, exclude) {
1967
+ if (exclude && exclude.contains(el)) return true;
1968
+ if (el === document.body || el === document.documentElement) return true;
1969
+ if (el.closest("[data-direct-edit]") || el.closest("[data-direct-edit-host]")) return true;
1970
+ return false;
1971
+ }
1972
+ function findContainerViaTraversal(x, y, exclude) {
1973
+ const el = elementFromPointWithoutOverlays(x, y);
1974
+ if (!el) return null;
1975
+ let current = el;
1976
+ while (current) {
1977
+ if (!skipElement(current, exclude)) {
1978
+ if (isLayoutContainer(current) || isBlockContainer(current)) return current;
2004
1979
  }
1980
+ current = current.parentElement;
2005
1981
  }
2006
- return frame;
1982
+ return null;
2007
1983
  }
2008
- function shouldIncludeFrame(frame, lastFrame) {
2009
- if (!lastFrame) return true;
2010
- if (frame.name !== lastFrame.name) return true;
2011
- if (!lastFrame.file && frame.file) return true;
2012
- if (lastFrame.file && frame.file && lastFrame.line == null && frame.line != null) return true;
2013
- if (lastFrame.file && frame.file && lastFrame.line != null && frame.line != null && lastFrame.column == null && frame.column != null) {
2014
- return true;
1984
+ function findContainerAtPoint(x, y, exclude, preferredParent) {
1985
+ const host = document.querySelector("[data-direct-edit-host]");
1986
+ if (host) host.style.display = "none";
1987
+ const elements = document.elementsFromPoint(x, y);
1988
+ if (host) host.style.display = "";
1989
+ for (const el of elements) {
1990
+ if (skipElement(el, exclude)) continue;
1991
+ if (isLayoutContainer(el) || isBlockContainer(el)) return el;
2015
1992
  }
2016
- return false;
1993
+ if (preferredParent && (isLayoutContainer(preferredParent) || isBlockContainer(preferredParent))) {
1994
+ for (const el of elements) {
1995
+ if (el === preferredParent) return preferredParent;
1996
+ }
1997
+ }
1998
+ return findContainerViaTraversal(x, y, exclude);
2017
1999
  }
2018
- function getOwnerStack(fiber) {
2019
- const frames = [];
2020
- let current = fiber;
2021
- let lastFrame = null;
2022
- let nearestComponentFiber = null;
2023
- while (current) {
2024
- const frame = buildFrame(current);
2025
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2026
- frames.push(frame);
2027
- lastFrame = frame;
2028
- if (!nearestComponentFiber) {
2029
- nearestComponentFiber = current;
2030
- }
2000
+ function findLayoutContainerAtPoint(x, y, exclude, preferredParent) {
2001
+ const host = document.querySelector("[data-direct-edit-host]");
2002
+ if (host) host.style.display = "none";
2003
+ const elements = document.elementsFromPoint(x, y);
2004
+ if (host) host.style.display = "";
2005
+ for (const el of elements) {
2006
+ if (skipElement(el, exclude)) continue;
2007
+ if (isLayoutContainer(el)) return el;
2008
+ }
2009
+ if (preferredParent && isLayoutContainer(preferredParent)) {
2010
+ for (const el of elements) {
2011
+ if (el === preferredParent) return preferredParent;
2031
2012
  }
2032
- current = current._debugOwner;
2033
2013
  }
2034
- return { frames, nearestComponentFiber };
2014
+ return null;
2035
2015
  }
2036
- function getRenderStack(fiber) {
2037
- const frames = [];
2038
- let current = fiber;
2039
- let lastFrame = null;
2040
- let nearestComponentFiber = null;
2041
- while (current) {
2042
- const frame = buildFrame(current);
2043
- if (frame && shouldIncludeFrame(frame, lastFrame)) {
2044
- frames.push(frame);
2045
- lastFrame = frame;
2046
- if (!nearestComponentFiber) {
2047
- nearestComponentFiber = current;
2016
+ function calculateDropPosition(container, pointerX, pointerY, draggedElement) {
2017
+ const { axis, reversed: isReversed } = detectChildrenDirection(container, draggedElement);
2018
+ const isHorizontal = axis === "horizontal";
2019
+ const children = Array.from(container.children).filter(
2020
+ (child) => child !== draggedElement && child instanceof HTMLElement
2021
+ );
2022
+ if (children.length === 0) {
2023
+ const containerRect2 = container.getBoundingClientRect();
2024
+ return {
2025
+ insertBefore: null,
2026
+ indicator: {
2027
+ x: containerRect2.left + 4,
2028
+ y: containerRect2.top + 4,
2029
+ width: isHorizontal ? 1 : containerRect2.width - 8,
2030
+ height: isHorizontal ? containerRect2.height - 8 : 1
2048
2031
  }
2032
+ };
2033
+ }
2034
+ const containerRect = container.getBoundingClientRect();
2035
+ let insertBefore = null;
2036
+ let indicatorPosition = 0;
2037
+ for (let i = 0; i < children.length; i++) {
2038
+ const child = children[i];
2039
+ const rect = child.getBoundingClientRect();
2040
+ const midpoint = isHorizontal ? rect.left + rect.width / 2 : rect.top + rect.height / 2;
2041
+ const pointer = isHorizontal ? pointerX : pointerY;
2042
+ const beforeMidpoint = isReversed ? pointer > midpoint : pointer < midpoint;
2043
+ if (beforeMidpoint) {
2044
+ insertBefore = child;
2045
+ indicatorPosition = isHorizontal ? rect.left : rect.top;
2046
+ break;
2049
2047
  }
2050
- current = current.return;
2051
2048
  }
2052
- return { frames, nearestComponentFiber };
2053
- }
2054
- function getReactComponentInfo(element) {
2055
- const fiber = getFiberForElement(element);
2056
- if (!fiber) return { frames: [], nearestComponentFiber: null };
2057
- const elementSource = getSourceFromFiber(fiber);
2058
- const elementSourceFile = elementSource?.fileName || void 0;
2059
- const ownerResult = getOwnerStack(fiber);
2060
- if (ownerResult.frames.length > 0) {
2061
- return { ...ownerResult, elementSourceFile };
2049
+ if (!insertBefore) {
2050
+ const lastChild = children[children.length - 1];
2051
+ const lastRect = lastChild.getBoundingClientRect();
2052
+ indicatorPosition = isHorizontal ? lastRect.right : lastRect.bottom;
2062
2053
  }
2063
- return { ...getRenderStack(fiber), elementSourceFile };
2054
+ const indicator = isHorizontal ? {
2055
+ x: indicatorPosition,
2056
+ y: containerRect.top + 4,
2057
+ width: 2,
2058
+ height: containerRect.height - 8
2059
+ } : {
2060
+ x: containerRect.left + 4,
2061
+ y: indicatorPosition,
2062
+ width: containerRect.width - 8,
2063
+ height: 2
2064
+ };
2065
+ return { insertBefore, indicator };
2064
2066
  }
2065
2067
  function getElementDisplayName(element) {
2066
2068
  const tag = element.tagName.toLowerCase();