@lijinmei-810/dev-inspector 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2584 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DevInspector: () => DevInspector,
24
+ DevInspectorProvider: () => DevInspectorProvider,
25
+ InspectorPanel: () => InspectorPanel,
26
+ defaultDevInspectorConfig: () => defaultDevInspectorConfig,
27
+ mergeDevInspectorConfig: () => mergeDevInspectorConfig,
28
+ mountDevInspector: () => mountDevInspector,
29
+ useDevInspectorConfig: () => useDevInspectorConfig
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/DevInspector.tsx
34
+ var import_react2 = require("react");
35
+ var import_lucide_react = require("lucide-react");
36
+
37
+ // src/DevInspectorProvider.tsx
38
+ var import_react = require("react");
39
+
40
+ // src/config.ts
41
+ var FALLBACK_TOKENS = {
42
+ colorPalette: [],
43
+ tokenLabels: {},
44
+ radiusPresets: [
45
+ { label: "\u65E0", sub: "", value: "0px", token: "" },
46
+ { label: "S", sub: "4px", value: "4px", token: "" },
47
+ { label: "M", sub: "8px", value: "8px", token: "" },
48
+ { label: "L", sub: "12px", value: "12px", token: "" },
49
+ { label: "XL", sub: "16px", value: "16px", token: "" },
50
+ { label: "XXL", sub: "24px", value: "24px", token: "" }
51
+ ],
52
+ spaceSteps: [
53
+ { label: "\u65E0", size: "", val: "0px" },
54
+ { label: "S", size: "4px", val: "4px" },
55
+ { label: "M", size: "8px", val: "8px" },
56
+ { label: "L", size: "12px", val: "12px" },
57
+ { label: "XL", size: "16px", val: "16px" },
58
+ { label: "XXL", size: "24px", val: "24px" }
59
+ ],
60
+ borderWidthSteps: ["0px", "1px", "2px", "4px"],
61
+ fontSizeOptions: [],
62
+ fontWeightOptions: [
63
+ { label: "\u5E38", value: "400" },
64
+ { label: "\u4E2D", value: "500" },
65
+ { label: "\u7C97", value: "600" },
66
+ { label: "\u9ED1", value: "700" }
67
+ ],
68
+ shadowTokens: [],
69
+ typographyTokens: []
70
+ };
71
+ var defaultDevInspectorConfig = {
72
+ rootId: "dev-inspector-root",
73
+ endpoints: {
74
+ applyCss: "/__dev/apply-css",
75
+ submitStyleIntent: "/__dev/submit-style-intent",
76
+ styleIntents: "/__dev/style-intents",
77
+ deleteStyleIntent: "/__dev/style-intents/delete",
78
+ handoff: "/__dev/handoff",
79
+ reveal: "/__dev/reveal"
80
+ },
81
+ tokens: FALLBACK_TOKENS
82
+ };
83
+ function mergeDevInspectorConfig(overrides) {
84
+ return {
85
+ ...defaultDevInspectorConfig,
86
+ ...overrides,
87
+ endpoints: {
88
+ ...defaultDevInspectorConfig.endpoints,
89
+ ...overrides?.endpoints
90
+ },
91
+ tokens: {
92
+ ...defaultDevInspectorConfig.tokens,
93
+ ...overrides?.tokens
94
+ }
95
+ };
96
+ }
97
+
98
+ // src/DevInspectorProvider.tsx
99
+ var import_jsx_runtime = require("react/jsx-runtime");
100
+ var DevInspectorConfigContext = (0, import_react.createContext)(defaultDevInspectorConfig);
101
+ function DevInspectorProvider({
102
+ children,
103
+ config
104
+ }) {
105
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DevInspectorConfigContext.Provider, { value: mergeDevInspectorConfig(config), children });
106
+ }
107
+ function useDevInspectorConfig() {
108
+ return (0, import_react.useContext)(DevInspectorConfigContext);
109
+ }
110
+
111
+ // src/DevInspector.tsx
112
+ var import_jsx_runtime2 = require("react/jsx-runtime");
113
+ function calcDropPos(rect, dropHeight = 280) {
114
+ const spaceBelow = window.innerHeight - rect.bottom;
115
+ const top = spaceBelow >= dropHeight + 8 ? rect.bottom + 4 : rect.top - dropHeight - 4;
116
+ return { top: Math.max(8, top), left: rect.left };
117
+ }
118
+ var COLOR_PROPS = [
119
+ { label: "\u80CC\u666F\u8272", prop: "background-color" }
120
+ ];
121
+ function getColorLabel(val, colorPalette) {
122
+ for (const g of colorPalette) {
123
+ const found = g.colors.find((c) => c.val === val);
124
+ if (found) return `${g.group}\xB7${found.label}`;
125
+ }
126
+ return null;
127
+ }
128
+ function getTypographyToken(fontSize, fontWeight, color, typographyTokens) {
129
+ const normalizedColor = normalizeColor(color);
130
+ return typographyTokens.find(
131
+ (token) => token.fontSize === fontSize.trim() && token.fontWeight === fontWeight.trim() && normalizeColor(token.color) === normalizedColor
132
+ ) ?? null;
133
+ }
134
+ var BORDER_STYLE_OPTIONS = [
135
+ { label: "\u2500", value: "solid", title: "\u5B9E\u7EBF" },
136
+ { label: "\u2504", value: "dashed", title: "\u865A\u7EBF" },
137
+ { label: "\u22EF", value: "dotted", title: "\u70B9\u7EBF" },
138
+ { label: "\u2715", value: "none", title: "\u65E0" }
139
+ ];
140
+ var SIZE_OPTIONS = [
141
+ { label: "Fill", mode: "fill", value: "100%" },
142
+ { label: "Hug", mode: "hug", value: "fit-content" },
143
+ { label: "Fixed", mode: "fixed" }
144
+ ];
145
+ function rgbToHex(rgb) {
146
+ const m = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
147
+ if (!m) return rgb;
148
+ return "#" + [m[1], m[2], m[3]].map((n) => parseInt(n).toString(16).padStart(2, "0")).join("");
149
+ }
150
+ function normalizeColor(val) {
151
+ const m = val.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
152
+ if (m) return "#" + [m[1], m[2], m[3]].map((n) => parseInt(n).toString(16).padStart(2, "0")).join("");
153
+ return val.trim();
154
+ }
155
+ function formatColorDisplay(val) {
156
+ const m = val.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)$/);
157
+ if (m) {
158
+ const hex = "#" + [m[1], m[2], m[3]].map((n) => parseInt(n).toString(16).padStart(2, "0")).join("");
159
+ const alpha = Math.round(parseFloat(m[4]) * 100);
160
+ return alpha < 100 ? `${hex} / ${alpha}%` : hex;
161
+ }
162
+ return val;
163
+ }
164
+ var shadowValueCache = /* @__PURE__ */ new Map();
165
+ var _copiedStyles = [];
166
+ function canonicalizeShadowValue(val) {
167
+ const raw = (val || "none").trim() || "none";
168
+ if (shadowValueCache.has(raw)) return shadowValueCache.get(raw);
169
+ if (typeof document === "undefined" || !document.body) return raw;
170
+ const probe = document.createElement("div");
171
+ probe.style.boxShadow = raw;
172
+ probe.style.position = "fixed";
173
+ probe.style.opacity = "0";
174
+ probe.style.pointerEvents = "none";
175
+ document.body.appendChild(probe);
176
+ const normalized = getComputedStyle(probe).boxShadow.trim() || raw;
177
+ probe.remove();
178
+ shadowValueCache.set(raw, normalized);
179
+ return normalized;
180
+ }
181
+ function formatShadowDisplay(val) {
182
+ if (!val || val === "none") return "none";
183
+ return val.replace(/\s+/g, " ");
184
+ }
185
+ function getShadowDisplay(val, authoredVal, shadowTokens) {
186
+ const authoredVar = authoredVal.match(/var\((--[^),\s]+)/)?.[1];
187
+ const normalized = canonicalizeShadowValue(val);
188
+ const matched = shadowTokens.find((token) => token.cssVar === authoredVar) ?? shadowTokens.find((token) => canonicalizeShadowValue(token.value) === normalized);
189
+ if (matched) {
190
+ return {
191
+ label: matched.label,
192
+ sub: matched.cssVar,
193
+ isHardcoded: false
194
+ };
195
+ }
196
+ return {
197
+ label: val === "none" ? "\u65E0" : "\u81EA\u5B9A\u4E49",
198
+ sub: formatShadowDisplay(val),
199
+ isHardcoded: val !== "none"
200
+ };
201
+ }
202
+ function getClasses(el) {
203
+ return Array.from(el.classList).filter((c) => !c.startsWith("di-"));
204
+ }
205
+ var STATE_CLASS_NAMES = /* @__PURE__ */ new Set([
206
+ "active",
207
+ "selected",
208
+ "current",
209
+ "open",
210
+ "expanded",
211
+ "collapsed",
212
+ "disabled",
213
+ "enabled",
214
+ "checked",
215
+ "focus",
216
+ "focused",
217
+ "hover",
218
+ "pressed",
219
+ "loading",
220
+ "error",
221
+ "success",
222
+ "warning"
223
+ ]);
224
+ function isStateClass(className) {
225
+ return STATE_CLASS_NAMES.has(className) || className.startsWith("is-") || className.startsWith("has-") || className.startsWith("state-") || className.endsWith("--active") || className.endsWith("--selected") || className.endsWith("--current") || className.endsWith("--open") || className.endsWith("--disabled");
226
+ }
227
+ function getComponentClasses(el) {
228
+ const componentClasses = getClasses(el).filter(
229
+ (c) => !isStateClass(c) && !/^lucide(-|$)/.test(c)
230
+ );
231
+ return componentClasses.length ? componentClasses : getClasses(el);
232
+ }
233
+ function getStateClasses(el) {
234
+ return getClasses(el).filter((c) => !/^lucide(-|$)/.test(c));
235
+ }
236
+ var UNSAFE_GLOBAL_TAGS = /* @__PURE__ */ new Set([
237
+ "a",
238
+ "aside",
239
+ "button",
240
+ "div",
241
+ "em",
242
+ "h1",
243
+ "h2",
244
+ "h3",
245
+ "h4",
246
+ "h5",
247
+ "h6",
248
+ "img",
249
+ "input",
250
+ "label",
251
+ "li",
252
+ "main",
253
+ "ol",
254
+ "p",
255
+ "path",
256
+ "section",
257
+ "span",
258
+ "strong",
259
+ "svg",
260
+ "textarea",
261
+ "ul"
262
+ ]);
263
+ function classSelector(classes) {
264
+ const escapeClass = (value) => {
265
+ try {
266
+ return CSS.escape(value);
267
+ } catch {
268
+ return value.replace(/[^a-zA-Z0-9_-]/g, "\\$&");
269
+ }
270
+ };
271
+ return classes.length ? "." + classes.map(escapeClass).join(".") : "";
272
+ }
273
+ function queryByClasses(el, classes) {
274
+ if (!classes.length) return [el];
275
+ const includePanels = !!el.closest(".di-panel");
276
+ try {
277
+ return Array.from(document.querySelectorAll(classSelector(classes))).filter((e) => includePanels || !e.closest(".di-panel"));
278
+ } catch {
279
+ return [el];
280
+ }
281
+ }
282
+ function getSameComponentEls(el) {
283
+ return queryByClasses(el, getComponentClasses(el));
284
+ }
285
+ function getScopeTargets(el, scope) {
286
+ if (scope === "component") return getSameComponentEls(el);
287
+ return [el];
288
+ }
289
+ function getClassSelectorForScope(el, scope) {
290
+ const classes = scope === "component" ? getComponentClasses(el) : getStateClasses(el);
291
+ return classSelector(classes) || el.tagName.toLowerCase();
292
+ }
293
+ function getStructuralStep(el) {
294
+ const tag = el.tagName.toLowerCase();
295
+ const parent = el.parentElement;
296
+ if (!parent) return tag;
297
+ const sameTagSiblings = Array.from(parent.children).filter((child) => child.tagName === el.tagName);
298
+ if (sameTagSiblings.length <= 1) return tag;
299
+ return `${tag}:nth-of-type(${sameTagSiblings.indexOf(el) + 1})`;
300
+ }
301
+ function getContextualSelectorForScope(el, scope) {
302
+ let anchor = el.parentElement;
303
+ while (anchor && !getClasses(anchor).length) anchor = anchor.parentElement;
304
+ if (!anchor) return "";
305
+ const anchorSelector = getClassSelectorForScope(anchor, scope);
306
+ const path = [];
307
+ let cursor = el;
308
+ while (cursor && cursor !== anchor) {
309
+ path.unshift(getStructuralStep(cursor));
310
+ cursor = cursor.parentElement;
311
+ }
312
+ return path.length ? `${anchorSelector} > ${path.join(" > ")}` : anchorSelector;
313
+ }
314
+ function getSelectorForScope(el, scope) {
315
+ const classes = scope === "component" ? getComponentClasses(el) : getStateClasses(el);
316
+ if (classes.length) return classSelector(classes);
317
+ const tag = el.tagName.toLowerCase();
318
+ if (!UNSAFE_GLOBAL_TAGS.has(tag)) return tag;
319
+ const contextualSelector = getContextualSelectorForScope(el, scope);
320
+ return contextualSelector || tag;
321
+ }
322
+ function canPersistSelector(el, scope) {
323
+ const classes = scope === "component" ? getComponentClasses(el) : getStateClasses(el);
324
+ if (classes.length) return true;
325
+ if (el.classList.contains("lucide") || Array.from(el.classList).some((c) => /^lucide-/.test(c))) {
326
+ return getContextualSelectorForScope(el, scope).length > 0;
327
+ }
328
+ const tag = el.tagName.toLowerCase();
329
+ if (!UNSAFE_GLOBAL_TAGS.has(tag)) return true;
330
+ return getContextualSelectorForScope(el, scope).length > 0;
331
+ }
332
+ function isInsidePanel(el) {
333
+ return el.closest(".di-panel") !== null || el.closest(".di-trigger") !== null || el.closest(".di-label") !== null;
334
+ }
335
+ function scanTokenMap() {
336
+ const map = {};
337
+ try {
338
+ for (const sheet of Array.from(document.styleSheets)) {
339
+ try {
340
+ for (const rule of Array.from(sheet.cssRules)) {
341
+ if (rule instanceof CSSStyleRule && rule.selectorText === ":root") {
342
+ for (let i = 0; i < rule.style.length; i++) {
343
+ const prop = rule.style[i];
344
+ if (!prop.startsWith("--")) continue;
345
+ const raw = rule.style.getPropertyValue(prop).trim();
346
+ const hex = raw.startsWith("rgb") ? rgbToHex(raw) : raw;
347
+ map[raw] = prop;
348
+ if (hex !== raw) map[hex] = prop;
349
+ }
350
+ }
351
+ }
352
+ } catch {
353
+ }
354
+ }
355
+ } catch {
356
+ }
357
+ return map;
358
+ }
359
+ function getComputedColor(el, prop) {
360
+ return normalizeColor(getComputedStyle(el).getPropertyValue(prop).trim());
361
+ }
362
+ function getComputedRadius(el) {
363
+ return getComputedStyle(el).getPropertyValue("border-radius").trim();
364
+ }
365
+ function parseTranslate(val) {
366
+ const raw = (val || "none").trim();
367
+ if (!raw || raw === "none") return { x: 0, y: 0 };
368
+ const parts = raw.split(/\s+/);
369
+ const toNum = (v) => v ? Number.parseFloat(v) || 0 : 0;
370
+ return { x: toNum(parts[0]), y: toNum(parts[1]) };
371
+ }
372
+ function formatTranslate(pos) {
373
+ return `${Math.round(pos.x)}px ${Math.round(pos.y)}px`;
374
+ }
375
+ function normalizeCssSize(v) {
376
+ const raw = v.trim();
377
+ if (!raw) return "auto";
378
+ if (/^-?\d+(\.\d+)?$/.test(raw)) return `${raw}px`;
379
+ const appendedPxNumber = raw.match(/px(-?\d+(?:\.\d+)?)$/i);
380
+ if (appendedPxNumber) return `${appendedPxNumber[1]}px`;
381
+ return raw;
382
+ }
383
+ function getAuthoredStyleValue(el, prop) {
384
+ const inline = el.style.getPropertyValue(prop).trim();
385
+ if (inline) return inline;
386
+ let found = "";
387
+ try {
388
+ for (const sheet of Array.from(document.styleSheets)) {
389
+ try {
390
+ for (const rule of Array.from(sheet.cssRules)) {
391
+ if (!(rule instanceof CSSStyleRule)) continue;
392
+ if (!rule.style.getPropertyValue(prop)) continue;
393
+ if (el.matches(rule.selectorText)) found = rule.style.getPropertyValue(prop).trim();
394
+ }
395
+ } catch {
396
+ }
397
+ }
398
+ } catch {
399
+ }
400
+ return found;
401
+ }
402
+ function inferSizeMode(el, axis, computedSize) {
403
+ const cs = getComputedStyle(el);
404
+ const authored = getAuthoredStyleValue(el, axis).toLowerCase();
405
+ const display = cs.display.trim();
406
+ const flexGrow = Number.parseFloat(cs.flexGrow) || 0;
407
+ if (authored) {
408
+ if (authored === "auto") return axis === "height" ? "hug" : "fill";
409
+ if (authored.includes("fit-content") || authored.includes("max-content") || authored.includes("min-content")) return "hug";
410
+ if (authored.includes("%") || authored.includes("vw") || authored.includes("vh") || flexGrow > 0) return "fill";
411
+ return "fixed";
412
+ }
413
+ if (axis === "width") {
414
+ if (flexGrow > 0) return "fill";
415
+ if (display === "block" && el.parentElement) {
416
+ const parentWidth = el.parentElement.getBoundingClientRect().width;
417
+ const selfWidth = el.getBoundingClientRect().width;
418
+ if (parentWidth > 0 && selfWidth / parentWidth > 0.88) return "fill";
419
+ }
420
+ if (display.startsWith("inline")) return "hug";
421
+ }
422
+ if (axis === "height" && !getAuthoredStyleValue(el, "min-height") && computedSize !== "0px") {
423
+ return "hug";
424
+ }
425
+ return "fixed";
426
+ }
427
+ function sizeValueForMode(mode, current) {
428
+ if (mode === "fill") return "100%";
429
+ if (mode === "hug") return "fit-content";
430
+ return current || "0px";
431
+ }
432
+ function displaySizeValue(cssValue, current) {
433
+ if (!cssValue || cssValue === "100%" || cssValue === "fit-content") return current || "0px";
434
+ return cssValue;
435
+ }
436
+ function getOneLineHugHeight(el) {
437
+ if (!(el instanceof HTMLElement)) return 0;
438
+ const hasText = (el.textContent ?? "").trim().length > 0;
439
+ const isTextControl = el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLButtonElement;
440
+ if (!hasText && !isTextControl) return 0;
441
+ const cs = getComputedStyle(el);
442
+ const fontSize = Number.parseFloat(cs.fontSize) || 0;
443
+ const lineHeight = cs.lineHeight === "normal" ? fontSize * 1.2 : Number.parseFloat(cs.lineHeight) || fontSize * 1.2;
444
+ const paddingY = (Number.parseFloat(cs.paddingTop) || 0) + (Number.parseFloat(cs.paddingBottom) || 0);
445
+ const borderY = (Number.parseFloat(cs.borderTopWidth) || 0) + (Number.parseFloat(cs.borderBottomWidth) || 0);
446
+ return Math.ceil(lineHeight + paddingY + borderY);
447
+ }
448
+ function clampHeightToOneLine(cssValue, el) {
449
+ const px = cssValue.match(/^(-?\d+(?:\.\d+)?)px$/i);
450
+ if (!px) return cssValue;
451
+ const minH = getOneLineHugHeight(el);
452
+ if (!minH) return cssValue;
453
+ return `${Math.max(Number.parseFloat(px[1]), minH)}px`;
454
+ }
455
+ function calcPanelPos(rect) {
456
+ const W = 380;
457
+ const maxH = window.innerHeight * 0.9;
458
+ let left = rect.right + 16;
459
+ let top = rect.top;
460
+ if (left + W > window.innerWidth - 8) left = Math.max(8, rect.left - W - 16);
461
+ top = Math.min(top, window.innerHeight - maxH - 8);
462
+ top = Math.max(8, top);
463
+ return { top, left };
464
+ }
465
+ function matchPreset(presets, val) {
466
+ const px = val.replace(/\s/g, "");
467
+ return presets.find((p) => p.value === px || p.value === val) ?? null;
468
+ }
469
+ function resizeTextareaToContent(el) {
470
+ el.style.height = "auto";
471
+ el.style.height = `${el.scrollHeight}px`;
472
+ }
473
+ function SideInput({
474
+ value,
475
+ onChange,
476
+ spaceSteps,
477
+ wide,
478
+ compact
479
+ }) {
480
+ const [focused, setFocused] = (0, import_react2.useState)(false);
481
+ const [draft, setDraft] = (0, import_react2.useState)("");
482
+ const [popupPos, setPopupPos] = (0, import_react2.useState)({ top: 0, left: 0 });
483
+ const triggerRef = (0, import_react2.useRef)(null);
484
+ const step = spaceSteps.find((s) => s.val === value);
485
+ const displayLabel = step && step.label !== "\u65E0" ? step.label : value === "0px" ? "0" : value;
486
+ const displaySub = step && step.label !== "\u65E0" ? value : null;
487
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `di-side-combo${wide ? " di-side-combo--wide" : ""}${compact ? " di-side-combo--compact" : ""}`, children: [
488
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-side-display", ref: triggerRef, onClick: () => {
489
+ if (triggerRef.current) {
490
+ const r = triggerRef.current.getBoundingClientRect();
491
+ setPopupPos({ top: r.bottom + 4, left: wide ? r.left : r.left + r.width / 2 });
492
+ }
493
+ setFocused(true);
494
+ setDraft(value);
495
+ }, children: [
496
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-side-display-label", children: displayLabel }),
497
+ displaySub && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-side-display-sub", children: displaySub })
498
+ ] }),
499
+ focused && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-side-overlay", onClick: () => setFocused(false) }),
501
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-side-popup", style: { top: popupPos.top, left: popupPos.left, transform: wide ? "none" : "translateX(-50%)" }, children: [
502
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
503
+ "input",
504
+ {
505
+ className: "di-side-input-edit",
506
+ value: draft,
507
+ autoFocus: true,
508
+ onChange: (e) => setDraft(e.target.value),
509
+ onKeyDown: (e) => {
510
+ if (e.key === "Enter") {
511
+ const s = spaceSteps.find((s2) => s2.label.toLowerCase() === draft.toLowerCase());
512
+ onChange(s ? s.val : draft || "0px");
513
+ setFocused(false);
514
+ }
515
+ if (e.key === "Escape") setFocused(false);
516
+ },
517
+ placeholder: "\u8F93\u5165\u6570\u503C\u2026"
518
+ }
519
+ ),
520
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-side-steps", children: spaceSteps.map((s) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
521
+ "button",
522
+ {
523
+ className: `di-side-step-item${value === s.val ? " di-side-step-item--on" : ""}`,
524
+ onMouseDown: (e) => {
525
+ e.preventDefault();
526
+ onChange(s.val);
527
+ setFocused(false);
528
+ },
529
+ children: [
530
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: s.label }),
531
+ s.val !== "0px" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-side-step-sub", children: s.val })
532
+ ]
533
+ },
534
+ s.val
535
+ )) })
536
+ ] })
537
+ ] })
538
+ ] });
539
+ }
540
+ function parseFourSides(val) {
541
+ const p = (val || "0px").trim().split(/\s+/);
542
+ if (p.length === 1) return { top: p[0], right: p[0], bottom: p[0], left: p[0] };
543
+ if (p.length === 2) return { top: p[0], right: p[1], bottom: p[0], left: p[1] };
544
+ if (p.length === 3) return { top: p[0], right: p[1], bottom: p[2], left: p[1] };
545
+ return { top: p[0], right: p[1], bottom: p[2], left: p[3] };
546
+ }
547
+ function joinFourSides(s) {
548
+ if (s.top === s.right && s.right === s.bottom && s.bottom === s.left) return s.top;
549
+ if (s.top === s.bottom && s.left === s.right) return `${s.top} ${s.right}`;
550
+ return `${s.top} ${s.right} ${s.bottom} ${s.left}`;
551
+ }
552
+ function SpaceCard({ title, variant, value, onChange, spaceSteps }) {
553
+ if (variant === "gap") {
554
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-space-card", children: [
555
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-space-head", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-space-title", children: title }) }),
556
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-gap-input-row", children: [
557
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-gap-block" }),
558
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SideInput, { value, onChange, spaceSteps, wide: true }),
559
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-gap-block" })
560
+ ] })
561
+ ] });
562
+ }
563
+ const sides = parseFourSides(value);
564
+ function updateSide(side, v) {
565
+ const next = { ...sides, [side]: v };
566
+ onChange(joinFourSides(next));
567
+ }
568
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-space-card", children: [
569
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-space-head", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-space-title", children: title }) }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `di-boxing di-boxing--${variant}`, children: [
571
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-box-top", children: [
572
+ " ",
573
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SideInput, { value: sides.top, onChange: (v) => updateSide("top", v), spaceSteps, compact: true })
574
+ ] }),
575
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-box-left", children: [
576
+ " ",
577
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SideInput, { value: sides.left, onChange: (v) => updateSide("left", v), spaceSteps, compact: true })
578
+ ] }),
579
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-box-center", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-boxing-block" }) }),
580
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-box-right", children: [
581
+ " ",
582
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SideInput, { value: sides.right, onChange: (v) => updateSide("right", v), spaceSteps, compact: true })
583
+ ] }),
584
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-box-bottom", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SideInput, { value: sides.bottom, onChange: (v) => updateSide("bottom", v), spaceSteps, compact: true }) })
585
+ ] })
586
+ ] });
587
+ }
588
+ function getTextContent(el) {
589
+ const text = Array.from(el.childNodes).filter((n) => n.nodeType === Node.TEXT_NODE).map((n) => n.textContent ?? "").join("").trim();
590
+ return text.length > 0 ? el.textContent?.trim() ?? null : null;
591
+ }
592
+ var TOKEN_TYPES = [
593
+ { key: "bg", label: "\u80CC\u666F\u8272", code: "bg" },
594
+ { key: "text", label: "\u6587\u5B57\u8272", code: "text" },
595
+ { key: "accent", label: "\u5F3A\u8C03\u8272", code: "accent" },
596
+ { key: "border", label: "\u8FB9\u6846\u8272", code: "border" }
597
+ ];
598
+ var TOKEN_COMPONENTS = [
599
+ { key: "global", label: "\u5168\u5C40", code: "global" },
600
+ { key: "sidebar", label: "\u4FA7\u8FB9\u680F", code: "sidebar" },
601
+ { key: "button", label: "\u6309\u94AE", code: "button" },
602
+ { key: "card", label: "\u5361\u7247", code: "card" },
603
+ { key: "tag", label: "\u6807\u7B7E", code: "tag" },
604
+ { key: "input", label: "\u8F93\u5165\u6846", code: "input" }
605
+ ];
606
+ var TOKEN_STATES = [
607
+ { key: "default", label: "\u9ED8\u8BA4\u6001", code: "default" },
608
+ { key: "hover", label: "\u60AC\u6D6E\u6001", code: "hover" },
609
+ { key: "active", label: "\u6FC0\u6D3B\u6001", code: "active" },
610
+ { key: "disabled", label: "\u7981\u7528\u6001", code: "disabled" },
611
+ { key: "success", label: "\u6210\u529F\u6001", code: "success" },
612
+ { key: "warning", label: "\u8B66\u544A\u6001", code: "warning" }
613
+ ];
614
+ function ColorDropdown({ value, onChange, onClose, onAddToken, pos, colorPalette }) {
615
+ const initHex = value.startsWith("#") ? value : "#6b7280";
616
+ const [hexInput, setHexInput] = (0, import_react2.useState)(initHex);
617
+ const [alpha, setAlpha] = (0, import_react2.useState)(100);
618
+ function buildColor(hex, a) {
619
+ const m = hex.match(/^#([0-9a-f]{6})$/i);
620
+ if (!m || a >= 100) return hex;
621
+ const r = parseInt(m[1].slice(0, 2), 16), g = parseInt(m[1].slice(2, 4), 16), b = parseInt(m[1].slice(4, 6), 16);
622
+ return `rgba(${r},${g},${b},${(a / 100).toFixed(2)})`;
623
+ }
624
+ function applyColor(hex, a) {
625
+ onChange(buildColor(hex, a), "");
626
+ }
627
+ const style = pos ? { position: "fixed", top: pos.top, left: pos.left, zIndex: 99998 } : {};
628
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
629
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "fixed", inset: 0, zIndex: 99997 }, onClick: onClose }),
630
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-palette-dropdown", style, children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-palette-group", children: [
632
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-palette-group-label", children: "\u65E0" }),
633
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-palette-swatches", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
634
+ "button",
635
+ {
636
+ className: "di-palette-none",
637
+ title: "\u65E0\u80CC\u666F\u8272 / transparent",
638
+ onClick: () => {
639
+ onChange("transparent", "");
640
+ onClose();
641
+ }
642
+ }
643
+ ) })
644
+ ] }),
645
+ colorPalette.map((g) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-palette-group", children: [
646
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-palette-group-label", children: g.group }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-palette-swatches", children: [
648
+ g.colors.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
649
+ "button",
650
+ {
651
+ className: `di-palette-swatch${value === c.val ? " di-palette-swatch--on" : ""}`,
652
+ style: { background: c.val },
653
+ title: `${g.group}\xB7${c.label} ${c.val}`,
654
+ onClick: () => {
655
+ onChange(c.val, c.token);
656
+ onClose();
657
+ }
658
+ },
659
+ c.token
660
+ )),
661
+ onAddToken && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
662
+ "button",
663
+ {
664
+ className: "di-palette-add-btn",
665
+ title: `\u6DFB\u52A0\u4E3A${g.group}\u8272 token`,
666
+ onClick: () => {
667
+ onAddToken(buildColor(hexInput, alpha));
668
+ onClose();
669
+ },
670
+ children: "+"
671
+ }
672
+ )
673
+ ] })
674
+ ] }, g.group)),
675
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-custom-bottom", children: [
676
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
677
+ "button",
678
+ {
679
+ className: "di-custom-color-trigger",
680
+ style: { background: buildColor(hexInput, alpha), flexShrink: 0 },
681
+ onClick: () => {
682
+ }
683
+ }
684
+ ),
685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-field-wrap", children: [
686
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-field-prefix", children: "#" }),
687
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
688
+ "input",
689
+ {
690
+ className: "di-field-input",
691
+ value: hexInput.replace(/^#/, ""),
692
+ placeholder: "ffffff",
693
+ onChange: (e) => {
694
+ const h = "#" + e.target.value;
695
+ setHexInput(h);
696
+ applyColor(h, alpha);
697
+ },
698
+ onBlur: (e) => {
699
+ if (!/^[0-9a-f]{6}$/i.test(e.target.value)) setHexInput(initHex);
700
+ }
701
+ }
702
+ )
703
+ ] }),
704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-field-wrap di-field-wrap--fixed", children: [
705
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
706
+ "input",
707
+ {
708
+ className: "di-field-input di-field-input--num",
709
+ type: "number",
710
+ min: "0",
711
+ max: "100",
712
+ value: alpha,
713
+ onChange: (e) => {
714
+ const a = Math.min(100, Math.max(0, +e.target.value || 0));
715
+ setAlpha(a);
716
+ applyColor(hexInput, a);
717
+ }
718
+ }
719
+ ),
720
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-field-suffix", children: "%" })
721
+ ] })
722
+ ] })
723
+ ] })
724
+ ] });
725
+ }
726
+ function inferType(cssProp) {
727
+ if (!cssProp) return "bg";
728
+ if (cssProp === "color") return "text";
729
+ if (cssProp.includes("border")) return "border";
730
+ if (cssProp.includes("background")) return "bg";
731
+ return "accent";
732
+ }
733
+ function inferComponent(classes) {
734
+ const joined = classes.join(" ").toLowerCase();
735
+ if (/sidebar|nav-item|nav/.test(joined)) return "sidebar";
736
+ if (/button|btn|start/.test(joined)) return "button";
737
+ if (/card/.test(joined)) return "card";
738
+ if (/tag|badge|chip/.test(joined)) return "tag";
739
+ if (/input|field|form/.test(joined)) return "input";
740
+ return "global";
741
+ }
742
+ function inferState(classes) {
743
+ const joined = classes.join(" ").toLowerCase();
744
+ if (/is-active|active|is-current|current/.test(joined)) return "active";
745
+ if (/disabled/.test(joined)) return "disabled";
746
+ if (/hover/.test(joined)) return "hover";
747
+ if (/success/.test(joined)) return "success";
748
+ if (/warning/.test(joined)) return "warning";
749
+ return "default";
750
+ }
751
+ function AddTokenModal({ value, cssProp, elementClasses, onClose, onConfirm, colorPalette }) {
752
+ const [mode, setMode] = (0, import_react2.useState)("new");
753
+ const [type, setType] = (0, import_react2.useState)(() => inferType(cssProp));
754
+ const [component, setComponent] = (0, import_react2.useState)(() => inferComponent(elementClasses ?? []));
755
+ const [state, setState] = (0, import_react2.useState)(() => inferState(elementClasses ?? []));
756
+ const [replaceTarget, setReplaceTarget] = (0, import_react2.useState)("");
757
+ const allTokens = colorPalette.flatMap((g) => g.colors);
758
+ const typeObj = TOKEN_TYPES.find((t) => t.key === type);
759
+ const componentObj = TOKEN_COMPONENTS.find((c) => c.key === component);
760
+ const stateObj = TOKEN_STATES.find((s) => s.key === state);
761
+ const generatedVar = mode === "new" ? `--color-${typeObj.code}-${componentObj.code}-${stateObj.code}` : replaceTarget;
762
+ const BtnGroup = ({ items, active, onSelect }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: items.map((i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
763
+ "button",
764
+ {
765
+ className: `di-modal-opt-btn${active === i.key ? " --on" : ""}`,
766
+ onClick: () => onSelect(i.key),
767
+ children: i.label
768
+ },
769
+ i.key
770
+ )) });
771
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-modal-overlay", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal", onClick: (e) => e.stopPropagation(), children: [
772
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-header", children: [
773
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-modal-swatch", style: { background: value } }),
774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-modal-hex", children: value }),
775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { flex: 1 } }),
776
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 12, color: "#6b7280" }, children: "\u6DFB\u52A0\u4E3A token" })
777
+ ] }),
778
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-body", children: [
779
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-modal-tabs", children: [{ k: "new", l: "\u65B0\u5EFA token" }, { k: "replace", l: "\u66FF\u6362\u5DF2\u6709 token" }].map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
780
+ "button",
781
+ {
782
+ className: `di-modal-tab${mode === m.k ? " --on" : ""}`,
783
+ onClick: () => setMode(m.k),
784
+ children: m.l
785
+ },
786
+ m.k
787
+ )) }),
788
+ mode === "new" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
789
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field", children: [
790
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field-label", children: [
791
+ "\u989C\u8272\u7C7B\u578B ",
792
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-modal-auto-tag", children: "\u81EA\u52A8\u8BC6\u522B" })
793
+ ] }),
794
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BtnGroup, { items: TOKEN_TYPES, active: type, onSelect: setType })
795
+ ] }),
796
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field", children: [
797
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field-label", children: [
798
+ "\u7EC4\u4EF6 ",
799
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-modal-auto-tag", children: "\u81EA\u52A8\u8BC6\u522B" })
800
+ ] }),
801
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BtnGroup, { items: TOKEN_COMPONENTS, active: component, onSelect: setComponent })
802
+ ] }),
803
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field", children: [
804
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field-label", children: [
805
+ "\u7528\u9014 / \u72B6\u6001 ",
806
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-modal-auto-tag", children: "\u81EA\u52A8\u63A8\u65AD\uFF0C\u53EF\u6539" })
807
+ ] }),
808
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BtnGroup, { items: TOKEN_STATES, active: state, onSelect: setState })
809
+ ] })
810
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-field", children: [
811
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-modal-field-label", children: "\u9009\u62E9\u8981\u66FF\u6362\u7684 token" }),
812
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
813
+ "select",
814
+ {
815
+ className: "di-modal-select",
816
+ value: replaceTarget,
817
+ onChange: (e) => setReplaceTarget(e.target.value),
818
+ children: [
819
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "\u8BF7\u9009\u62E9\u2026" }),
820
+ allTokens.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: c.token, children: [
821
+ c.token,
822
+ "\uFF08",
823
+ c.val,
824
+ "\uFF09"
825
+ ] }, c.token))
826
+ ]
827
+ }
828
+ )
829
+ ] }),
830
+ generatedVar && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-result", children: [
831
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-modal-result-label", children: "\u7CFB\u7EDF\u751F\u6210 token \u540D\u79F0" }),
832
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-modal-result-var", children: generatedVar }),
833
+ mode === "new" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-result-trail", children: [
834
+ typeObj.label,
835
+ " \u2192 ",
836
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: typeObj.code }),
837
+ "\u2002",
838
+ componentObj.label,
839
+ " \u2192 ",
840
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: componentObj.code }),
841
+ "\u2002",
842
+ stateObj.label,
843
+ " \u2192 ",
844
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: stateObj.code })
845
+ ] })
846
+ ] })
847
+ ] }),
848
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-modal-foot", children: [
849
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-modal-cancel", onClick: onClose, children: "\u53D6\u6D88" }),
850
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
851
+ "button",
852
+ {
853
+ className: "di-modal-ok",
854
+ disabled: !generatedVar,
855
+ onClick: () => {
856
+ if (generatedVar) {
857
+ onConfirm(generatedVar, value, type);
858
+ onClose();
859
+ }
860
+ },
861
+ children: "\u786E\u8BA4\u521B\u5EFA"
862
+ }
863
+ )
864
+ ] })
865
+ ] }) });
866
+ }
867
+ function getDisplayLabel(val, tokenMap, colorPalette, tokenLabels) {
868
+ const displayVal = formatColorDisplay(val);
869
+ const paletteLabel = getColorLabel(val, colorPalette);
870
+ if (paletteLabel) return { label: paletteLabel, sub: displayVal, isHardcoded: false };
871
+ const token = tokenMap[val];
872
+ if (token) return { label: tokenLabels[token] ?? token.replace("--", ""), sub: displayVal, isHardcoded: false };
873
+ return { label: displayVal, sub: "", isHardcoded: true };
874
+ }
875
+ function InspectorPanel({
876
+ targetEl,
877
+ tokenMap,
878
+ onTokenMapUpdate,
879
+ onClose
880
+ }) {
881
+ const isSecondary = false;
882
+ const { endpoints, tokens } = useDevInspectorConfig();
883
+ const {
884
+ colorPalette,
885
+ tokenLabels,
886
+ radiusPresets,
887
+ spaceSteps,
888
+ borderWidthSteps,
889
+ fontSizeOptions,
890
+ fontWeightOptions,
891
+ shadowTokens,
892
+ typographyTokens
893
+ } = tokens;
894
+ const shadowOptions = [
895
+ { cssVar: "", value: "none", label: "\u65E0", usage: "\u4E0D\u4F7F\u7528\u9634\u5F71" },
896
+ ...shadowTokens
897
+ ];
898
+ const [isEditing, setIsEditing] = (0, import_react2.useState)(false);
899
+ const panelElRef = (0, import_react2.useRef)(null);
900
+ const [selected, setSelected] = (0, import_react2.useState)(targetEl);
901
+ const [panelPos, setPanelPos] = (0, import_react2.useState)(() => calcPanelPos(targetEl.getBoundingClientRect()));
902
+ const dragRef = (0, import_react2.useRef)(null);
903
+ const modalOpenRef = (0, import_react2.useRef)(false);
904
+ const [colors, setColors] = (0, import_react2.useState)({});
905
+ const [radiusVal, setRadiusVal] = (0, import_react2.useState)("");
906
+ const [paddingVal, setPaddingVal] = (0, import_react2.useState)("0px");
907
+ const [marginVal, setMarginVal] = (0, import_react2.useState)("0px");
908
+ const [gapVal, setGapVal] = (0, import_react2.useState)("0px");
909
+ const [translateVal, setTranslateVal] = (0, import_react2.useState)({ x: 0, y: 0 });
910
+ const [widthVal, setWidthVal] = (0, import_react2.useState)("");
911
+ const [heightVal, setHeightVal] = (0, import_react2.useState)("");
912
+ const [widthMode, setWidthMode] = (0, import_react2.useState)("fixed");
913
+ const [heightMode, setHeightMode] = (0, import_react2.useState)("hug");
914
+ const [customRadius, setCustomRadius] = (0, import_react2.useState)("");
915
+ const [scope, setScope] = (0, import_react2.useState)("current");
916
+ const [note, setNote] = (0, import_react2.useState)("");
917
+ const [textContent, setTextContent] = (0, import_react2.useState)(null);
918
+ const [pendingColors, setPendingColors] = (0, import_react2.useState)({});
919
+ const [pendingRadius, setPendingRadius] = (0, import_react2.useState)("");
920
+ const [shadowVal, setShadowVal] = (0, import_react2.useState)("none");
921
+ const [shadowAuthoredVal, setShadowAuthoredVal] = (0, import_react2.useState)("");
922
+ const [pendingShadow, setPendingShadow] = (0, import_react2.useState)("");
923
+ const [borderColorVal, setBorderColorVal] = (0, import_react2.useState)("");
924
+ const [borderWidthVal, setBorderWidthVal] = (0, import_react2.useState)("0px");
925
+ const [borderStyleVal, setBorderStyleVal] = (0, import_react2.useState)("none");
926
+ const [pendingBorderColor, setPendingBorderColor] = (0, import_react2.useState)("");
927
+ const [pendingBorderWidth, setPendingBorderWidth] = (0, import_react2.useState)("");
928
+ const [pendingBorderStyle, setPendingBorderStyle] = (0, import_react2.useState)("");
929
+ const [expandedBorderColor, setExpandedBorderColor] = (0, import_react2.useState)(false);
930
+ const [showShadowDrop, setShowShadowDrop] = (0, import_react2.useState)(false);
931
+ const [showStyleDrop, setShowStyleDrop] = (0, import_react2.useState)(false);
932
+ const [showWeightDrop, setShowWeightDrop] = (0, import_react2.useState)(false);
933
+ const [showFontSizeDrop, setShowFontSizeDrop] = (0, import_react2.useState)(false);
934
+ const [showScopeHelp, setShowScopeHelp] = (0, import_react2.useState)(false);
935
+ const [dropPos, setDropPos] = (0, import_react2.useState)({ top: 0, left: 0 });
936
+ const [fontSizeVal, setFontSizeVal] = (0, import_react2.useState)("");
937
+ const [fontWeightVal, setFontWeightVal] = (0, import_react2.useState)("");
938
+ const [textColorVal, setTextColorVal] = (0, import_react2.useState)("");
939
+ const [fontSizeCustomDraft, setFontSizeCustomDraft] = (0, import_react2.useState)("");
940
+ const [expandedTextColor, setExpandedTextColor] = (0, import_react2.useState)(false);
941
+ const [pendingFontSize, setPendingFontSize] = (0, import_react2.useState)("");
942
+ const [pendingFontWeight, setPendingFontWeight] = (0, import_react2.useState)("");
943
+ const [pendingTextColor, setPendingTextColor] = (0, import_react2.useState)("");
944
+ const [pendingPadding, setPendingPadding] = (0, import_react2.useState)("");
945
+ const [pendingMargin, setPendingMargin] = (0, import_react2.useState)("");
946
+ const [pendingGap, setPendingGap] = (0, import_react2.useState)("");
947
+ const [pendingTranslate, setPendingTranslate] = (0, import_react2.useState)(null);
948
+ const [pendingWidth, setPendingWidth] = (0, import_react2.useState)("");
949
+ const [pendingHeight, setPendingHeight] = (0, import_react2.useState)("");
950
+ const [pendingWidthMode, setPendingWidthMode] = (0, import_react2.useState)(null);
951
+ const [pendingHeightMode, setPendingHeightMode] = (0, import_react2.useState)(null);
952
+ const [sizeDraft, setSizeDraft] = (0, import_react2.useState)({});
953
+ const [newTokenProp, setNewTokenProp] = (0, import_react2.useState)(null);
954
+ const [newTokenName, setNewTokenName] = (0, import_react2.useState)("");
955
+ const [saveMsg, setSaveMsg] = (0, import_react2.useState)("");
956
+ const [copyMsg, setCopyMsg] = (0, import_react2.useState)("");
957
+ const [submitMsg, setSubmitMsg] = (0, import_react2.useState)("");
958
+ const [styleIntentSummary, setStyleIntentSummary] = (0, import_react2.useState)({ pendingCount: 0, latestPending: null, pendingEntries: [] });
959
+ const [hasCopied, setHasCopied] = (0, import_react2.useState)(() => _copiedStyles.length > 0);
960
+ const [expandedColor, setExpandedColor] = (0, import_react2.useState)(null);
961
+ const [pendingNewToken, setPendingNewToken] = (0, import_react2.useState)(null);
962
+ const [addTokenModal, setAddTokenModal] = (0, import_react2.useState)(null);
963
+ const [customColorVals, setCustomColorVals] = (0, import_react2.useState)({});
964
+ const selectedRef = (0, import_react2.useRef)(targetEl);
965
+ const gapTargetRef = (0, import_react2.useRef)(null);
966
+ (0, import_react2.useEffect)(() => {
967
+ modalOpenRef.current = addTokenModal !== null;
968
+ }, [addTokenModal]);
969
+ const formatStyleIntentSummary = (0, import_react2.useCallback)((r) => ({
970
+ pendingCount: r.pendingCount ?? 0,
971
+ latestPending: r.latestPending ? {
972
+ id: r.latestPending.id,
973
+ targetLabel: r.latestPending.targetLabel,
974
+ selector: r.latestPending.selector,
975
+ createdAt: r.latestPending.createdAt,
976
+ note: r.latestPending.note,
977
+ entries: r.latestPending.entries ?? []
978
+ } : null,
979
+ pendingEntries: Array.isArray(r.pendingEntries) ? r.pendingEntries.map((entry) => ({
980
+ id: entry.id,
981
+ targetLabel: entry.targetLabel,
982
+ selector: entry.selector,
983
+ createdAt: entry.createdAt,
984
+ note: entry.note,
985
+ entries: entry.entries ?? []
986
+ })) : []
987
+ }), []);
988
+ const refreshStyleIntentSummary = (0, import_react2.useCallback)(() => {
989
+ fetch(endpoints.styleIntents).then((r) => r.json()).then((r) => {
990
+ if (r.ok) {
991
+ setStyleIntentSummary(formatStyleIntentSummary(r));
992
+ }
993
+ }).catch(() => {
994
+ });
995
+ }, [endpoints.styleIntents, formatStyleIntentSummary]);
996
+ (0, import_react2.useEffect)(() => {
997
+ refreshStyleIntentSummary();
998
+ }, [refreshStyleIntentSummary]);
999
+ const selectEl = (0, import_react2.useCallback)((el) => {
1000
+ selectedRef.current = el;
1001
+ const rect = el.getBoundingClientRect();
1002
+ setPanelPos(calcPanelPos(rect));
1003
+ const elCs = getComputedStyle(el);
1004
+ const c = {};
1005
+ for (const { prop } of COLOR_PROPS) {
1006
+ const val = getComputedColor(el, prop);
1007
+ if (!val || val === "rgba(0, 0, 0, 0)" || val === "transparent") continue;
1008
+ if (prop === "border-color" && elCs.borderWidth.trim() === "0px") continue;
1009
+ c[prop] = val;
1010
+ }
1011
+ setColors(c);
1012
+ setPendingColors({});
1013
+ setFontSizeVal(elCs.fontSize.trim());
1014
+ setFontWeightVal(elCs.fontWeight.trim());
1015
+ setTextColorVal(normalizeColor(elCs.color.trim()));
1016
+ setFontSizeCustomDraft(elCs.fontSize.trim());
1017
+ setPendingFontSize("");
1018
+ setPendingFontWeight("");
1019
+ setPendingTextColor("");
1020
+ setExpandedTextColor(false);
1021
+ const bw = elCs.borderTopWidth.trim();
1022
+ const bs = elCs.borderTopStyle.trim();
1023
+ const bc = normalizeColor(elCs.borderTopColor.trim());
1024
+ setBorderWidthVal(bw);
1025
+ setBorderStyleVal(bs);
1026
+ setBorderColorVal(bw !== "0px" ? bc : "");
1027
+ setPendingBorderColor("");
1028
+ setPendingBorderWidth("");
1029
+ setPendingBorderStyle("");
1030
+ setExpandedBorderColor(false);
1031
+ const r = getComputedRadius(el);
1032
+ setRadiusVal(r);
1033
+ setPendingRadius("");
1034
+ const shadowComputed = elCs.boxShadow.trim() || "none";
1035
+ setShadowVal(shadowComputed === "rgba(0, 0, 0, 0) 0px 0px 0px 0px" ? "none" : shadowComputed);
1036
+ setShadowAuthoredVal(getAuthoredStyleValue(el, "box-shadow"));
1037
+ setPendingShadow("");
1038
+ setShowShadowDrop(false);
1039
+ const cs = getComputedStyle(el);
1040
+ const normPad = (v) => {
1041
+ const parts = v.trim().split(" ");
1042
+ return parts.every((p) => p === parts[0]) ? parts[0] : v.trim();
1043
+ };
1044
+ setPaddingVal(normPad(`${cs.paddingTop} ${cs.paddingRight} ${cs.paddingBottom} ${cs.paddingLeft}`));
1045
+ setMarginVal(normPad(`${cs.marginTop} ${cs.marginRight} ${cs.marginBottom} ${cs.marginLeft}`));
1046
+ const isFlexGrid = (d) => d.includes("flex") || d.includes("grid");
1047
+ if (isFlexGrid(cs.display)) {
1048
+ const g = cs.gap.trim();
1049
+ setGapVal(g === "normal" ? "0px" : g);
1050
+ gapTargetRef.current = el;
1051
+ } else if (el.parentElement) {
1052
+ const pcs = getComputedStyle(el.parentElement);
1053
+ if (isFlexGrid(pcs.display)) {
1054
+ const g = pcs.gap.trim();
1055
+ setGapVal(g === "normal" ? "0px" : g);
1056
+ gapTargetRef.current = el.parentElement;
1057
+ } else {
1058
+ setGapVal("0px");
1059
+ gapTargetRef.current = el;
1060
+ }
1061
+ }
1062
+ setPendingPadding("");
1063
+ setPendingMargin("");
1064
+ setPendingGap("");
1065
+ setTranslateVal(parseTranslate(cs.translate));
1066
+ setWidthVal(cs.width.trim());
1067
+ setHeightVal(cs.height.trim());
1068
+ setWidthMode(inferSizeMode(el, "width", cs.width.trim()));
1069
+ setHeightMode(inferSizeMode(el, "height", cs.height.trim()));
1070
+ setPendingTranslate(null);
1071
+ setPendingWidth("");
1072
+ setPendingHeight("");
1073
+ setPendingWidthMode(null);
1074
+ setPendingHeightMode(null);
1075
+ setSizeDraft({});
1076
+ setNote("");
1077
+ setTextContent(getTextContent(el));
1078
+ setNewTokenProp(null);
1079
+ setExpandedColor(null);
1080
+ setShowScopeHelp(false);
1081
+ setIsEditing(false);
1082
+ setSelected(el);
1083
+ }, []);
1084
+ (0, import_react2.useEffect)(() => {
1085
+ selectEl(targetEl);
1086
+ }, [targetEl]);
1087
+ (0, import_react2.useEffect)(() => {
1088
+ document.querySelectorAll(".di-selected").forEach((e) => e.classList.remove("di-selected"));
1089
+ if (scope !== "current") {
1090
+ getScopeTargets(selected, scope).forEach((e) => e.classList.add("di-selected"));
1091
+ } else {
1092
+ selected.classList.add("di-selected");
1093
+ }
1094
+ return () => {
1095
+ document.querySelectorAll(".di-selected").forEach((e) => e.classList.remove("di-selected"));
1096
+ };
1097
+ }, [selected, scope]);
1098
+ function applyToDOM(changes) {
1099
+ const el = selectedRef.current;
1100
+ if (!el) return;
1101
+ const targets = getScopeTargets(el, scope);
1102
+ changes.forEach(({ prop, val }) => {
1103
+ targets.forEach((t) => t.style.setProperty(prop, val));
1104
+ });
1105
+ }
1106
+ function onDragStart(e) {
1107
+ if (e.target.closest("button, input, textarea")) return;
1108
+ e.preventDefault();
1109
+ dragRef.current = { sx: e.clientX, sy: e.clientY, sl: panelPos.left, st: panelPos.top };
1110
+ const onMove = (ev) => {
1111
+ if (!dragRef.current) return;
1112
+ const left = Math.max(0, Math.min(window.innerWidth - 380, dragRef.current.sl + ev.clientX - dragRef.current.sx));
1113
+ const top = Math.max(0, Math.min(window.innerHeight - 60, dragRef.current.st + ev.clientY - dragRef.current.sy));
1114
+ setPanelPos({ left, top });
1115
+ };
1116
+ const onUp = () => {
1117
+ dragRef.current = null;
1118
+ document.removeEventListener("mousemove", onMove);
1119
+ document.removeEventListener("mouseup", onUp);
1120
+ };
1121
+ document.addEventListener("mousemove", onMove);
1122
+ document.addEventListener("mouseup", onUp);
1123
+ }
1124
+ function handleAddToken(val, cssProp) {
1125
+ setAddTokenModal({ value: val, cssProp });
1126
+ }
1127
+ function handleTokenConfirm(cssVar, val, usage) {
1128
+ setPendingNewToken({ cssVar, value: val, usage });
1129
+ onTokenMapUpdate({ [val]: cssVar });
1130
+ tokenLabels[cssVar] = cssVar.replace("--color-", "").replace(/-/g, "\xB7");
1131
+ }
1132
+ function liveApply(prop, val) {
1133
+ if (prop === "gap" && gapTargetRef.current) {
1134
+ gapTargetRef.current.style.setProperty("gap", val);
1135
+ } else {
1136
+ applyToDOM([{ prop, val }]);
1137
+ }
1138
+ }
1139
+ function liveApplyMany(changes) {
1140
+ applyToDOM(changes);
1141
+ }
1142
+ function getPendingEntries() {
1143
+ const el = selectedRef.current;
1144
+ if (!el) return null;
1145
+ const fixedMinHeight = pendingHeight && pendingHeightMode === "fixed" ? `${getOneLineHugHeight(el) || Number.parseFloat(pendingHeight) || 0}px` : "";
1146
+ const pending = [
1147
+ ...Object.entries(pendingColors),
1148
+ ...pendingTextColor ? [["color", pendingTextColor]] : [],
1149
+ ...pendingRadius ? [["border-radius", pendingRadius]] : [],
1150
+ ...pendingShadow ? [["box-shadow", pendingShadow]] : [],
1151
+ ...pendingBorderColor ? [["border-color", pendingBorderColor]] : [],
1152
+ ...pendingBorderWidth ? [["border-width", pendingBorderWidth]] : [],
1153
+ ...pendingBorderStyle ? [["border-style", pendingBorderStyle]] : [],
1154
+ ...pendingFontSize ? [["font-size", pendingFontSize]] : [],
1155
+ ...pendingFontWeight ? [["font-weight", pendingFontWeight]] : [],
1156
+ ...pendingPadding ? [["padding", pendingPadding]] : [],
1157
+ ...pendingMargin ? [["margin", pendingMargin]] : [],
1158
+ ...pendingGap ? [["gap", pendingGap]] : [],
1159
+ ...pendingTranslate ? [["translate", formatTranslate(pendingTranslate)]] : [],
1160
+ ...pendingWidth ? [["width", pendingWidth]] : [],
1161
+ ...pendingHeight ? [["height", pendingHeight]] : [],
1162
+ ...fixedMinHeight ? [["min-height", fixedMinHeight]] : [],
1163
+ ...pendingHeight && pendingHeightMode === "fixed" ? [["max-height", pendingHeight]] : []
1164
+ ];
1165
+ const gapEntry = pending.find(([p]) => p === "gap");
1166
+ const nonGapPending = pending.filter(([p]) => p !== "gap");
1167
+ const selector = getSelectorForScope(el, scope);
1168
+ const entries = [];
1169
+ if (gapEntry && gapTargetRef.current && gapTargetRef.current !== el) {
1170
+ entries.push({
1171
+ selector: getSelectorForScope(gapTargetRef.current, "current"),
1172
+ changes: [{ prop: "gap", from: gapVal, val: gapEntry[1] }]
1173
+ });
1174
+ }
1175
+ entries.push({
1176
+ selector,
1177
+ changes: (gapEntry && gapTargetRef.current !== el ? nonGapPending : pending).map(([prop, val]) => ({ prop, from: getOriginalValueForProp(prop), val })),
1178
+ note: note || void 0
1179
+ });
1180
+ return {
1181
+ el,
1182
+ selector,
1183
+ pending,
1184
+ entries
1185
+ };
1186
+ }
1187
+ function nudgeSelected(dx, dy) {
1188
+ const base = pendingTranslate ?? translateVal;
1189
+ const next = { x: base.x + dx, y: base.y + dy };
1190
+ setPendingTranslate(next);
1191
+ liveApply("translate", formatTranslate(next));
1192
+ }
1193
+ function setSize(prop, val, mode = "fixed") {
1194
+ const current = prop === "width" ? widthVal : heightVal;
1195
+ const next = normalizeCssSize(val);
1196
+ const selectedEl = selectedRef.current;
1197
+ const cssValue = prop === "height" && mode === "fixed" ? clampHeightToOneLine(next, selectedEl) : mode === "fixed" ? next : sizeValueForMode(mode, current);
1198
+ if (prop === "width") {
1199
+ setPendingWidth(cssValue);
1200
+ setPendingWidthMode(mode);
1201
+ } else {
1202
+ setPendingHeight(cssValue);
1203
+ setPendingHeightMode(mode);
1204
+ }
1205
+ if (prop === "height" && mode === "fixed") {
1206
+ const minHeight = `${getOneLineHugHeight(selectedEl) || Number.parseFloat(cssValue) || 0}px`;
1207
+ liveApplyMany([
1208
+ { prop: "height", val: cssValue },
1209
+ { prop: "min-height", val: minHeight },
1210
+ { prop: "max-height", val: cssValue }
1211
+ ]);
1212
+ return;
1213
+ }
1214
+ if (prop === "height") {
1215
+ const el = selectedRef.current;
1216
+ if (el) {
1217
+ const targets = getScopeTargets(el, scope);
1218
+ targets.forEach((t) => t.style.removeProperty("min-height"));
1219
+ targets.forEach((t) => t.style.removeProperty("max-height"));
1220
+ }
1221
+ }
1222
+ liveApply(prop, cssValue);
1223
+ }
1224
+ function handleSave() {
1225
+ const payload = getPendingEntries();
1226
+ if (!payload) return;
1227
+ const { el, pending, entries } = payload;
1228
+ if (pending.length === 0 && !note && !newTokenName) {
1229
+ setSaveMsg("\u65E0\u6539\u52A8");
1230
+ setTimeout(() => setSaveMsg(""), 1500);
1231
+ return;
1232
+ }
1233
+ applyToDOM(pending.map(([prop, val]) => ({ prop, val })));
1234
+ if (!canPersistSelector(el, scope)) {
1235
+ setSaveMsg("\u9700\u9009\u4E2D\u5177\u4F53\u7C7B\u540D");
1236
+ setTimeout(() => setSaveMsg(""), 2e3);
1237
+ return;
1238
+ }
1239
+ fetch(endpoints.applyCss, {
1240
+ method: "POST",
1241
+ headers: { "Content-Type": "application/json" },
1242
+ body: JSON.stringify({ entries })
1243
+ }).then((r) => r.json()).then((r) => {
1244
+ setSaveMsg(r.ok ? "\u5DF2\u4FDD\u5B58 \u2713" : "\u4FDD\u5B58\u5931\u8D25");
1245
+ setTimeout(() => setSaveMsg(""), 2e3);
1246
+ }).catch(() => {
1247
+ setSaveMsg("\u4FDD\u5B58\u5931\u8D25");
1248
+ setTimeout(() => setSaveMsg(""), 2e3);
1249
+ });
1250
+ }
1251
+ async function copyTextToClipboard(text) {
1252
+ if (navigator.clipboard?.writeText) {
1253
+ try {
1254
+ await navigator.clipboard.writeText(text);
1255
+ return true;
1256
+ } catch {
1257
+ }
1258
+ }
1259
+ const ta = document.createElement("textarea");
1260
+ ta.value = text;
1261
+ ta.style.cssText = "position:fixed;opacity:0;top:0;left:0";
1262
+ document.body.appendChild(ta);
1263
+ ta.select();
1264
+ const copied = document.execCommand("copy");
1265
+ document.body.removeChild(ta);
1266
+ return copied;
1267
+ }
1268
+ function buildAiTaskPrompt(params) {
1269
+ const inboxJson = "/Users/heqiao/Desktop/Claude\u7EC3\u4E60/\u9879\u76EE3-\u5FEB\u6D88AI\u4E2D\u53F0/docs/style-inbox.json";
1270
+ const inboxMd = "/Users/heqiao/Desktop/Claude\u7EC3\u4E60/\u9879\u76EE3-\u5FEB\u6D88AI\u4E2D\u53F0/docs/STYLE_INBOX.md";
1271
+ const changes = params.changes.map((change, index) => `${index + 1}. ${getChangeLabel(change.prop)}\uFF1A${change.from} \u2192 ${change.val}`).join("\n");
1272
+ const latestHint = params.entryId ? `\u4F18\u5148\u5904\u7406 id = ${params.entryId} \u8FD9\u6761\u8BB0\u5F55\u3002` : "\u8FD9\u6761\u4EFB\u52A1\u6587\u672C\u6765\u81EA\u5F53\u524D\u9009\u4E2D\u5143\u7D20\u7684\u672C\u8F6E\u4FEE\u6539\u3002";
1273
+ return [
1274
+ "\u8BF7\u5904\u7406\u8FD9\u6761 DevInspector \u6837\u5F0F\u4EFB\u52A1\uFF1A",
1275
+ "",
1276
+ latestHint,
1277
+ `\u5982\u9700\u67E5\u770B\u7D2F\u8BA1\u8BB0\u5F55\uFF0C\u8BFB\u53D6\uFF1A${inboxJson}`,
1278
+ `\u5FC5\u8981\u65F6\u5BF9\u7167\uFF1A${inboxMd}`,
1279
+ "",
1280
+ `\u5BF9\u8C61\uFF1A${params.targetLabel}`,
1281
+ `\u4F5C\u7528\u8303\u56F4\uFF1A${params.scopeLabel}`,
1282
+ `\u9009\u62E9\u5668\uFF1A${params.selector}`,
1283
+ "\u6539\u52A8\uFF1A",
1284
+ changes,
1285
+ "",
1286
+ "\u8BF7\u5148\u5224\u65AD\u662F\u5426\u9002\u5408\u56FA\u5316\u8FDB\u6B63\u5F0F\u7EC4\u4EF6\u6837\u5F0F\uFF0C\u518D\u4FEE\u6539\u4EE3\u7801\uFF0C\u5E76\u5728\u5904\u7406\u540E\u628A\u8FD9\u6761\u4EFB\u52A1\u6807\u8BB0\u4E3A\u5DF2\u5904\u7406\u3002"
1287
+ ].join("\n");
1288
+ }
1289
+ function handleSubmitToAi() {
1290
+ const payload = getPendingEntries();
1291
+ if (!payload) return;
1292
+ const { el, pending, selector } = payload;
1293
+ const changes = getPendingChangeRecords();
1294
+ if (pending.length === 0 && !note) {
1295
+ setSubmitMsg("\u5148\u6539\u70B9\u6837\u5F0F\u6216\u5199\u5907\u6CE8");
1296
+ setTimeout(() => setSubmitMsg(""), 1800);
1297
+ return;
1298
+ }
1299
+ const scopeLabel = scope === "current" ? "\u5F53\u524D\u5143\u7D20" : "\u540C\u7EC4\u4EF6";
1300
+ const targetClasses = getClasses(el);
1301
+ const targetLabel = targetClasses.length ? `${el.tagName.toLowerCase()}.${targetClasses.join(".")}` : el.tagName.toLowerCase();
1302
+ const prompt2 = buildAiTaskPrompt({
1303
+ targetLabel,
1304
+ selector,
1305
+ scopeLabel,
1306
+ changes
1307
+ });
1308
+ copyTextToClipboard(prompt2).then((copied) => {
1309
+ setSubmitMsg(copied ? "\u4EFB\u52A1\u6587\u672C\u5DF2\u590D\u5236 \u2713" : "\u590D\u5236\u5931\u8D25");
1310
+ setTimeout(() => setSubmitMsg(""), copied ? 2200 : 1800);
1311
+ }).catch(() => {
1312
+ setSubmitMsg("\u590D\u5236\u5931\u8D25");
1313
+ setTimeout(() => setSubmitMsg(""), 1800);
1314
+ });
1315
+ }
1316
+ function handleDeleteStyleIntent(intentId, selector, prop) {
1317
+ fetch(endpoints.deleteStyleIntent, {
1318
+ method: "POST",
1319
+ headers: { "Content-Type": "application/json" },
1320
+ body: JSON.stringify({ id: intentId, selector, prop })
1321
+ }).then(async (response) => {
1322
+ let body = null;
1323
+ try {
1324
+ body = await response.json();
1325
+ } catch {
1326
+ body = null;
1327
+ }
1328
+ return {
1329
+ httpOk: response.ok,
1330
+ ...body ?? {}
1331
+ };
1332
+ }).then((r) => {
1333
+ if (r.ok) {
1334
+ setStyleIntentSummary(formatStyleIntentSummary(r));
1335
+ setSubmitMsg(prop ? "\u5DF2\u5220\u9664\u5C5E\u6027" : "\u5DF2\u5220\u9664\u5BF9\u8C61");
1336
+ } else {
1337
+ const errorMsg = !r.httpOk ? "\u5220\u9664\u5931\u8D25\uFF1A\u672C\u5730\u670D\u52A1\u5F02\u5E38" : `\u5220\u9664\u5931\u8D25${r.error ? `\uFF1A${String(r.error)}` : ""}`;
1338
+ setSubmitMsg(errorMsg);
1339
+ }
1340
+ setTimeout(() => setSubmitMsg(""), 1800);
1341
+ }).catch(() => {
1342
+ setSubmitMsg("\u5220\u9664\u5931\u8D25\uFF1A\u8BF7\u5237\u65B0\u9875\u9762\u6216\u91CD\u542F\u672C\u5730 dev");
1343
+ setTimeout(() => setSubmitMsg(""), 1800);
1344
+ });
1345
+ }
1346
+ function getOriginalValueForProp(prop) {
1347
+ if (prop === "font-size") return fontSizeVal;
1348
+ if (prop === "font-weight") return fontWeightVal;
1349
+ if (prop === "color") return getDisplayLabel(textColorVal, tokenMap, colorPalette, tokenLabels).label;
1350
+ if (prop === "background-color") return getDisplayLabel(colors[prop] ?? "", tokenMap, colorPalette, tokenLabels).label;
1351
+ if (prop === "border-color") return getDisplayLabel(borderColorVal, tokenMap, colorPalette, tokenLabels).label;
1352
+ if (prop === "border-width") return borderWidthVal;
1353
+ if (prop === "border-style") return borderStyleVal;
1354
+ if (prop === "border-radius") return radiusVal;
1355
+ if (prop === "box-shadow") return getShadowDisplay(shadowVal, shadowAuthoredVal, shadowTokens).label;
1356
+ if (prop === "padding") return paddingVal;
1357
+ if (prop === "margin") return marginVal;
1358
+ if (prop === "gap") return gapVal;
1359
+ if (prop === "translate") return formatTranslate(translateVal);
1360
+ if (prop === "width") return widthVal;
1361
+ if (prop === "height") return heightVal;
1362
+ if (prop === "min-height") return `${getOneLineHugHeight(selectedRef.current) || Number.parseFloat(heightVal) || 0}px`;
1363
+ if (prop === "max-height") return heightVal;
1364
+ return "";
1365
+ }
1366
+ function getPendingChangeRecords() {
1367
+ const records = [];
1368
+ const add = (prop, from, val) => records.push({ prop, from, val });
1369
+ if (pendingFontSize) add("font-size", fontSizeVal, pendingFontSize);
1370
+ if (pendingFontWeight) add("font-weight", fontWeightVal, pendingFontWeight);
1371
+ if (pendingTextColor) add("color", getDisplayLabel(textColorVal, tokenMap, colorPalette, tokenLabels).label, getDisplayLabel(pendingTextColor, tokenMap, colorPalette, tokenLabels).label);
1372
+ for (const [prop, val] of Object.entries(pendingColors)) {
1373
+ add(prop, getDisplayLabel(colors[prop] ?? "", tokenMap, colorPalette, tokenLabels).label, getDisplayLabel(val, tokenMap, colorPalette, tokenLabels).label);
1374
+ }
1375
+ if (pendingBorderColor) add("border-color", getDisplayLabel(borderColorVal, tokenMap, colorPalette, tokenLabels).label, getDisplayLabel(pendingBorderColor, tokenMap, colorPalette, tokenLabels).label);
1376
+ if (pendingBorderWidth) add("border-width", borderWidthVal, pendingBorderWidth);
1377
+ if (pendingBorderStyle) add("border-style", borderStyleVal, pendingBorderStyle);
1378
+ if (pendingRadius) add("border-radius", radiusVal, pendingRadius);
1379
+ if (pendingShadow) add("box-shadow", getShadowDisplay(shadowVal, shadowAuthoredVal, shadowTokens).label, getShadowDisplay(pendingShadow, pendingShadow, shadowTokens).label);
1380
+ if (pendingPadding) add("padding", paddingVal, pendingPadding);
1381
+ if (pendingMargin) add("margin", marginVal, pendingMargin);
1382
+ if (pendingGap) add("gap", gapVal, pendingGap);
1383
+ if (pendingTranslate) add("translate", formatTranslate(translateVal), formatTranslate(pendingTranslate));
1384
+ if (pendingWidth) add("width", widthVal, pendingWidth);
1385
+ if (pendingHeight) add("height", heightVal, pendingHeight);
1386
+ if (pendingNewToken) add("token", "\u65B0\u589E", `${pendingNewToken.cssVar}: ${pendingNewToken.value}`);
1387
+ return records;
1388
+ }
1389
+ function getChangeLabel(prop) {
1390
+ const map = {
1391
+ "font-size": "\u5B57\u53F7",
1392
+ "font-weight": "\u5B57\u91CD",
1393
+ "color": "\u6587\u5B57\u8272",
1394
+ "background-color": "\u80CC\u666F\u8272",
1395
+ "border-color": "\u8FB9\u6846\u8272",
1396
+ "border-width": "\u8FB9\u6846\u7C97\u7EC6",
1397
+ "border-style": "\u8FB9\u6846\u6837\u5F0F",
1398
+ "border-radius": "\u5706\u89D2",
1399
+ "box-shadow": "\u9634\u5F71",
1400
+ "padding": "\u5185\u8FB9\u8DDD",
1401
+ "margin": "\u5916\u8FB9\u8DDD",
1402
+ "gap": "\u5143\u7D20\u95F4\u8DDD",
1403
+ "translate": "\u4F4D\u7F6E",
1404
+ "width": "\u5BBD\u5EA6",
1405
+ "height": "\u9AD8\u5EA6",
1406
+ "min-height": "\u6700\u5C0F\u9AD8\u5EA6",
1407
+ "max-height": "\u6700\u5927\u9AD8\u5EA6"
1408
+ };
1409
+ return map[prop] || prop;
1410
+ }
1411
+ function handleReset() {
1412
+ const el = selectedRef.current;
1413
+ if (!el) return;
1414
+ const targets = getScopeTargets(el, scope);
1415
+ targets.forEach((t) => {
1416
+ const hEl = t;
1417
+ [...Object.keys(pendingColors)].forEach((p) => hEl.style.removeProperty(p));
1418
+ if (pendingRadius) hEl.style.removeProperty("border-radius");
1419
+ if (pendingShadow) hEl.style.removeProperty("box-shadow");
1420
+ if (pendingBorderColor) hEl.style.removeProperty("border-color");
1421
+ if (pendingBorderWidth) hEl.style.removeProperty("border-width");
1422
+ if (pendingBorderStyle) hEl.style.removeProperty("border-style");
1423
+ if (pendingPadding) hEl.style.removeProperty("padding");
1424
+ if (pendingMargin) hEl.style.removeProperty("margin");
1425
+ if (pendingGap) hEl.style.removeProperty("gap");
1426
+ if (pendingTranslate) hEl.style.removeProperty("translate");
1427
+ if (pendingWidth) hEl.style.removeProperty("width");
1428
+ if (pendingHeight) hEl.style.removeProperty("height");
1429
+ if (pendingHeight) hEl.style.removeProperty("min-height");
1430
+ if (pendingHeight) hEl.style.removeProperty("max-height");
1431
+ });
1432
+ setPendingColors({});
1433
+ setPendingRadius("");
1434
+ setPendingShadow("");
1435
+ setPendingFontSize("");
1436
+ setPendingFontWeight("");
1437
+ setPendingTextColor("");
1438
+ setPendingBorderColor("");
1439
+ setPendingBorderWidth("");
1440
+ setPendingBorderStyle("");
1441
+ setPendingPadding("");
1442
+ setPendingMargin("");
1443
+ setPendingGap("");
1444
+ setPendingTranslate(null);
1445
+ setPendingWidth("");
1446
+ setPendingHeight("");
1447
+ setPendingWidthMode(null);
1448
+ setPendingHeightMode(null);
1449
+ setSizeDraft({});
1450
+ setCustomColorVals({});
1451
+ setColors(Object.fromEntries(
1452
+ COLOR_PROPS.map(({ prop }) => [prop, getComputedColor(el, prop)]).filter(([, v]) => v && v !== "rgba(0, 0, 0, 0)" && v !== "transparent")
1453
+ ));
1454
+ const cs = getComputedStyle(el);
1455
+ setRadiusVal(getComputedRadius(el));
1456
+ setShadowVal(cs.boxShadow.trim() === "rgba(0, 0, 0, 0) 0px 0px 0px 0px" ? "none" : cs.boxShadow.trim());
1457
+ setShadowAuthoredVal(getAuthoredStyleValue(el, "box-shadow"));
1458
+ const normSpace = (v) => {
1459
+ const parts = v.trim().split(" ");
1460
+ return parts.every((p) => p === parts[0]) ? parts[0] : v.trim();
1461
+ };
1462
+ setPaddingVal(normSpace(`${cs.paddingTop} ${cs.paddingRight} ${cs.paddingBottom} ${cs.paddingLeft}`));
1463
+ setMarginVal(normSpace(`${cs.marginTop} ${cs.marginRight} ${cs.marginBottom} ${cs.marginLeft}`));
1464
+ const g = cs.gap.trim();
1465
+ setGapVal(g === "normal" ? "0px" : g);
1466
+ setTranslateVal(parseTranslate(cs.translate));
1467
+ setWidthVal(cs.width.trim());
1468
+ setHeightVal(cs.height.trim());
1469
+ setWidthMode(inferSizeMode(el, "width", cs.width.trim()));
1470
+ setHeightMode(inferSizeMode(el, "height", cs.height.trim()));
1471
+ }
1472
+ function handleClose() {
1473
+ onClose();
1474
+ }
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1476
+ addTokenModal && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1477
+ AddTokenModal,
1478
+ {
1479
+ value: addTokenModal.value,
1480
+ cssProp: addTokenModal.cssProp,
1481
+ elementClasses: getClasses(selected),
1482
+ colorPalette,
1483
+ onClose: () => setAddTokenModal(null),
1484
+ onConfirm: handleTokenConfirm
1485
+ }
1486
+ ),
1487
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1488
+ "div",
1489
+ {
1490
+ ref: panelElRef,
1491
+ className: "di-panel",
1492
+ "data-di-panel-role": "primary",
1493
+ style: { top: panelPos.top, left: panelPos.left },
1494
+ children: [
1495
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-head", onMouseDown: onDragStart, children: [
1496
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-head-left", children: [
1497
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-title", children: "\u9875\u9762\u6837\u5F0F" }),
1498
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-badge-dev", children: "Dev Only" }),
1499
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1500
+ "button",
1501
+ {
1502
+ className: "di-layer-btn",
1503
+ title: "\u9009\u4E2D\u7236\u5C42",
1504
+ disabled: !selected.parentElement || selected.parentElement === document.body,
1505
+ onClick: () => {
1506
+ if (selected.parentElement && selected.parentElement !== document.body) selectEl(selected.parentElement);
1507
+ },
1508
+ children: "\u2191"
1509
+ }
1510
+ ),
1511
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1512
+ "button",
1513
+ {
1514
+ className: "di-layer-btn",
1515
+ title: "\u9009\u4E2D\u7B2C\u4E00\u4E2A\u5B50\u5C42",
1516
+ disabled: !selected.firstElementChild,
1517
+ onClick: () => {
1518
+ if (selected.firstElementChild) selectEl(selected.firstElementChild);
1519
+ },
1520
+ children: "\u2193"
1521
+ }
1522
+ )
1523
+ ] }),
1524
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-head-right", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-close", onClick: handleClose, children: "\xD7" }) })
1525
+ ] }),
1526
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-body", children: [
1527
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
1528
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section-title-row", children: [
1529
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u4F5C\u7528\u8303\u56F4" }),
1530
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1531
+ "button",
1532
+ {
1533
+ type: "button",
1534
+ className: `di-help-icon${showScopeHelp ? " di-help-icon--on" : ""}`,
1535
+ "aria-label": "\u67E5\u770B\u4F5C\u7528\u8303\u56F4\u8BF4\u660E",
1536
+ "aria-expanded": showScopeHelp,
1537
+ onClick: () => setShowScopeHelp((v) => !v),
1538
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.CircleHelp, { size: 14, strokeWidth: 1.8 })
1539
+ }
1540
+ )
1541
+ ] }),
1542
+ showScopeHelp && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-help-popover", children: "\u540C\u7EC4\u4EF6 = \u5FFD\u7565\u6FC0\u6D3B / \u5F53\u524D / \u5C55\u5F00\u7B49\u72B6\u6001\u7C7B\u540E\uFF0C\u5171\u4EAB\u540C\u4E00\u4E1A\u52A1\u7C7B\u540D\u7684\u5143\u7D20\u3002" }),
1543
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-scope-row", children: [
1544
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: `di-scope-btn${scope === "current" ? " di-scope-btn--on" : ""}`, onClick: () => setScope("current"), children: "\u5F53\u524D\u5143\u7D20" }),
1545
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: `di-scope-btn${scope === "component" ? " di-scope-btn--on" : ""}`, onClick: () => setScope("component"), children: [
1546
+ "\u540C\u7EC4\u4EF6 ",
1547
+ selected && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-scope-count", children: getSameComponentEls(selected).length })
1548
+ ] })
1549
+ ] })
1550
+ ] }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
1552
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u6587\u5B57" }),
1553
+ textContent !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1554
+ "textarea",
1555
+ {
1556
+ className: "di-note di-note--sm",
1557
+ defaultValue: textContent,
1558
+ ref: (el) => {
1559
+ if (el) resizeTextareaToContent(el);
1560
+ },
1561
+ placeholder: "\u4FEE\u6539\u6587\u5B57\u5185\u5BB9...",
1562
+ onChange: (e) => {
1563
+ resizeTextareaToContent(e.currentTarget);
1564
+ const el = selectedRef.current;
1565
+ if (!el) return;
1566
+ const ts = getScopeTargets(el, scope);
1567
+ ts.forEach((t) => {
1568
+ t.textContent = e.currentTarget.value;
1569
+ });
1570
+ }
1571
+ }
1572
+ ),
1573
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-row", children: [
1574
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-card", children: [
1575
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-card-title", children: "\u5B57\u53F7" }),
1576
+ (() => {
1577
+ const curSize = pendingFontSize || fontSizeVal || "\u2014";
1578
+ const curWeight = pendingFontWeight || fontWeightVal;
1579
+ const curColor = pendingTextColor || textColorVal;
1580
+ const matchedToken = getTypographyToken(curSize, curWeight, curColor, typographyTokens);
1581
+ const curOpt = matchedToken ? fontSizeOptions.find((opt) => opt.key === matchedToken.key) : null;
1582
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1584
+ "div",
1585
+ {
1586
+ className: "di-border-style-single di-font-token-trigger",
1587
+ role: "button",
1588
+ tabIndex: 0,
1589
+ onClick: (e) => {
1590
+ const r = e.currentTarget.getBoundingClientRect();
1591
+ setDropPos(calcDropPos(r));
1592
+ setShowWeightDrop(false);
1593
+ setShowStyleDrop(false);
1594
+ setExpandedTextColor(false);
1595
+ setExpandedBorderColor(false);
1596
+ setShowShadowDrop(false);
1597
+ setCustomRadius("");
1598
+ setSizeDraft({});
1599
+ setFontSizeCustomDraft(curSize);
1600
+ setShowFontSizeDrop((v) => !v);
1601
+ },
1602
+ onKeyDown: (e) => {
1603
+ if (e.key === "Enter" || e.key === " ") {
1604
+ e.preventDefault();
1605
+ const r = e.currentTarget.getBoundingClientRect();
1606
+ setDropPos(calcDropPos(r));
1607
+ setFontSizeCustomDraft(curSize);
1608
+ setShowFontSizeDrop((v) => !v);
1609
+ }
1610
+ },
1611
+ children: [
1612
+ curOpt && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", children: curOpt.label }),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `di-border-style-name${curOpt ? "" : " di-border-style-name--custom"}`, children: curSize }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "5", viewBox: "0 0 8 5", fill: "none", style: { marginLeft: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l3 3 3-3", stroke: "#9ca3af", strokeWidth: "1.5", strokeLinecap: "round" }) })
1615
+ ]
1616
+ }
1617
+ ),
1618
+ showFontSizeDrop && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1619
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "fixed", inset: 0, zIndex: 99997 }, onClick: () => setShowFontSizeDrop(false) }),
1620
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-style-drop", style: { position: "fixed", top: dropPos.top, left: dropPos.left, zIndex: 99998 }, children: [
1621
+ fontSizeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1622
+ "button",
1623
+ {
1624
+ className: `di-border-style-drop-item${curOpt?.key === opt.key ? " di-border-style-drop-item--on" : ""}`,
1625
+ onClick: () => {
1626
+ setPendingFontSize(opt.value);
1627
+ setPendingFontWeight(opt.fontWeight);
1628
+ setPendingTextColor(opt.color);
1629
+ liveApplyMany([
1630
+ { prop: "font-size", val: opt.value },
1631
+ { prop: "font-weight", val: opt.fontWeight },
1632
+ { prop: "color", val: opt.color }
1633
+ ]);
1634
+ setShowFontSizeDrop(false);
1635
+ },
1636
+ children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", children: opt.label }),
1638
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: `${opt.value} / ${opt.fontWeight}` })
1639
+ ]
1640
+ },
1641
+ opt.key
1642
+ )),
1643
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-dropdown-custom", children: [
1644
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-dropdown-custom-label", children: "\u81EA\u5B9A\u4E49" }),
1645
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1646
+ "input",
1647
+ {
1648
+ className: "di-dropdown-custom-input",
1649
+ value: fontSizeCustomDraft,
1650
+ placeholder: "13px",
1651
+ onChange: (e) => setFontSizeCustomDraft(e.target.value),
1652
+ onClick: (e) => e.stopPropagation()
1653
+ }
1654
+ ),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1656
+ "button",
1657
+ {
1658
+ type: "button",
1659
+ className: "di-dropdown-custom-apply",
1660
+ onClick: (e) => {
1661
+ e.stopPropagation();
1662
+ if (!fontSizeCustomDraft.trim()) return;
1663
+ setPendingFontSize(fontSizeCustomDraft.trim());
1664
+ liveApply("font-size", fontSizeCustomDraft.trim());
1665
+ setShowFontSizeDrop(false);
1666
+ },
1667
+ children: "\u5E94\u7528"
1668
+ }
1669
+ )
1670
+ ] })
1671
+ ] })
1672
+ ] })
1673
+ ] });
1674
+ })()
1675
+ ] }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-card", style: { position: "relative" }, children: [
1677
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-card-title", children: "\u5B57\u91CD" }),
1678
+ (() => {
1679
+ const cur = pendingFontWeight || fontWeightVal;
1680
+ const curOpt = fontWeightOptions.find((o) => o.value === cur) ?? fontWeightOptions[1];
1681
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1682
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1683
+ "button",
1684
+ {
1685
+ className: "di-border-style-single",
1686
+ style: { marginTop: 4 },
1687
+ onClick: (e) => {
1688
+ const r = e.currentTarget.getBoundingClientRect();
1689
+ setDropPos(calcDropPos(r));
1690
+ setShowWeightDrop((v) => !v);
1691
+ },
1692
+ children: [
1693
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", style: curOpt.value === "none" ? { color: "#9ca3af" } : void 0, children: curOpt.label }),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: cur }),
1695
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "5", viewBox: "0 0 8 5", fill: "none", style: { marginLeft: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l3 3 3-3", stroke: "#9ca3af", strokeWidth: "1.5", strokeLinecap: "round" }) })
1696
+ ]
1697
+ }
1698
+ ),
1699
+ showWeightDrop && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1700
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "fixed", inset: 0, zIndex: 99997 }, onClick: () => setShowWeightDrop(false) }),
1701
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-style-drop", style: { position: "fixed", top: dropPos.top, left: dropPos.left, zIndex: 99998 }, children: fontWeightOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1702
+ "button",
1703
+ {
1704
+ className: `di-border-style-drop-item${cur === opt.value ? " di-border-style-drop-item--on" : ""}`,
1705
+ onClick: () => {
1706
+ setPendingFontWeight(opt.value);
1707
+ liveApply("font-weight", opt.value);
1708
+ setShowWeightDrop(false);
1709
+ },
1710
+ children: [
1711
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", style: opt.value === "none" ? { color: "#9ca3af" } : void 0, children: opt.label }),
1712
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: opt.value })
1713
+ ]
1714
+ },
1715
+ opt.value
1716
+ )) })
1717
+ ] })
1718
+ ] });
1719
+ })()
1720
+ ] }),
1721
+ (() => {
1722
+ const tcVal = pendingTextColor || textColorVal;
1723
+ const { label: tcLabel, sub: tcSub, isHardcoded: tcHard } = getDisplayLabel(tcVal, tokenMap, colorPalette, tokenLabels);
1724
+ const tcDark = (() => {
1725
+ const m = tcVal.match(/^#([0-9a-f]{6})$/i);
1726
+ if (!m) return true;
1727
+ const r = parseInt(m[1].slice(0, 2), 16), g = parseInt(m[1].slice(2, 4), 16), b = parseInt(m[1].slice(4, 6), 16);
1728
+ return (r * 299 + g * 587 + b * 114) / 1e3 < 128;
1729
+ })();
1730
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-card", style: { position: "relative" }, children: [
1731
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-card-title", children: "\u989C\u8272" }),
1732
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-color-body", style: { marginTop: 4 }, children: [
1733
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1734
+ "button",
1735
+ {
1736
+ className: `di-swatch-btn${tcDark ? " di-swatch-btn--dark" : ""}`,
1737
+ style: { background: tcVal || "#1d293d" },
1738
+ onClick: (e) => {
1739
+ const r = e.currentTarget.getBoundingClientRect();
1740
+ setDropPos(calcDropPos(r));
1741
+ setExpandedTextColor((v) => !v);
1742
+ },
1743
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l4 4 4-4", stroke: tcDark ? "#fff" : "#374151", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1744
+ }
1745
+ ),
1746
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-color-info", children: [
1747
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: tcHard ? "di-token-name--plain" : "di-token-name", children: tcLabel }),
1748
+ tcSub && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-hex", children: tcSub })
1749
+ ] })
1750
+ ] }),
1751
+ expandedTextColor && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1752
+ ColorDropdown,
1753
+ {
1754
+ value: tcVal,
1755
+ pos: dropPos,
1756
+ colorPalette,
1757
+ onChange: (c) => {
1758
+ setPendingTextColor(c);
1759
+ liveApply("color", c);
1760
+ },
1761
+ onClose: () => setExpandedTextColor(false),
1762
+ onAddToken: (v) => handleAddToken(v, "color")
1763
+ }
1764
+ )
1765
+ ] });
1766
+ })()
1767
+ ] })
1768
+ ] }),
1769
+ Object.keys(colors).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
1770
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u989C\u8272" }),
1771
+ COLOR_PROPS.filter(({ prop }) => colors[prop]).map(({ label, prop }) => {
1772
+ const val = pendingColors[prop] ?? colors[prop];
1773
+ const token = tokenMap[val];
1774
+ const isDark = (() => {
1775
+ const m = val.match(/^#([0-9a-f]{6})$/i);
1776
+ if (!m) return false;
1777
+ const r = parseInt(m[1].slice(0, 2), 16), g = parseInt(m[1].slice(2, 4), 16), b = parseInt(m[1].slice(4, 6), 16);
1778
+ return (r * 299 + g * 587 + b * 114) / 1e3 < 128;
1779
+ })();
1780
+ const isExpanded = expandedColor === prop;
1781
+ const tokenList = Object.entries(tokenMap).filter(([v]) => v.startsWith("#") && v !== val).map(([v, t]) => ({ val: v, token: t }));
1782
+ const { label: dispLabel, sub: dispSub, isHardcoded: dispHard } = getDisplayLabel(val, tokenMap, colorPalette, tokenLabels);
1783
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-color-row", children: [
1784
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-attr-label", children: label }),
1785
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1786
+ "button",
1787
+ {
1788
+ className: `di-swatch-btn${isDark ? " di-swatch-btn--dark" : ""}`,
1789
+ style: { background: val },
1790
+ onClick: (e) => {
1791
+ const r = e.currentTarget.getBoundingClientRect();
1792
+ setDropPos(calcDropPos(r));
1793
+ setExpandedColor(isExpanded ? null : prop);
1794
+ },
1795
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l4 4 4-4", stroke: isDark ? "#fff" : "#374151", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1796
+ }
1797
+ ),
1798
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-color-info", children: [
1799
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: dispHard ? "di-token-name--plain" : "di-token-name", children: dispLabel }),
1800
+ dispSub && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-hex", children: dispSub })
1801
+ ] }),
1802
+ isExpanded && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1803
+ ColorDropdown,
1804
+ {
1805
+ value: val,
1806
+ pos: dropPos,
1807
+ colorPalette,
1808
+ onChange: (c, _tk) => {
1809
+ setPendingColors((prev) => ({ ...prev, [prop]: c }));
1810
+ liveApply(prop, c);
1811
+ },
1812
+ onClose: () => setExpandedColor(null),
1813
+ onAddToken: (v) => handleAddToken(v, prop)
1814
+ }
1815
+ )
1816
+ ] }, prop);
1817
+ })
1818
+ ] }),
1819
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
1820
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u5E03\u5C40" }),
1821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-layout-grid", children: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-layout-card", children: [
1823
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-layout-card-title", children: "\u4F4D\u7F6E" }),
1824
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-nudge-pad", "aria-label": "\u79FB\u52A8\u5143\u7D20", children: [
1825
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-nudge-btn di-nudge-btn--up", onClick: () => nudgeSelected(0, -1), title: "\u4E0A\u79FB 1px", children: "\u2191" }),
1826
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-nudge-btn di-nudge-btn--left", onClick: () => nudgeSelected(-1, 0), title: "\u5DE6\u79FB 1px", children: "\u2190" }),
1827
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-nudge-readout", children: [
1828
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1829
+ "X ",
1830
+ Math.round((pendingTranslate ?? translateVal).x)
1831
+ ] }),
1832
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1833
+ "Y ",
1834
+ Math.round((pendingTranslate ?? translateVal).y)
1835
+ ] })
1836
+ ] }),
1837
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-nudge-btn di-nudge-btn--right", onClick: () => nudgeSelected(1, 0), title: "\u53F3\u79FB 1px", children: "\u2192" }),
1838
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-nudge-btn di-nudge-btn--down", onClick: () => nudgeSelected(0, 1), title: "\u4E0B\u79FB 1px", children: "\u2193" })
1839
+ ] })
1840
+ ] }),
1841
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-layout-card di-layout-card--size", children: [
1842
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-layout-card-title", children: "\u5C3A\u5BF8" }),
1843
+ [
1844
+ { key: "width", label: "W", current: widthVal, pending: pendingWidth, mode: widthMode, pendingMode: pendingWidthMode },
1845
+ { key: "height", label: "H", current: heightVal, pending: pendingHeight, mode: heightMode, pendingMode: pendingHeightMode }
1846
+ ].map((item) => {
1847
+ const cur = displaySizeValue(item.pending, item.current);
1848
+ const inputVal = sizeDraft[item.key] ?? cur;
1849
+ const activeMode = item.pendingMode ?? item.mode;
1850
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-size-row", children: [
1851
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-size-axis", children: item.label }),
1852
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1853
+ "input",
1854
+ {
1855
+ className: "di-size-value",
1856
+ value: inputVal,
1857
+ "aria-label": `${item.label} \u81EA\u5B9A\u4E49\u5C3A\u5BF8`,
1858
+ onChange: (e) => {
1859
+ setSizeDraft((prev) => ({ ...prev, [item.key]: e.target.value }));
1860
+ setSize(item.key, e.target.value, "fixed");
1861
+ },
1862
+ onFocus: (e) => {
1863
+ setSizeDraft((prev) => ({ ...prev, [item.key]: cur }));
1864
+ e.currentTarget.select();
1865
+ },
1866
+ onClick: (e) => e.currentTarget.select(),
1867
+ onMouseUp: (e) => e.preventDefault(),
1868
+ onBlur: () => setSizeDraft((prev) => {
1869
+ const next = { ...prev };
1870
+ delete next[item.key];
1871
+ return next;
1872
+ }),
1873
+ onKeyDown: (e) => {
1874
+ if (e.key === "Enter") e.currentTarget.blur();
1875
+ }
1876
+ }
1877
+ ),
1878
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1879
+ "select",
1880
+ {
1881
+ className: "di-size-mode-select",
1882
+ value: activeMode,
1883
+ onChange: (e) => {
1884
+ const mode = e.target.value;
1885
+ setSize(item.key, item.current, mode);
1886
+ },
1887
+ children: SIZE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt.mode, children: opt.label }, opt.mode))
1888
+ }
1889
+ )
1890
+ ] }, item.key);
1891
+ })
1892
+ ] })
1893
+ ] })
1894
+ ] }),
1895
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
1896
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u9634\u5F71" }),
1897
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-shadow-grid", children: (() => {
1898
+ const activeShadow = pendingShadow || shadowVal;
1899
+ const shadowDisplay = getShadowDisplay(activeShadow, shadowAuthoredVal, shadowTokens);
1900
+ const matchedOption = shadowOptions.find((option) => canonicalizeShadowValue(option.value) === canonicalizeShadowValue(activeShadow)) ?? null;
1901
+ const activeOption = matchedOption ?? shadowOptions[0];
1902
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1903
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-shadow-card", style: { position: "relative" }, children: [
1904
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-shadow-card-title", children: "Token" }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1906
+ "button",
1907
+ {
1908
+ className: "di-border-style-single",
1909
+ onClick: (e) => {
1910
+ const r = e.currentTarget.getBoundingClientRect();
1911
+ setDropPos(calcDropPos(r));
1912
+ setShowShadowDrop((v) => !v);
1913
+ },
1914
+ children: [
1915
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", style: activeOption.cssVar ? void 0 : { color: "#9ca3af" }, children: activeOption.label }),
1916
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: activeOption.cssVar || "none" }),
1917
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "5", viewBox: "0 0 8 5", fill: "none", style: { marginLeft: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l3 3 3-3", stroke: "#9ca3af", strokeWidth: "1.5", strokeLinecap: "round" }) })
1918
+ ]
1919
+ }
1920
+ ),
1921
+ showShadowDrop && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1922
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "fixed", inset: 0, zIndex: 99997 }, onClick: () => setShowShadowDrop(false) }),
1923
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-style-drop di-shadow-drop", style: { position: "fixed", top: dropPos.top, left: dropPos.left, zIndex: 99998 }, children: [
1924
+ shadowOptions.map((option) => {
1925
+ const isOn = canonicalizeShadowValue(option.value) === canonicalizeShadowValue(activeShadow);
1926
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1927
+ "button",
1928
+ {
1929
+ className: `di-border-style-drop-item${isOn ? " di-border-style-drop-item--on" : ""}`,
1930
+ onClick: () => {
1931
+ setPendingShadow(option.value);
1932
+ liveApply("box-shadow", option.value);
1933
+ setShowShadowDrop(false);
1934
+ },
1935
+ children: [
1936
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", style: option.cssVar ? void 0 : { color: "#9ca3af" }, children: option.label }),
1937
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "di-shadow-drop-meta", children: [
1938
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: option.cssVar || option.usage }),
1939
+ option.cssVar && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-shadow-drop-value", children: option.value })
1940
+ ] })
1941
+ ]
1942
+ },
1943
+ option.cssVar || option.label
1944
+ );
1945
+ }),
1946
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1947
+ "button",
1948
+ {
1949
+ className: `di-border-style-drop-item${matchedOption ? "" : " di-border-style-drop-item--on"}`,
1950
+ onClick: () => {
1951
+ const next = prompt("\u81EA\u5B9A\u4E49\u9634\u5F71\uFF08\u5982 0 12px 30px rgba(15,23,42,0.08)\uFF09", activeShadow === "none" ? "" : activeShadow);
1952
+ if (next === null) return;
1953
+ const value = next.trim() || "none";
1954
+ setPendingShadow(value);
1955
+ liveApply("box-shadow", value);
1956
+ setShowShadowDrop(false);
1957
+ },
1958
+ children: [
1959
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", children: "\u81EA\u5B9A\u4E49" }),
1960
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "di-shadow-drop-meta", children: [
1961
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: shadowDisplay.label }),
1962
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-shadow-drop-value", children: formatShadowDisplay(activeShadow) })
1963
+ ] })
1964
+ ]
1965
+ }
1966
+ )
1967
+ ] })
1968
+ ] })
1969
+ ] }),
1970
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-shadow-card", children: [
1971
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-shadow-card-title", children: "\u9884\u89C8" }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-shadow-preview-row", children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-shadow-preview-chip", style: { boxShadow: activeShadow === "none" ? "none" : activeShadow } }),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-shadow-preview-copy", children: [
1975
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: shadowDisplay.isHardcoded ? "di-token-name--plain" : "di-token-name", children: shadowDisplay.label }),
1976
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-hex di-hex--wrap", children: shadowDisplay.sub })
1977
+ ] })
1978
+ ] })
1979
+ ] })
1980
+ ] });
1981
+ })() })
1982
+ ] }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
1984
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u8FB9\u6846" }),
1985
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-row", children: [
1986
+ (() => {
1987
+ const bcVal = pendingBorderColor || borderColorVal;
1988
+ const { label: bcLabel, sub: bcSub, isHardcoded: bcHard } = getDisplayLabel(bcVal || "", tokenMap, colorPalette, tokenLabels);
1989
+ const bcDark = (() => {
1990
+ const m = bcVal?.match(/^#([0-9a-f]{6})$/i);
1991
+ if (!m) return false;
1992
+ const r = parseInt(m[1].slice(0, 2), 16), g = parseInt(m[1].slice(2, 4), 16), b = parseInt(m[1].slice(4, 6), 16);
1993
+ return (r * 299 + g * 587 + b * 114) / 1e3 < 128;
1994
+ })();
1995
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-card", children: [
1996
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-card-title", children: "\u989C\u8272" }),
1997
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-color-body", children: [
1998
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1999
+ "button",
2000
+ {
2001
+ className: `di-swatch-btn${bcDark ? " di-swatch-btn--dark" : ""}${!bcVal ? " di-swatch-btn--empty" : ""}`,
2002
+ style: { background: bcVal || void 0 },
2003
+ onClick: (e) => {
2004
+ const r = e.currentTarget.getBoundingClientRect();
2005
+ setDropPos(calcDropPos(r));
2006
+ setExpandedBorderColor((v) => !v);
2007
+ },
2008
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l4 4 4-4", stroke: !bcVal ? "#9ca3af" : bcDark ? "#fff" : "#374151", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2009
+ }
2010
+ ),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-color-info", children: [
2012
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: bcHard ? "di-token-name--plain" : "di-token-name", children: bcVal ? bcLabel : "\u672A\u8BBE\u7F6E" }),
2013
+ bcSub && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-hex", children: bcSub })
2014
+ ] })
2015
+ ] }),
2016
+ expandedBorderColor && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2017
+ ColorDropdown,
2018
+ {
2019
+ value: bcVal || "",
2020
+ pos: dropPos,
2021
+ colorPalette,
2022
+ onChange: (c) => {
2023
+ setPendingBorderColor(c);
2024
+ liveApply("border-color", c);
2025
+ if ((pendingBorderWidth || borderWidthVal) === "0px") {
2026
+ liveApply("border-width", "1px");
2027
+ liveApply("border-style", "solid");
2028
+ setPendingBorderWidth("1px");
2029
+ setPendingBorderStyle("solid");
2030
+ }
2031
+ },
2032
+ onClose: () => setExpandedBorderColor(false),
2033
+ onAddToken: (v) => handleAddToken(v, "border-color")
2034
+ }
2035
+ )
2036
+ ] });
2037
+ })(),
2038
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-card", style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
2039
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-card-title", children: "\u7C97\u7EC6" }),
2040
+ (() => {
2041
+ const cur = pendingBorderWidth || borderWidthVal || "0px";
2042
+ const idx = borderWidthSteps.indexOf(cur);
2043
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-spinner", children: [
2044
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-spinner-val", children: cur }),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-spinner-btns", children: [
2046
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2047
+ "button",
2048
+ {
2049
+ className: "di-spinner-up",
2050
+ disabled: idx <= 0,
2051
+ onClick: () => {
2052
+ const nv = borderWidthSteps[Math.max(0, idx - 1)];
2053
+ setPendingBorderWidth(nv);
2054
+ liveApply("border-width", nv);
2055
+ },
2056
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "5", viewBox: "0 0 8 5", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 4l3-3 3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }) })
2057
+ }
2058
+ ),
2059
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2060
+ "button",
2061
+ {
2062
+ className: "di-spinner-dn",
2063
+ disabled: idx >= borderWidthSteps.length - 1,
2064
+ onClick: () => {
2065
+ const nv = borderWidthSteps[Math.min(borderWidthSteps.length - 1, idx < 0 ? 1 : idx + 1)];
2066
+ setPendingBorderWidth(nv);
2067
+ liveApply("border-width", nv);
2068
+ },
2069
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "5", viewBox: "0 0 8 5", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l3 3 3-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", fill: "none" }) })
2070
+ }
2071
+ )
2072
+ ] })
2073
+ ] });
2074
+ })()
2075
+ ] }),
2076
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-border-card", style: { position: "relative" }, children: [
2077
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-card-title", children: "\u6837\u5F0F" }),
2078
+ (() => {
2079
+ const cur = pendingBorderStyle || borderStyleVal;
2080
+ const curOpt = BORDER_STYLE_OPTIONS.find((o) => o.value === cur) ?? BORDER_STYLE_OPTIONS[0];
2081
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2082
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2083
+ "button",
2084
+ {
2085
+ className: "di-border-style-single",
2086
+ onClick: (e) => {
2087
+ const r = e.currentTarget.getBoundingClientRect();
2088
+ setDropPos(calcDropPos(r));
2089
+ setShowStyleDrop((v) => !v);
2090
+ },
2091
+ children: [
2092
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", style: curOpt.value === "none" ? { color: "#9ca3af" } : void 0, children: curOpt.label }),
2093
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: curOpt.title }),
2094
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "5", viewBox: "0 0 8 5", fill: "none", style: { marginLeft: "auto", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1l3 3 3-3", stroke: "#9ca3af", strokeWidth: "1.5", strokeLinecap: "round" }) })
2095
+ ]
2096
+ }
2097
+ ),
2098
+ showStyleDrop && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2099
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "fixed", inset: 0, zIndex: 99997 }, onClick: () => setShowStyleDrop(false) }),
2100
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-border-style-drop", style: { position: "fixed", top: dropPos.top, left: dropPos.left, zIndex: 99998 }, children: BORDER_STYLE_OPTIONS.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2101
+ "button",
2102
+ {
2103
+ className: `di-border-style-drop-item${cur === opt.value ? " di-border-style-drop-item--on" : ""}`,
2104
+ onClick: () => {
2105
+ setPendingBorderStyle(opt.value);
2106
+ liveApply("border-style", opt.value);
2107
+ setShowStyleDrop(false);
2108
+ },
2109
+ children: [
2110
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-label", style: opt.value === "none" ? { color: "#9ca3af" } : void 0, children: opt.label }),
2111
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-border-style-name", children: opt.title })
2112
+ ]
2113
+ },
2114
+ opt.value
2115
+ )) })
2116
+ ] })
2117
+ ] });
2118
+ })()
2119
+ ] })
2120
+ ] })
2121
+ ] }),
2122
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
2123
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u5706\u89D2" }),
2124
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-preset-row", children: [
2125
+ radiusPresets.map((opt) => {
2126
+ const current = pendingRadius || radiusVal;
2127
+ const isOn = matchPreset(radiusPresets, current)?.value === opt.value;
2128
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2129
+ "button",
2130
+ {
2131
+ className: `di-preset${isOn ? " di-preset--on" : ""}`,
2132
+ onClick: () => {
2133
+ setPendingRadius(opt.value);
2134
+ setCustomRadius("");
2135
+ liveApply("border-radius", opt.value);
2136
+ },
2137
+ children: [
2138
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-preset-label", children: opt.label }),
2139
+ opt.sub && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-preset-sub", children: opt.sub })
2140
+ ]
2141
+ },
2142
+ opt.label
2143
+ );
2144
+ }),
2145
+ (() => {
2146
+ const cur = pendingRadius || radiusVal;
2147
+ const isCustom = !!cur && cur !== "0px" && !matchPreset(radiusPresets, cur);
2148
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2149
+ "button",
2150
+ {
2151
+ className: `di-preset${isCustom ? " di-preset--on" : ""}`,
2152
+ onClick: () => {
2153
+ const v = prompt("\u81EA\u5B9A\u4E49\u5706\u89D2\uFF08\u5982 12px\uFF09", cur || "");
2154
+ if (v) {
2155
+ setPendingRadius(v);
2156
+ setCustomRadius(v);
2157
+ liveApply("border-radius", v);
2158
+ }
2159
+ },
2160
+ children: [
2161
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-preset-label", children: "\u81EA\u5B9A\u4E49" }),
2162
+ isCustom && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-preset-sub", children: cur })
2163
+ ]
2164
+ }
2165
+ );
2166
+ })()
2167
+ ] })
2168
+ ] }),
2169
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
2170
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u95F4\u8DDD" }),
2171
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-space-row", children: [
2172
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2173
+ SpaceCard,
2174
+ {
2175
+ title: "\u5185\u8FB9\u8DDD",
2176
+ variant: "padding",
2177
+ value: pendingPadding || paddingVal,
2178
+ spaceSteps,
2179
+ onChange: (v) => {
2180
+ setPendingPadding(v);
2181
+ liveApply("padding", v);
2182
+ }
2183
+ }
2184
+ ),
2185
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2186
+ SpaceCard,
2187
+ {
2188
+ title: "\u5916\u8FB9\u8DDD",
2189
+ variant: "margin",
2190
+ value: pendingMargin || marginVal,
2191
+ spaceSteps,
2192
+ onChange: (v) => {
2193
+ setPendingMargin(v);
2194
+ liveApply("margin", v);
2195
+ }
2196
+ }
2197
+ ),
2198
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2199
+ SpaceCard,
2200
+ {
2201
+ title: "\u5143\u7D20\u95F4\u8DDD",
2202
+ variant: "gap",
2203
+ value: pendingGap || gapVal,
2204
+ spaceSteps,
2205
+ onChange: (v) => {
2206
+ setPendingGap(v);
2207
+ liveApply("gap", v);
2208
+ }
2209
+ }
2210
+ )
2211
+ ] })
2212
+ ] }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-section", children: [
2214
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-section-title", children: "\u672C\u6B21\u4FEE\u6539\u5185\u5BB9" }),
2215
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-inbox-summary", children: [
2216
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-inbox-pill", children: [
2217
+ "\u5DF2\u8BB0\u5F55 ",
2218
+ styleIntentSummary.pendingCount
2219
+ ] }),
2220
+ (() => {
2221
+ const currentChanges = getPendingChangeRecords();
2222
+ if (currentChanges.length === 0) return null;
2223
+ const el = selectedRef.current;
2224
+ const targetClasses = el ? getClasses(el) : [];
2225
+ const targetLabel = el ? targetClasses.length ? `${el.tagName.toLowerCase()}.${targetClasses.join(".")}` : el.tagName.toLowerCase() : "\u5F53\u524D\u5BF9\u8C61";
2226
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-inbox-list", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-inbox-card di-inbox-card--draft", children: [
2227
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-inbox-card-head", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-inbox-target", children: targetLabel }) }),
2228
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ol", { className: "di-inbox-change-list", children: currentChanges.map((change, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "di-inbox-change-item", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "di-inbox-change-text", children: [
2229
+ idx + 1,
2230
+ ". ",
2231
+ getChangeLabel(change.prop),
2232
+ "\uFF1A",
2233
+ change.from,
2234
+ " \u2192 ",
2235
+ change.val
2236
+ ] }) }, `current-${change.prop}-${idx}`)) })
2237
+ ] }) });
2238
+ })(),
2239
+ styleIntentSummary.pendingEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-inbox-list", children: styleIntentSummary.pendingEntries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-inbox-card", children: [
2240
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-inbox-card-head", children: [
2241
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-inbox-target", children: entry.targetLabel || entry.selector || "\u672A\u547D\u540D\u5BF9\u8C61" }),
2242
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-inbox-delete", onClick: () => handleDeleteStyleIntent(entry.id), children: "\u5220\u9664\u5BF9\u8C61" })
2243
+ ] }),
2244
+ entry.note ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-inbox-note", children: entry.note }) : null,
2245
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ol", { className: "di-inbox-change-list", children: entry.entries.flatMap((group) => group.changes.map((change) => ({ selector: group.selector, ...change }))).map((change, idx) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "di-inbox-change-item", children: [
2246
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "di-inbox-change-text", children: [
2247
+ idx + 1,
2248
+ ". ",
2249
+ getChangeLabel(change.prop),
2250
+ "\uFF1A",
2251
+ change.from ? `${change.from} \u2192 ` : "",
2252
+ change.val
2253
+ ] }),
2254
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2255
+ "button",
2256
+ {
2257
+ className: "di-inbox-delete di-inbox-delete--mini",
2258
+ onClick: () => handleDeleteStyleIntent(entry.id, change.selector, change.prop),
2259
+ children: "\u5220\u9664"
2260
+ }
2261
+ )
2262
+ ] }, `${entry.id}-${change.selector}-${change.prop}-${idx}`)) })
2263
+ ] }, entry.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-empty", children: "\u8FD8\u6CA1\u6709\u8BB0\u5F55\u7684\u4FEE\u6539" })
2264
+ ] })
2265
+ ] })
2266
+ ] }),
2267
+ (() => {
2268
+ const hasPending = Object.keys(pendingColors).length > 0 || !!pendingTextColor || !!pendingRadius || !!pendingShadow || !!pendingBorderColor || !!pendingBorderWidth || !!pendingBorderStyle || !!pendingFontSize || !!pendingFontWeight || !!pendingPadding || !!pendingMargin || !!pendingGap || !!pendingTranslate || !!pendingWidth || !!pendingHeight || !!note;
2269
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-foot", children: [
2270
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-btn-cancel", onClick: handleReset, children: "\u91CD\u7F6E" }),
2271
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-btn-cancel", onClick: () => {
2272
+ const el = selectedRef.current;
2273
+ if (!el) return;
2274
+ const effectiveColors = { ...colors, ...pendingColors };
2275
+ const pending = [
2276
+ ...Object.entries(effectiveColors).filter(([, v]) => v && v !== "transparent"),
2277
+ [pendingTextColor || textColorVal ? "color" : "", pendingTextColor || textColorVal],
2278
+ [pendingRadius || radiusVal ? "border-radius" : "", pendingRadius || radiusVal],
2279
+ [pendingShadow || (shadowVal !== "none" ? shadowVal : "") ? "box-shadow" : "", pendingShadow || (shadowVal !== "none" ? shadowVal : "")],
2280
+ [pendingBorderColor || borderColorVal ? "border-color" : "", pendingBorderColor || borderColorVal],
2281
+ [pendingBorderWidth || (borderWidthVal !== "0px" ? borderWidthVal : "") ? "border-width" : "", pendingBorderWidth || borderWidthVal],
2282
+ [pendingBorderStyle || (borderStyleVal !== "none" ? borderStyleVal : "") ? "border-style" : "", pendingBorderStyle || borderStyleVal],
2283
+ [pendingFontSize || fontSizeVal ? "font-size" : "", pendingFontSize || fontSizeVal],
2284
+ [pendingFontWeight || fontWeightVal ? "font-weight" : "", pendingFontWeight || fontWeightVal],
2285
+ [pendingPadding || (paddingVal !== "0px" ? paddingVal : "") ? "padding" : "", pendingPadding || paddingVal],
2286
+ [pendingMargin || (marginVal !== "0px" ? marginVal : "") ? "margin" : "", pendingMargin || marginVal],
2287
+ [pendingGap || (gapVal !== "0px" ? gapVal : "") ? "gap" : "", pendingGap || gapVal],
2288
+ [pendingWidth || widthVal ? "width" : "", pendingWidth || widthVal],
2289
+ [pendingHeight || heightVal ? "height" : "", pendingHeight || heightVal]
2290
+ ].filter(([k, v]) => k && v);
2291
+ const selector = getSelectorForScope(el, scope);
2292
+ const css = pending.length > 0 ? `${selector} {
2293
+ ${pending.map(([p, v]) => ` ${p}: ${v};`).join("\n")}
2294
+ }` : `/* ${selector} \u2014 \u6682\u65E0\u6539\u52A8 */`;
2295
+ const ta = document.createElement("textarea");
2296
+ ta.value = css;
2297
+ ta.style.cssText = "position:fixed;opacity:0;top:0;left:0";
2298
+ document.body.appendChild(ta);
2299
+ ta.select();
2300
+ document.execCommand("copy");
2301
+ document.body.removeChild(ta);
2302
+ _copiedStyles = pending.map(([p, v]) => ({ prop: p, val: v }));
2303
+ setHasCopied(true);
2304
+ setCopyMsg("\u5DF2\u590D\u5236 \u2713");
2305
+ setTimeout(() => setCopyMsg(""), 1500);
2306
+ }, children: copyMsg || "\u590D\u5236\u6837\u5F0F" }),
2307
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2308
+ "button",
2309
+ {
2310
+ className: "di-btn-save",
2311
+ onClick: handleSubmitToAi,
2312
+ disabled: !hasPending,
2313
+ style: !hasPending ? { opacity: 0.4, cursor: "not-allowed" } : {},
2314
+ title: "\u590D\u5236\u4E00\u6BB5\u53EF\u76F4\u63A5\u53D1\u7ED9 AI \u7684\u4EFB\u52A1\u6587\u672C",
2315
+ children: submitMsg || "\u53D1\u9001\u7ED9AI"
2316
+ }
2317
+ )
2318
+ ] });
2319
+ })(),
2320
+ hasCopied && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-paste-bar", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: "di-btn-paste", onClick: () => {
2321
+ _copiedStyles.forEach(({ prop, val }) => {
2322
+ if (prop === "background-color" || prop === "background")
2323
+ setPendingColors((prev) => ({ ...prev, [prop]: val }));
2324
+ else if (prop === "color") setPendingTextColor(val);
2325
+ else if (prop === "border-radius") setPendingRadius(val);
2326
+ else if (prop === "box-shadow") setPendingShadow(val);
2327
+ else if (prop === "border-color") setPendingBorderColor(val);
2328
+ else if (prop === "border-width") setPendingBorderWidth(val);
2329
+ else if (prop === "border-style") setPendingBorderStyle(val);
2330
+ else if (prop === "font-size") setPendingFontSize(val);
2331
+ else if (prop === "font-weight") setPendingFontWeight(val);
2332
+ else if (prop === "padding") setPendingPadding(val);
2333
+ else if (prop === "margin") setPendingMargin(val);
2334
+ else if (prop === "gap") setPendingGap(val);
2335
+ else if (prop === "width") setPendingWidth(val);
2336
+ else if (prop === "height") setPendingHeight(val);
2337
+ });
2338
+ applyToDOM(_copiedStyles);
2339
+ }, children: [
2340
+ "\u7C98\u8D34\u6837\u5F0F\uFF08",
2341
+ _copiedStyles.length,
2342
+ " \u4E2A\u5C5E\u6027\uFF09"
2343
+ ] }) })
2344
+ ]
2345
+ }
2346
+ )
2347
+ ] });
2348
+ }
2349
+ var CODE_FILES = [
2350
+ { name: "src/", desc: "React \u7EC4\u4EF6\u3001\u9875\u9762\u3001\u6837\u5F0F\u6E90\u7801\uFF08\u4E0D\u542B\u8C03\u8BD5\u5DE5\u5177\uFF09" },
2351
+ { name: "index.html", desc: "\u5E94\u7528\u5165\u53E3 HTML" },
2352
+ { name: "package.json", desc: "\u4F9D\u8D56\u5305\u4E0E\u811A\u672C\u914D\u7F6E" },
2353
+ { name: "tsconfig.json", desc: "TypeScript \u7F16\u8BD1\u914D\u7F6E" },
2354
+ { name: "vite.config.ts", desc: "\u6784\u5EFA\u5DE5\u5177\u914D\u7F6E" }
2355
+ ];
2356
+ var PRODUCT_FILES = [
2357
+ { name: "docs/PRODUCT_PLAN.md", desc: "\u4EA7\u54C1\u89C4\u5212\u4E0E\u8DEF\u7EBF\u56FE" },
2358
+ { name: "docs/PROJECT.md", desc: "\u9879\u76EE\u80CC\u666F\u4E0E\u76EE\u6807\u6982\u8FF0" },
2359
+ { name: "docs/DECISIONS.md", desc: "\u5173\u952E\u4EA7\u54C1\u51B3\u7B56\u8BB0\u5F55" },
2360
+ { name: "docs/CHANGELOG.md", desc: "\u529F\u80FD\u8FED\u4EE3\u53D8\u66F4\u65E5\u5FD7" },
2361
+ { name: "docs/CODE_STRUCTURE.md", desc: "\u524D\u7AEF\u76EE\u5F55\u7ED3\u6784\u8BF4\u660E" },
2362
+ { name: "docs/DESIGN_STANDARDS.md", desc: "\u8BBE\u8BA1\u89C4\u8303\u603B\u89C8" }
2363
+ ];
2364
+ var DESIGN_FILES = [
2365
+ { name: "docs/design/OVERVIEW.md", desc: "\u8BBE\u8BA1\u7CFB\u7EDF\u603B\u89C8" },
2366
+ { name: "docs/design/tokens.md", desc: "Design Token \u4F7F\u7528\u8BF4\u660E" },
2367
+ { name: "docs/design/layout.md", desc: "\u9875\u9762\u5E03\u5C40\u89C4\u8303" },
2368
+ { name: "docs/design/component-index.md", desc: "\u7EC4\u4EF6\u6E05\u5355\u7D22\u5F15" },
2369
+ { name: "docs/design/business-components.md", desc: "\u4E1A\u52A1\u7EC4\u4EF6\u8BF4\u660E" }
2370
+ ];
2371
+ function FileList({ files }) {
2372
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "di-dl-file-list", children: files.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
2373
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-dl-file-name", children: f.name }),
2374
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-dl-file-desc", children: f.desc })
2375
+ ] }, f.name)) });
2376
+ }
2377
+ function DownloadButton() {
2378
+ const { endpoints } = useDevInspectorConfig();
2379
+ const [open, setOpen] = (0, import_react2.useState)(false);
2380
+ const [status, setStatus] = (0, import_react2.useState)("idle");
2381
+ const [filePath, setFilePath] = (0, import_react2.useState)("");
2382
+ const [details, setDetails] = (0, import_react2.useState)({ code: false, product: false, design: false });
2383
+ const [opts, setOpts] = (0, import_react2.useState)({ code: true, product: false, design: false });
2384
+ function toggle(k) {
2385
+ setOpts((prev) => ({ ...prev, [k]: !prev[k] }));
2386
+ }
2387
+ function toggleDetail(k) {
2388
+ setDetails((prev) => ({ ...prev, [k]: !prev[k] }));
2389
+ }
2390
+ function handleOpen() {
2391
+ setOpen((v) => !v);
2392
+ if (open) setStatus("idle");
2393
+ }
2394
+ async function download() {
2395
+ if (!opts.code && !opts.product && !opts.design) return;
2396
+ setStatus("packing");
2397
+ try {
2398
+ const params = new URLSearchParams({
2399
+ code: opts.code ? "1" : "0",
2400
+ product: opts.product ? "1" : "0",
2401
+ design: opts.design ? "1" : "0"
2402
+ });
2403
+ const res = await fetch(`${endpoints.handoff}?${params}`);
2404
+ const json = await res.json();
2405
+ if (!json.ok) throw new Error(json.error);
2406
+ setFilePath(json.path);
2407
+ setStatus("done");
2408
+ } catch {
2409
+ setStatus("error");
2410
+ }
2411
+ }
2412
+ async function revealInFinder() {
2413
+ await fetch(`${endpoints.reveal}?path=${encodeURIComponent(filePath)}`);
2414
+ }
2415
+ const sections = [
2416
+ { key: "code", label: "\u524D\u7AEF\u4EE3\u7801", files: CODE_FILES },
2417
+ { key: "product", label: "\u4EA7\u54C1\u6587\u6863", files: PRODUCT_FILES },
2418
+ { key: "design", label: "\u8BBE\u8BA1\u6587\u6863", files: DESIGN_FILES }
2419
+ ];
2420
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2421
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-dl-btn", onClick: handleOpen, children: "\u4E0B\u8F7D" }),
2422
+ open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-dl-modal", children: [
2423
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-dl-title", children: "\u9009\u62E9\u4E0B\u8F7D\u5185\u5BB9" }),
2424
+ status === "packing" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-dl-status", children: [
2425
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "di-dl-spinner" }),
2426
+ "\u6B63\u5728\u6253\u5305\uFF0C\u8BF7\u7A0D\u5019\u2026"
2427
+ ] }),
2428
+ status === "done" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-dl-done", children: [
2429
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-dl-done-check", children: "\u2713 \u5DF2\u4FDD\u5B58\u81F3\u684C\u9762" }),
2430
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-dl-done-path", children: filePath.replace(/.*\//, "") }),
2431
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-dl-reveal-btn", onClick: revealInFinder, children: "\u5728 Finder \u4E2D\u663E\u793A" })
2432
+ ] }),
2433
+ status === "error" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "di-dl-status di-dl-status--error", children: "\u6253\u5305\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u63A7\u5236\u53F0" }),
2434
+ (status === "idle" || status === "error") && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2435
+ sections.map(({ key, label, files }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
2436
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-dl-row", children: [
2437
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "di-dl-check-label", children: [
2438
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: opts[key], onChange: () => toggle(key) }),
2439
+ label
2440
+ ] }),
2441
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "di-dl-detail-btn", onClick: () => toggleDetail(key), children: details[key] ? "\u6536\u8D77" : "\u8BE6\u60C5" })
2442
+ ] }),
2443
+ details[key] && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FileList, { files })
2444
+ ] }, key)),
2445
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2446
+ "button",
2447
+ {
2448
+ className: "di-dl-confirm",
2449
+ onClick: download,
2450
+ disabled: !opts.code && !opts.product && !opts.design,
2451
+ children: "\u4E0B\u8F7D"
2452
+ }
2453
+ )
2454
+ ] })
2455
+ ] })
2456
+ ] });
2457
+ }
2458
+ function DevInspector() {
2459
+ const [active, setActive] = (0, import_react2.useState)(false);
2460
+ const [tokenMap, setTokenMap] = (0, import_react2.useState)({});
2461
+ const [panels, setPanels] = (0, import_react2.useState)([]);
2462
+ const modalOpenRef = (0, import_react2.useRef)(false);
2463
+ (0, import_react2.useEffect)(() => {
2464
+ setTokenMap(scanTokenMap());
2465
+ }, []);
2466
+ (0, import_react2.useEffect)(() => {
2467
+ const fn = (e) => {
2468
+ if (e.altKey && e.key === "i") setActive((v) => !v);
2469
+ if (e.key === "Escape") {
2470
+ setActive(false);
2471
+ setPanels([]);
2472
+ }
2473
+ };
2474
+ window.addEventListener("keydown", fn);
2475
+ return () => window.removeEventListener("keydown", fn);
2476
+ }, []);
2477
+ (0, import_react2.useEffect)(() => {
2478
+ const onOver = (e) => {
2479
+ if (!active || modalOpenRef.current) return;
2480
+ const el = e.target;
2481
+ if (!el?.classList) return;
2482
+ if (isInsidePanel(el)) {
2483
+ el.classList.remove("di-hover");
2484
+ return;
2485
+ }
2486
+ el.classList.add("di-hover");
2487
+ };
2488
+ const onOut = (e) => {
2489
+ e.target?.classList?.remove("di-hover");
2490
+ };
2491
+ const onClick = (e) => {
2492
+ if (!active || modalOpenRef.current) return;
2493
+ const el = e.target;
2494
+ if (isInsidePanel(el)) return;
2495
+ e.preventDefault();
2496
+ e.stopPropagation();
2497
+ el.classList.remove("di-hover");
2498
+ setPanels(
2499
+ (prev) => prev.length === 0 ? [{ id: "main", el }] : prev.map((p, i) => i === 0 ? { ...p, el } : p)
2500
+ );
2501
+ };
2502
+ document.addEventListener("mouseover", onOver, true);
2503
+ document.addEventListener("mouseout", onOut, true);
2504
+ document.addEventListener("click", onClick, true);
2505
+ return () => {
2506
+ document.removeEventListener("mouseover", onOver, true);
2507
+ document.removeEventListener("mouseout", onOut, true);
2508
+ document.removeEventListener("click", onClick, true);
2509
+ };
2510
+ }, [active]);
2511
+ (0, import_react2.useEffect)(() => {
2512
+ if (!active) {
2513
+ document.querySelectorAll(".di-selected,.di-hover").forEach((e) => e.classList.remove("di-selected", "di-hover"));
2514
+ }
2515
+ }, [active]);
2516
+ (0, import_react2.useEffect)(() => {
2517
+ document.body.style.cursor = active ? "crosshair" : "";
2518
+ return () => {
2519
+ document.body.style.cursor = "";
2520
+ };
2521
+ }, [active]);
2522
+ const primaryEl = panels[0]?.el;
2523
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2524
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DownloadButton, {}),
2525
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2526
+ "button",
2527
+ {
2528
+ className: `di-trigger${active ? " di-trigger--on" : ""}`,
2529
+ onClick: () => {
2530
+ setActive((v) => !v);
2531
+ if (active) setPanels([]);
2532
+ },
2533
+ title: "Dev Inspector (Alt+I)",
2534
+ children: active ? "\u9000\u51FA" : "\u7F16\u8F91"
2535
+ }
2536
+ ),
2537
+ active && primaryEl && (() => {
2538
+ const rect = primaryEl.getBoundingClientRect();
2539
+ const classes = getClasses(primaryEl);
2540
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "di-label", style: { top: rect.top - 34, left: rect.left + rect.width / 2 }, children: [
2541
+ "\u5DF2\u9009\u4E2D ",
2542
+ classes[0] ?? primaryEl.tagName.toLowerCase()
2543
+ ] });
2544
+ })(),
2545
+ panels.map((p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2546
+ InspectorPanel,
2547
+ {
2548
+ targetEl: p.el,
2549
+ tokenMap,
2550
+ onTokenMapUpdate: (updates) => setTokenMap((prev) => ({ ...prev, ...updates })),
2551
+ onClose: () => setPanels((prev) => prev.filter((x) => x.id !== p.id))
2552
+ },
2553
+ p.id
2554
+ ))
2555
+ ] });
2556
+ }
2557
+
2558
+ // src/mount.tsx
2559
+ var import_react3 = require("react");
2560
+ var import_client = require("react-dom/client");
2561
+ var import_jsx_runtime3 = require("react/jsx-runtime");
2562
+ function mountDevInspector(config) {
2563
+ const resolved = mergeDevInspectorConfig(config);
2564
+ const existingRoot = document.getElementById(resolved.rootId);
2565
+ if (existingRoot) return existingRoot;
2566
+ const devRoot = document.createElement("div");
2567
+ devRoot.id = resolved.rootId;
2568
+ document.body.appendChild(devRoot);
2569
+ (0, import_client.createRoot)(devRoot).render(
2570
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react3.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DevInspectorProvider, { config: resolved, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DevInspector, {}) }) })
2571
+ );
2572
+ return devRoot;
2573
+ }
2574
+ // Annotate the CommonJS export names for ESM import in node:
2575
+ 0 && (module.exports = {
2576
+ DevInspector,
2577
+ DevInspectorProvider,
2578
+ InspectorPanel,
2579
+ defaultDevInspectorConfig,
2580
+ mergeDevInspectorConfig,
2581
+ mountDevInspector,
2582
+ useDevInspectorConfig
2583
+ });
2584
+ //# sourceMappingURL=index.cjs.map