uivisor 0.1.4 → 0.1.6
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/overlay/index.js +472 -44
- package/package.json +1 -1
package/dist/overlay/index.js
CHANGED
|
@@ -542,6 +542,155 @@ var SHORTHAND_SETS = [
|
|
|
542
542
|
}
|
|
543
543
|
];
|
|
544
544
|
|
|
545
|
+
// src/overlay/designtokens.ts
|
|
546
|
+
var COLOR_RE = /^(#[0-9a-f]{3,8}|rgba?\(|hsla?\()/i;
|
|
547
|
+
var LEN_RE = /^-?\d*\.?\d+(px|rem|em)$/i;
|
|
548
|
+
var SHADOW_RE = /\d+px.*(rgba?\(|hsla?\(|#[0-9a-f]{3,8})/i;
|
|
549
|
+
var FONT_STACK_RE = /(sans-serif|serif|monospace|system-ui|,)/i;
|
|
550
|
+
var isColor = (v) => COLOR_RE.test(v.trim());
|
|
551
|
+
var isLen = (v) => LEN_RE.test(v.trim());
|
|
552
|
+
function lenToPx(value, rootPx = 16) {
|
|
553
|
+
const m = /^(-?\d*\.?\d+)(px|rem|em)$/i.exec(value.trim());
|
|
554
|
+
if (!m) return null;
|
|
555
|
+
const n = parseFloat(m[1]);
|
|
556
|
+
const unit = m[2].toLowerCase();
|
|
557
|
+
if (unit === "px") return n;
|
|
558
|
+
return n * rootPx;
|
|
559
|
+
}
|
|
560
|
+
var PREFIXES = [
|
|
561
|
+
{ re: /^--font-size-/, cat: "font-size" },
|
|
562
|
+
{ re: /^--fs-/, cat: "font-size" },
|
|
563
|
+
{ re: /^--text-/, cat: "font-size" },
|
|
564
|
+
// only when value is a length (handled below)
|
|
565
|
+
{ re: /^--leading-/, cat: "line-height" },
|
|
566
|
+
{ re: /^--line-height-/, cat: "line-height" },
|
|
567
|
+
{ re: /^--tracking-/, cat: "letter-spacing" },
|
|
568
|
+
{ re: /^--letter-spacing-/, cat: "letter-spacing" },
|
|
569
|
+
{ re: /^--radius-/, cat: "radius" },
|
|
570
|
+
{ re: /^--rounded-/, cat: "radius" },
|
|
571
|
+
{ re: /^--shadow-/, cat: "shadow" },
|
|
572
|
+
{ re: /^--space-/, cat: "spacing" },
|
|
573
|
+
{ re: /^--spacing-/, cat: "spacing" },
|
|
574
|
+
{ re: /^--gap-/, cat: "spacing" },
|
|
575
|
+
{ re: /^--airy-/, cat: "spacing" },
|
|
576
|
+
{ re: /^--color-/, cat: "color" },
|
|
577
|
+
{ re: /^--bg-/, cat: "color" },
|
|
578
|
+
{ re: /^--border-/, cat: "color" },
|
|
579
|
+
{ re: /^--font-/, cat: "font-family" }
|
|
580
|
+
];
|
|
581
|
+
var FONTSIZE_HINT = /(^|[-_])(fs|font-size|text|headline|title|body|label|display|caption|heading)([-_]|$)/i;
|
|
582
|
+
var SPACING_HINT = /(^|[-_])(space|spacing|gap|airy|inset)([-_]|$)/i;
|
|
583
|
+
function classifyVar(name, value) {
|
|
584
|
+
const v = value.trim();
|
|
585
|
+
const n = name.toLowerCase();
|
|
586
|
+
if (!v) return null;
|
|
587
|
+
if (n.includes("shadow") || SHADOW_RE.test(v)) return "shadow";
|
|
588
|
+
if (isColor(v)) return "color";
|
|
589
|
+
if (FONT_STACK_RE.test(v) && !isLen(v)) {
|
|
590
|
+
if (n.includes("family") || /^--font(-|$)/.test(n) || FONT_STACK_RE.test(v)) return "font-family";
|
|
591
|
+
}
|
|
592
|
+
if (isLen(v)) {
|
|
593
|
+
if (n.includes("radius") || n.includes("rounded")) return "radius";
|
|
594
|
+
if (n.includes("leading") || n.includes("line-height")) return "line-height";
|
|
595
|
+
if (n.includes("tracking") || n.includes("letter")) return "letter-spacing";
|
|
596
|
+
if (FONTSIZE_HINT.test(n)) return "font-size";
|
|
597
|
+
if (SPACING_HINT.test(n)) return "spacing";
|
|
598
|
+
return null;
|
|
599
|
+
}
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
function tokenName(cssVar, _category) {
|
|
603
|
+
for (const p of PREFIXES) {
|
|
604
|
+
if (p.re.test(cssVar)) return cssVar.replace(p.re, "");
|
|
605
|
+
}
|
|
606
|
+
return cssVar.replace(/^--/, "");
|
|
607
|
+
}
|
|
608
|
+
function buildDesignSystem(vars, rootPx = 16) {
|
|
609
|
+
const tokens = [];
|
|
610
|
+
for (const [cssVar, value] of Object.entries(vars)) {
|
|
611
|
+
const category = classifyVar(cssVar, value);
|
|
612
|
+
if (!category) continue;
|
|
613
|
+
const scalar = category === "font-size" || category === "radius" || category === "spacing";
|
|
614
|
+
tokens.push({
|
|
615
|
+
cssVar,
|
|
616
|
+
name: tokenName(cssVar, category),
|
|
617
|
+
category,
|
|
618
|
+
value: value.trim(),
|
|
619
|
+
px: scalar ? lenToPx(value, rootPx) : null
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
const byCategory = {};
|
|
623
|
+
for (const t of tokens) (byCategory[t.category] ||= []).push(t);
|
|
624
|
+
for (const cat of Object.keys(byCategory)) {
|
|
625
|
+
byCategory[cat].sort(
|
|
626
|
+
(a, b) => a.px != null && b.px != null ? a.px - b.px : a.name.localeCompare(b.name)
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
return { tokens, byCategory, source: tokens.length ? "css-vars" : "none" };
|
|
630
|
+
}
|
|
631
|
+
function nearestToken(ds, category, target) {
|
|
632
|
+
const list = ds.byCategory[category];
|
|
633
|
+
if (!list || !list.length) return null;
|
|
634
|
+
if (target.value != null) {
|
|
635
|
+
const norm = (s) => {
|
|
636
|
+
const t = s.trim();
|
|
637
|
+
return (rgbToHex(t) || t).replace(/\s+/g, "").toLowerCase();
|
|
638
|
+
};
|
|
639
|
+
const want = norm(target.value);
|
|
640
|
+
const hit = list.find((t) => norm(t.value) === want);
|
|
641
|
+
if (hit) return { token: hit, exact: true };
|
|
642
|
+
}
|
|
643
|
+
if (target.px != null && list.some((t) => t.px != null)) {
|
|
644
|
+
let best = list[0];
|
|
645
|
+
let bestD = Infinity;
|
|
646
|
+
for (const t of list) {
|
|
647
|
+
if (t.px == null) continue;
|
|
648
|
+
const d = Math.abs(t.px - target.px);
|
|
649
|
+
if (d < bestD) {
|
|
650
|
+
bestD = d;
|
|
651
|
+
best = t;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return { token: best, exact: bestD < 0.5 };
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
var SCALAR_VAR_SELECTOR = /(^|[\s,>])(:root|html|\[data-theme)/i;
|
|
659
|
+
function detectDesignSystem() {
|
|
660
|
+
if (typeof document === "undefined") return { tokens: [], byCategory: {}, source: "none" };
|
|
661
|
+
const names = /* @__PURE__ */ new Set();
|
|
662
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
663
|
+
let rules;
|
|
664
|
+
try {
|
|
665
|
+
rules = sheet.cssRules;
|
|
666
|
+
} catch {
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
for (const rule of Array.from(rules)) collectVarNames(rule, names);
|
|
670
|
+
}
|
|
671
|
+
const root = document.documentElement;
|
|
672
|
+
const cs = getComputedStyle(root);
|
|
673
|
+
const rootPx = parseFloat(cs.fontSize) || 16;
|
|
674
|
+
const vars = {};
|
|
675
|
+
for (const name of names) {
|
|
676
|
+
const resolved = cs.getPropertyValue(name).trim();
|
|
677
|
+
if (resolved) vars[name] = resolved;
|
|
678
|
+
}
|
|
679
|
+
return buildDesignSystem(vars, rootPx);
|
|
680
|
+
}
|
|
681
|
+
function collectVarNames(rule, out) {
|
|
682
|
+
const style = rule.style;
|
|
683
|
+
const selector = rule.selectorText;
|
|
684
|
+
if (style && selector && SCALAR_VAR_SELECTOR.test(selector)) {
|
|
685
|
+
for (let i = 0; i < style.length; i++) {
|
|
686
|
+
const prop = style[i];
|
|
687
|
+
if (prop.startsWith("--")) out.add(prop);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const inner = rule.cssRules;
|
|
691
|
+
if (inner) for (const r of Array.from(inner)) collectVarNames(r, out);
|
|
692
|
+
}
|
|
693
|
+
|
|
545
694
|
// src/overlay/mechanism.ts
|
|
546
695
|
var TW_UTILITY = /^-?(?:p|m|px|py|pt|pr|pb|pl|mx|my|mt|mr|mb|ml|gap|w|h|min-w|max-w|min-h|max-h|text|bg|border|rounded|flex|grid|gap-x|gap-y|items|justify|self|place|font|leading|tracking|space|inline|block|inline-block|hidden|table|absolute|relative|fixed|sticky|static|top|bottom|left|right|inset|z|shadow|opacity|transition|duration|ease|scale|rotate|translate|cursor|overflow|object|aspect|order|col|row|basis|grow|shrink|divide|ring|outline)(?:-|$)/;
|
|
547
696
|
var TW_VARIANT = /^(?:sm|md|lg|xl|2xl|hover|focus|focus-visible|focus-within|active|visited|disabled|dark|group|group-hover|peer|first|last|odd|even|motion-safe|motion-reduce|print|rtl|ltr)::?|^(?:sm|md|lg|xl|2xl|hover|focus|active|disabled|dark|group-hover):/;
|
|
@@ -667,6 +816,7 @@ function renderPrompt(records) {
|
|
|
667
816
|
lines.push("");
|
|
668
817
|
let anyClassTarget = false;
|
|
669
818
|
let anyNewClass = false;
|
|
819
|
+
let anyDesignToken = false;
|
|
670
820
|
active.forEach((r, i) => {
|
|
671
821
|
const id = r.identity;
|
|
672
822
|
const newClass = r.target?.startsWith("new:") ? r.target.slice(4) : null;
|
|
@@ -718,7 +868,15 @@ function renderPrompt(records) {
|
|
|
718
868
|
const scope = bp === "base" ? "all sizes (base)" : `${bp} breakpoint (\u2265${byBp[bp][0].breakpointPx}px)`;
|
|
719
869
|
lines.push(`- At ${scope}:`);
|
|
720
870
|
for (const c of byBp[bp]) {
|
|
721
|
-
|
|
871
|
+
let suggestion = "";
|
|
872
|
+
if (c.after.token) {
|
|
873
|
+
suggestion = ` \u2192 \`${variant(bp, c.after.token)}\``;
|
|
874
|
+
} else if (c.after.designToken) {
|
|
875
|
+
const at = bp === "base" ? "" : ` (scope to ${bp})`;
|
|
876
|
+
suggestion = ` \u2192 use design token \`${c.after.designToken}\` (\`var(${c.after.designToken})\`)${at}`;
|
|
877
|
+
}
|
|
878
|
+
if (c.after.designToken || c.after.token && /^(text|bg|border|rounded|shadow)-(?!\[)/.test(c.after.token))
|
|
879
|
+
anyDesignToken = true;
|
|
722
880
|
lines.push(
|
|
723
881
|
` - ${c.property}: ${c.before.computed} \u2192 ${c.after.computed}${suggestion}`
|
|
724
882
|
);
|
|
@@ -747,6 +905,11 @@ function renderPrompt(records) {
|
|
|
747
905
|
"- When creating a new class, leave the current classes untouched and add the new class alongside them; pick the styling mechanism the project already uses."
|
|
748
906
|
);
|
|
749
907
|
}
|
|
908
|
+
if (anyDesignToken) {
|
|
909
|
+
lines.push(
|
|
910
|
+
"- Prefer the project DESIGN TOKEN shown for each change (a Tailwind utility like `text-headline-l`, or the CSS variable `var(--\u2026)`) over a hardcoded px/hex value \u2014 these come from the project\u2019s own design system."
|
|
911
|
+
);
|
|
912
|
+
}
|
|
750
913
|
return lines.join("\n");
|
|
751
914
|
}
|
|
752
915
|
function renderSpec(records, meta) {
|
|
@@ -1002,6 +1165,25 @@ var CSS = (
|
|
|
1002
1165
|
.uiv-newclass:focus { border-style: solid; border-color: #6366f1; color: #fff; }
|
|
1003
1166
|
.uiv-newclass.on { border-style: solid; border-color: #22d3ee; color: #fff; }
|
|
1004
1167
|
|
|
1168
|
+
/* ---- design-system indicator + token pickers ---- */
|
|
1169
|
+
.uiv-dsbar { padding: 7px 12px; border-bottom: 1px solid #27272a;
|
|
1170
|
+
font-size: 10px; font-weight: 600; letter-spacing: .3px; color: #a5b4fc;
|
|
1171
|
+
background: #1e1b4b33; display: flex; align-items: center; gap: 6px; }
|
|
1172
|
+
.uiv-tlabel { color: #818cf8 !important; font-size: 10px; }
|
|
1173
|
+
.uiv-ctl select.uiv-tokensel {
|
|
1174
|
+
width: 100%; background: #1e1b4b55; border: 1px solid #4338ca; color: #c7d2fe;
|
|
1175
|
+
border-radius: 7px; padding: 6px 7px; font-size: 11px; outline: none;
|
|
1176
|
+
font-family: ui-monospace, monospace; }
|
|
1177
|
+
.uiv-ctl select.uiv-tokensel:hover { border-color: #6366f1; color: #fff; }
|
|
1178
|
+
.uiv-ctl select.uiv-tokensel:focus { border-color: #818cf8; }
|
|
1179
|
+
.uiv-ctl select.uiv-tokensel.changed { border-color: #4ade80; color: #86efac; }
|
|
1180
|
+
.uiv-swatches { display: flex; flex-wrap: wrap; gap: 5px; }
|
|
1181
|
+
.uiv-swatch { width: 20px; height: 20px; border-radius: 5px; cursor: pointer;
|
|
1182
|
+
border: 1px solid rgba(255,255,255,0.18); padding: 0; outline: none;
|
|
1183
|
+
box-shadow: inset 0 0 0 1px rgba(0,0,0,0.15); }
|
|
1184
|
+
.uiv-swatch:hover { transform: scale(1.12); border-color: #fff; }
|
|
1185
|
+
.uiv-swatch.on { box-shadow: 0 0 0 2px #18181b, 0 0 0 3.5px #4ade80; border-color: #4ade80; }
|
|
1186
|
+
|
|
1005
1187
|
/* ---- current-styles readout ---- */
|
|
1006
1188
|
.uiv-readout { display: flex; flex-direction: column; gap: 3px; }
|
|
1007
1189
|
.uiv-rrow { display: grid; grid-template-columns: 70px 1fr; gap: 8px; align-items: center;
|
|
@@ -1009,6 +1191,13 @@ var CSS = (
|
|
|
1009
1191
|
.uiv-rk { color: #71717a; }
|
|
1010
1192
|
.uiv-rv { color: #fff; word-break: break-all; display: flex; align-items: center; gap: 6px; }
|
|
1011
1193
|
.uiv-rv.changed { color: #4ade80; } /* edited in uivisor \u2192 green */
|
|
1194
|
+
.uiv-rv.auto { color: #6b7280; } /* browser-computed / default \u2192 grey */
|
|
1195
|
+
.uiv-leg { display: flex; gap: 10px; padding: 1px 0 6px; font-size: 9px;
|
|
1196
|
+
text-transform: uppercase; letter-spacing: .4px; }
|
|
1197
|
+
.uiv-lg { color: #e4e4e7; display: flex; align-items: center; gap: 4px; } /* file = white */
|
|
1198
|
+
.uiv-lg::before { content: ''; width: 7px; height: 7px; border-radius: 2px; background: currentColor; }
|
|
1199
|
+
.uiv-lg.edit { color: #4ade80; }
|
|
1200
|
+
.uiv-lg.auto { color: #6b7280; }
|
|
1012
1201
|
.uiv-sw { display: inline-block; width: 11px; height: 11px; border-radius: 3px;
|
|
1013
1202
|
border: 1px solid rgba(255,255,255,0.2); flex: 0 0 auto; }
|
|
1014
1203
|
|
|
@@ -1121,11 +1310,17 @@ var Uivisor = class {
|
|
|
1121
1310
|
/** Undo / redo stacks of full edit-state snapshots. */
|
|
1122
1311
|
this.undoStack = [];
|
|
1123
1312
|
this.redoStack = [];
|
|
1124
|
-
/** Cached live computed-style for the selected element (invalidated
|
|
1313
|
+
/** Cached live computed-style for the selected element (invalidated each render). */
|
|
1125
1314
|
this._cs = null;
|
|
1126
1315
|
this._csEl = null;
|
|
1316
|
+
/** Per-render memo of authored longhands per element (for the styles readout). */
|
|
1317
|
+
this._matched = null;
|
|
1127
1318
|
/** Cached project breakpoint system (detected from CSS), refreshed until found. */
|
|
1128
1319
|
this._bp = null;
|
|
1320
|
+
/** Cached project design system (detected from CSS variables), refreshed until found. */
|
|
1321
|
+
this._ds = null;
|
|
1322
|
+
/** Memoised Tailwind-utility probes: candidate class → resolved class or null. */
|
|
1323
|
+
this.utilCache = /* @__PURE__ */ new Map();
|
|
1129
1324
|
// responsive (virtual screen) mode
|
|
1130
1325
|
this.responsive = false;
|
|
1131
1326
|
this.frameWidth = 768;
|
|
@@ -1201,6 +1396,43 @@ var Uivisor = class {
|
|
|
1201
1396
|
if (!this._bp || this._bp.name !== "detected") this._bp = detectBreakpoints();
|
|
1202
1397
|
return this._bp;
|
|
1203
1398
|
}
|
|
1399
|
+
/** Project design tokens — re-detect until the CSS variables resolve. */
|
|
1400
|
+
designSystem() {
|
|
1401
|
+
if (!this._ds || this._ds.source === "none") this._ds = detectDesignSystem();
|
|
1402
|
+
return this._ds;
|
|
1403
|
+
}
|
|
1404
|
+
/** Which token category (if any) a CSS property picks tokens from. */
|
|
1405
|
+
dsCategoryFor(css) {
|
|
1406
|
+
if (css === "font-size") return "font-size";
|
|
1407
|
+
if (css === "color" || css === "background-color") return "color";
|
|
1408
|
+
return null;
|
|
1409
|
+
}
|
|
1410
|
+
/** Does a Tailwind utility for this token actually exist in the project CSS?
|
|
1411
|
+
* Probe a hidden element in the page document and compare the resolved value. */
|
|
1412
|
+
dsUtility(css, token) {
|
|
1413
|
+
const prefix = css === "background-color" ? "bg" : "text";
|
|
1414
|
+
const cls = `${prefix}-${token.name}`;
|
|
1415
|
+
if (this.utilCache.has(cls)) return this.utilCache.get(cls) ?? null;
|
|
1416
|
+
let res = null;
|
|
1417
|
+
try {
|
|
1418
|
+
const probe = document.createElement("span");
|
|
1419
|
+
probe.className = cls;
|
|
1420
|
+
probe.style.cssText = "position:absolute;left:-99999px;top:0;visibility:hidden";
|
|
1421
|
+
document.body.appendChild(probe);
|
|
1422
|
+
const got = getComputedStyle(probe).getPropertyValue(css).trim();
|
|
1423
|
+
probe.remove();
|
|
1424
|
+
if (token.category === "color") {
|
|
1425
|
+
const a = (rgbToHex(got) || got).toLowerCase();
|
|
1426
|
+
const b = (rgbToHex(token.value) || token.value).toLowerCase();
|
|
1427
|
+
if (a && a === b) res = cls;
|
|
1428
|
+
} else if (token.px != null && Math.abs(parseFloat(got) - token.px) < 0.5) {
|
|
1429
|
+
res = cls;
|
|
1430
|
+
}
|
|
1431
|
+
} catch {
|
|
1432
|
+
}
|
|
1433
|
+
this.utilCache.set(cls, res);
|
|
1434
|
+
return res;
|
|
1435
|
+
}
|
|
1204
1436
|
mount() {
|
|
1205
1437
|
this.host = document.createElement("div");
|
|
1206
1438
|
this.host.id = "uivisor-root";
|
|
@@ -1309,7 +1541,10 @@ var Uivisor = class {
|
|
|
1309
1541
|
const prev = this._bp;
|
|
1310
1542
|
this._bp = null;
|
|
1311
1543
|
const next = this.bpSystem();
|
|
1312
|
-
|
|
1544
|
+
const prevDsN = this._ds?.tokens.length ?? -1;
|
|
1545
|
+
this._ds = null;
|
|
1546
|
+
const nextDs = this.designSystem();
|
|
1547
|
+
if (!prev || key(prev) !== key(next) || prevDsN !== nextDs.tokens.length) this.renderBody();
|
|
1313
1548
|
};
|
|
1314
1549
|
for (const d of [250, 900, 2200]) window.setTimeout(refresh, d);
|
|
1315
1550
|
}
|
|
@@ -1471,7 +1706,9 @@ var Uivisor = class {
|
|
|
1471
1706
|
const el = this.selected;
|
|
1472
1707
|
const st = this.st();
|
|
1473
1708
|
if (!el || !st) return "";
|
|
1474
|
-
|
|
1709
|
+
const inline = el.style.getPropertyValue(css);
|
|
1710
|
+
if (inline && !inline.includes("var(")) return inline;
|
|
1711
|
+
return this.computedVal(css) || st.original[css] || "";
|
|
1475
1712
|
}
|
|
1476
1713
|
liveNum(css) {
|
|
1477
1714
|
const v = this.liveVal(css).trim();
|
|
@@ -1545,7 +1782,7 @@ var Uivisor = class {
|
|
|
1545
1782
|
for (const css of props) {
|
|
1546
1783
|
for (const e of sibs) removeOverride(e, css);
|
|
1547
1784
|
const c = st.record.changes.find((ch) => ch.property === css);
|
|
1548
|
-
if (c) for (const e of targets) applyOverride(e, css, c.after.computed);
|
|
1785
|
+
if (c) for (const e of targets) applyOverride(e, css, c.live ?? c.after.computed);
|
|
1549
1786
|
}
|
|
1550
1787
|
this.reposition();
|
|
1551
1788
|
}
|
|
@@ -1570,6 +1807,24 @@ var Uivisor = class {
|
|
|
1570
1807
|
}
|
|
1571
1808
|
this.renderBody();
|
|
1572
1809
|
}
|
|
1810
|
+
/** Apply a design-system token to a property. The LIVE override is `var(--token)`
|
|
1811
|
+
* so a responsive token keeps adapting as you move across breakpoints; the
|
|
1812
|
+
* recorded value shows the token's value, tagged so the prompt asks for the token. */
|
|
1813
|
+
applyToken(css, token) {
|
|
1814
|
+
this.pushHistory();
|
|
1815
|
+
const live = `var(${token.cssVar})`;
|
|
1816
|
+
this.liveSet([css], live);
|
|
1817
|
+
const st = this.st();
|
|
1818
|
+
if (!st) return;
|
|
1819
|
+
const scope = this.activeScope();
|
|
1820
|
+
st.applied.add(css);
|
|
1821
|
+
const change = buildChange(css, st.original[css], token.value, scope);
|
|
1822
|
+
change.live = live;
|
|
1823
|
+
change.after.designToken = token.cssVar;
|
|
1824
|
+
change.after.token = st.record.styling.primaryMechanism === "tailwind" ? this.dsUtility(css, token) : null;
|
|
1825
|
+
this.setChange(st.record, change);
|
|
1826
|
+
this.renderBody();
|
|
1827
|
+
}
|
|
1573
1828
|
revertProps(cssList) {
|
|
1574
1829
|
const el = this.selected;
|
|
1575
1830
|
const st = this.st();
|
|
@@ -1631,6 +1886,9 @@ var Uivisor = class {
|
|
|
1631
1886
|
}
|
|
1632
1887
|
// ---- rendering ----
|
|
1633
1888
|
renderBody() {
|
|
1889
|
+
this._cs = null;
|
|
1890
|
+
this._csEl = null;
|
|
1891
|
+
this._matched = null;
|
|
1634
1892
|
const body = this.q(".uiv-body");
|
|
1635
1893
|
if (!this.selected) {
|
|
1636
1894
|
body.innerHTML = `
|
|
@@ -1651,6 +1909,7 @@ var Uivisor = class {
|
|
|
1651
1909
|
<div class="uiv-src">${escapeHtml(src)}</div>
|
|
1652
1910
|
<span class="uiv-mech">${st.record.styling.primaryMechanism}</span>
|
|
1653
1911
|
</div>
|
|
1912
|
+
${this.dsIndicatorHtml()}
|
|
1654
1913
|
${this.currentStylesHtml()}
|
|
1655
1914
|
${this.breakpointBarHtml()}
|
|
1656
1915
|
${this.targetHtml(st)}
|
|
@@ -1659,7 +1918,79 @@ var Uivisor = class {
|
|
|
1659
1918
|
`;
|
|
1660
1919
|
this.bindControls();
|
|
1661
1920
|
}
|
|
1662
|
-
/**
|
|
1921
|
+
/** Small indicator: how many design tokens were detected (or a hint if none). */
|
|
1922
|
+
dsIndicatorHtml() {
|
|
1923
|
+
const ds = this.designSystem();
|
|
1924
|
+
if (ds.source === "none") return "";
|
|
1925
|
+
const cats = Object.keys(ds.byCategory).map((c) => `${ds.byCategory[c].length} ${c}`).join(" \xB7 ");
|
|
1926
|
+
return `<div class="uiv-dsbar" title="${escapeAttr(cats)}">\u25C6 Design system \xB7 ${ds.tokens.length} tokens detected</div>`;
|
|
1927
|
+
}
|
|
1928
|
+
/** Longhand properties an authoring rule (or non-uivisor inline) sets on `el`.
|
|
1929
|
+
* Reimplements getMatchedCSSRules over same-origin sheets (incl. matching
|
|
1930
|
+
* @media), so we can tell "set in the project's CSS" from "browser default". */
|
|
1931
|
+
matchedProps(el) {
|
|
1932
|
+
const cache = this._matched ||= /* @__PURE__ */ new Map();
|
|
1933
|
+
const cached = cache.get(el);
|
|
1934
|
+
if (cached) return cached;
|
|
1935
|
+
const out = /* @__PURE__ */ new Set();
|
|
1936
|
+
const he = el;
|
|
1937
|
+
const applied = el === this.selected ? this.st()?.applied ?? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
|
|
1938
|
+
if (he.style) for (let i = 0; i < he.style.length; i++) {
|
|
1939
|
+
const p = he.style[i];
|
|
1940
|
+
if (!applied.has(p)) out.add(p);
|
|
1941
|
+
}
|
|
1942
|
+
const win = el.ownerDocument.defaultView || window;
|
|
1943
|
+
const walk = (rules) => {
|
|
1944
|
+
for (let i = 0; i < rules.length; i++) {
|
|
1945
|
+
const r = rules[i];
|
|
1946
|
+
if (r.selectorText && r.style) {
|
|
1947
|
+
let m = false;
|
|
1948
|
+
try {
|
|
1949
|
+
m = el.matches(r.selectorText);
|
|
1950
|
+
} catch {
|
|
1951
|
+
m = false;
|
|
1952
|
+
}
|
|
1953
|
+
if (m) for (let j = 0; j < r.style.length; j++) out.add(r.style[j]);
|
|
1954
|
+
} else if (r.media && r.cssRules) {
|
|
1955
|
+
let ok = true;
|
|
1956
|
+
try {
|
|
1957
|
+
ok = win.matchMedia(r.media.mediaText).matches;
|
|
1958
|
+
} catch {
|
|
1959
|
+
ok = true;
|
|
1960
|
+
}
|
|
1961
|
+
if (ok) walk(r.cssRules);
|
|
1962
|
+
} else if (r.cssRules) {
|
|
1963
|
+
walk(r.cssRules);
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1967
|
+
const sheets = el.ownerDocument.styleSheets;
|
|
1968
|
+
for (let i = 0; i < sheets.length; i++) {
|
|
1969
|
+
try {
|
|
1970
|
+
walk(sheets[i].cssRules);
|
|
1971
|
+
} catch {
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
cache.set(el, out);
|
|
1975
|
+
return out;
|
|
1976
|
+
}
|
|
1977
|
+
/** Is any of `props` authored in the project CSS? For inherited properties we
|
|
1978
|
+
* also walk ancestors (a body/parent font rule still counts as "from the file"). */
|
|
1979
|
+
isAuthored(props, inherit) {
|
|
1980
|
+
let node = this.selected;
|
|
1981
|
+
while (node) {
|
|
1982
|
+
const set = this.matchedProps(node);
|
|
1983
|
+
if (props.some((p) => set.has(p))) return true;
|
|
1984
|
+
node = inherit ? node.parentElement : null;
|
|
1985
|
+
}
|
|
1986
|
+
return false;
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Read-only readout of the element's ACTUAL current styles, three-state coloured:
|
|
1990
|
+
* white = authored in the project CSS · green = edited in uivisor ·
|
|
1991
|
+
* grey = browser-computed/auto (e.g. a width a flex item derived, a default).
|
|
1992
|
+
* Comprehensive + context-aware (flex/grid/position rows only when relevant).
|
|
1993
|
+
*/
|
|
1663
1994
|
currentStylesHtml() {
|
|
1664
1995
|
const el = this.selected;
|
|
1665
1996
|
if (!el) return "";
|
|
@@ -1675,47 +2006,75 @@ var Uivisor = class {
|
|
|
1675
2006
|
const h = hex(v);
|
|
1676
2007
|
return /^#|rgb/.test(h) ? `<span class="uiv-sw" style="background:${h}"></span>${h}` : h;
|
|
1677
2008
|
};
|
|
1678
|
-
const
|
|
1679
|
-
const t = g
|
|
1680
|
-
const r = g(`${prefix}-right`);
|
|
1681
|
-
const b = g(`${prefix}-bottom`);
|
|
1682
|
-
const l = g(`${prefix}-left`);
|
|
2009
|
+
const sides = (parts) => {
|
|
2010
|
+
const [t, r, b, l] = parts.map(g);
|
|
1683
2011
|
if (t === r && r === b && b === l) return t;
|
|
1684
2012
|
if (t === b && r === l) return `${t} ${r}`;
|
|
1685
2013
|
return `${t} ${r} ${b} ${l}`;
|
|
1686
2014
|
};
|
|
2015
|
+
const px4 = (pre, suf = "") => [`${pre}-top${suf}`, `${pre}-right${suf}`, `${pre}-bottom${suf}`, `${pre}-left${suf}`];
|
|
2016
|
+
const clip = (s, n = 30) => s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
|
|
1687
2017
|
const changedSet = new Set(this.st()?.record.changes.map((c) => c.property) ?? []);
|
|
1688
|
-
const
|
|
1689
|
-
|
|
2018
|
+
const stateCls = (props, inherit = false) => {
|
|
2019
|
+
if (props.some((p) => changedSet.has(p))) return " changed";
|
|
2020
|
+
return this.isAuthored(props, inherit) ? "" : " auto";
|
|
2021
|
+
};
|
|
1690
2022
|
const rows = [];
|
|
1691
|
-
const add = (k, v, props =
|
|
1692
|
-
if (v) rows.push({ k, v,
|
|
2023
|
+
const add = (k, v, props, inherit = false) => {
|
|
2024
|
+
if (v !== "" && v != null) rows.push({ k, v, cls: stateCls(props, inherit) });
|
|
1693
2025
|
};
|
|
1694
|
-
|
|
1695
|
-
add("
|
|
1696
|
-
const
|
|
1697
|
-
if (
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
2026
|
+
const disp = g("display");
|
|
2027
|
+
add("display", disp, ["display"]);
|
|
2028
|
+
const pos = g("position");
|
|
2029
|
+
if (pos && pos !== "static") {
|
|
2030
|
+
add("position", pos, ["position"]);
|
|
2031
|
+
const inset = ["top", "right", "bottom", "left"].filter((s) => g(s) !== "auto").map((s) => `${s[0]} ${g(s)}`).join(" ");
|
|
2032
|
+
if (inset) add("inset", inset, ["top", "right", "bottom", "left"]);
|
|
2033
|
+
}
|
|
2034
|
+
add("width", `${Math.round(parseFloat(g("width")) || 0)}px`, ["width"]);
|
|
2035
|
+
add("height", `${Math.round(parseFloat(g("height")) || 0)}px`, ["height"]);
|
|
2036
|
+
const maxw = g("max-width");
|
|
2037
|
+
if (maxw && maxw !== "none") add("max-w", maxw, ["max-width"]);
|
|
2038
|
+
const minh = g("min-height");
|
|
2039
|
+
if (minh && minh !== "0px" && minh !== "auto") add("min-h", minh, ["min-height"]);
|
|
2040
|
+
if (/flex|grid/.test(disp)) {
|
|
2041
|
+
if (disp.includes("flex")) add("direction", g("flex-direction"), ["flex-direction"]);
|
|
2042
|
+
add("justify", g("justify-content"), ["justify-content"]);
|
|
2043
|
+
add("align", g("align-items"), ["align-items"]);
|
|
2044
|
+
if (disp.includes("flex")) {
|
|
2045
|
+
const w = g("flex-wrap");
|
|
2046
|
+
if (w && w !== "nowrap") add("wrap", w, ["flex-wrap"]);
|
|
2047
|
+
}
|
|
2048
|
+
if (disp.includes("grid")) {
|
|
2049
|
+
const c = g("grid-template-columns");
|
|
2050
|
+
if (c && c !== "none") add("grid-cols", clip(c), ["grid-template-columns"]);
|
|
2051
|
+
}
|
|
1701
2052
|
const gap = g("gap");
|
|
1702
|
-
if (gap && gap !== "normal"
|
|
2053
|
+
if (gap && gap !== "normal") add("gap", gap, ["gap", "row-gap", "column-gap"]);
|
|
1703
2054
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
2055
|
+
let parentDisp = "";
|
|
2056
|
+
try {
|
|
2057
|
+
if (el.parentElement) parentDisp = getComputedStyle(el.parentElement).display;
|
|
2058
|
+
} catch {
|
|
2059
|
+
}
|
|
2060
|
+
if (/flex|grid/.test(parentDisp)) {
|
|
2061
|
+
add("flex", `${g("flex-grow")} ${g("flex-shrink")} ${g("flex-basis")}`, ["flex-grow", "flex-shrink", "flex-basis"]);
|
|
2062
|
+
const as = g("align-self");
|
|
2063
|
+
if (as && as !== "auto" && as !== "normal") add("self", as, ["align-self"]);
|
|
2064
|
+
}
|
|
2065
|
+
const pad = sides(px4("padding"));
|
|
2066
|
+
if (pad && pad !== "0px") add("padding", pad, px4("padding"));
|
|
2067
|
+
const mar = sides(px4("margin"));
|
|
2068
|
+
if (mar && mar !== "0px") add("margin", mar, px4("margin"));
|
|
1715
2069
|
const bw = g("border-top-width");
|
|
1716
2070
|
if (bw && parseFloat(bw) > 0)
|
|
1717
|
-
add("border", `${bw} ${g("border-top-style")} ${
|
|
1718
|
-
const br =
|
|
2071
|
+
add("border", `${bw} ${g("border-top-style")} ${swatch(g("border-top-color"))}`, px4("border", "-width"));
|
|
2072
|
+
const br = sides([
|
|
2073
|
+
"border-top-left-radius",
|
|
2074
|
+
"border-top-right-radius",
|
|
2075
|
+
"border-bottom-right-radius",
|
|
2076
|
+
"border-bottom-left-radius"
|
|
2077
|
+
]);
|
|
1719
2078
|
if (br && br !== "0px")
|
|
1720
2079
|
add("radius", br, [
|
|
1721
2080
|
"border-radius",
|
|
@@ -1724,11 +2083,35 @@ var Uivisor = class {
|
|
|
1724
2083
|
"border-bottom-right-radius",
|
|
1725
2084
|
"border-bottom-left-radius"
|
|
1726
2085
|
]);
|
|
1727
|
-
if (
|
|
2086
|
+
if (this.context(el).hasText) {
|
|
2087
|
+
add("font-size", g("font-size"), ["font-size"], true);
|
|
2088
|
+
add("weight", g("font-weight"), ["font-weight"], true);
|
|
2089
|
+
add("line", g("line-height"), ["line-height"], true);
|
|
2090
|
+
const ls = g("letter-spacing");
|
|
2091
|
+
if (ls && ls !== "normal") add("tracking", ls, ["letter-spacing"], true);
|
|
2092
|
+
add("color", swatch(g("color")), ["color"], true);
|
|
2093
|
+
const ta = g("text-align");
|
|
2094
|
+
if (ta && ta !== "start" && ta !== "left") add("text-align", ta, ["text-align"], true);
|
|
2095
|
+
}
|
|
2096
|
+
const bg = g("background-color");
|
|
2097
|
+
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") add("background", swatch(bg), ["background-color"]);
|
|
2098
|
+
const bgi = g("background-image");
|
|
2099
|
+
if (bgi && bgi !== "none") add("bg-image", clip(bgi, 26), ["background-image"]);
|
|
2100
|
+
const sh = g("box-shadow");
|
|
2101
|
+
if (sh && sh !== "none") add("shadow", clip(sh, 26), ["box-shadow"]);
|
|
1728
2102
|
const op = g("opacity");
|
|
1729
|
-
if (op && parseFloat(op) < 1) add("opacity", op);
|
|
2103
|
+
if (op && parseFloat(op) < 1) add("opacity", op, ["opacity"]);
|
|
2104
|
+
const ov = g("overflow");
|
|
2105
|
+
if (ov && ov !== "visible") add("overflow", ov, ["overflow", "overflow-x", "overflow-y"]);
|
|
2106
|
+
const z = g("z-index");
|
|
2107
|
+
if (z && z !== "auto") add("z-index", z, ["z-index"]);
|
|
2108
|
+
const tr = g("transform");
|
|
2109
|
+
if (tr && tr !== "none") add("transform", clip(tr, 22), ["transform"]);
|
|
1730
2110
|
const collapsed = this.collapsedSecs.has("Current styles");
|
|
1731
|
-
const
|
|
2111
|
+
const legend = `<div class="uiv-leg"><span class="uiv-lg">file</span><span class="uiv-lg edit">edited</span><span class="uiv-lg auto">auto</span></div>`;
|
|
2112
|
+
const items = collapsed ? "" : legend + rows.map(
|
|
2113
|
+
(r) => `<div class="uiv-rrow"><span class="uiv-rk">${r.k}</span><span class="uiv-rv${r.cls}">${r.v}</span></div>`
|
|
2114
|
+
).join("");
|
|
1732
2115
|
return `<div class="uiv-sec">${this.accordionTitle("Current styles")}<div class="uiv-readout">${items}</div></div>`;
|
|
1733
2116
|
}
|
|
1734
2117
|
/** Breakpoint scope switcher: shows the PROJECT's breakpoints + the live window one. */
|
|
@@ -1864,6 +2247,32 @@ var Uivisor = class {
|
|
|
1864
2247
|
const units = c.units.map((u) => `<option value="${u}"${u === d.unit ? " selected" : ""}>${UNIT_LABELS[u] ?? u}</option>`).join("");
|
|
1865
2248
|
return `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield"><div class="uiv-num uiv-dim${changed ? " changed" : ""}" data-css="${c.css}"><span class="uiv-scrub" title="Drag to change">${c.icon}</span><input type="number" step="any" value="${escapeAttr(d.num)}" placeholder="${escapeAttr(d.placeholder)}"><select class="uiv-unit" title="Unit">${units}</select></div></div><span></span></div>`;
|
|
1866
2249
|
}
|
|
2250
|
+
/** A design-token picker row for a property, shown only when the project exposes
|
|
2251
|
+
* tokens for that category. Picking a token applies its value + tags the prompt. */
|
|
2252
|
+
tokenRowHtml(css, label) {
|
|
2253
|
+
const cat = this.dsCategoryFor(css);
|
|
2254
|
+
if (!cat) return "";
|
|
2255
|
+
const ds = this.designSystem();
|
|
2256
|
+
const list = ds.byCategory[cat];
|
|
2257
|
+
if (!list || !list.length) return "";
|
|
2258
|
+
const target = cat === "font-size" ? { px: this.currentPx(css) ?? void 0 } : { value: this.computedVal(css) };
|
|
2259
|
+
const near = nearestToken(ds, cat, target);
|
|
2260
|
+
const edited = this.st()?.record.changes.some(
|
|
2261
|
+
(c) => c.property === css && c.after.designToken
|
|
2262
|
+
);
|
|
2263
|
+
if (cat === "color") {
|
|
2264
|
+
const swatches = list.map((t) => {
|
|
2265
|
+
const on = near?.exact && near.token.cssVar === t.cssVar;
|
|
2266
|
+
return `<button class="uiv-swatch${on ? " on" : ""}" data-css="${css}" data-var="${escapeAttr(t.cssVar)}" title="${escapeAttr(`${t.name} \xB7 ${t.value}`)}" style="background:${escapeAttr(t.value)}"></button>`;
|
|
2267
|
+
}).join("");
|
|
2268
|
+
return `<div class="uiv-ctl"><span class="clabel uiv-tlabel">${label}</span><div class="cfield uiv-swatches">${swatches}</div><span></span></div>`;
|
|
2269
|
+
}
|
|
2270
|
+
const head = `<option value="">${near && !near.exact ? `\u2248 ${escapeHtml(near.token.name)} \xB7 pick token` : "\u2014 pick token \u2014"}</option>`;
|
|
2271
|
+
const opts = list.map(
|
|
2272
|
+
(t) => `<option value="${escapeAttr(t.cssVar)}"${near?.exact && near.token.cssVar === t.cssVar ? " selected" : ""}>${escapeHtml(`${t.name} \xB7 ${t.value}`)}</option>`
|
|
2273
|
+
).join("");
|
|
2274
|
+
return `<div class="uiv-ctl"><span class="clabel uiv-tlabel">${label}</span><div class="cfield"><select class="uiv-sel uiv-tokensel${edited ? " changed" : ""}" data-css="${css}">${head}${opts}</select></div><span></span></div>`;
|
|
2275
|
+
}
|
|
1867
2276
|
controlRow(c) {
|
|
1868
2277
|
if (c.kind === "box") {
|
|
1869
2278
|
const cssList = c.sides.map((s) => s.css);
|
|
@@ -1888,7 +2297,7 @@ var Uivisor = class {
|
|
|
1888
2297
|
}
|
|
1889
2298
|
if (c.kind === "len") {
|
|
1890
2299
|
const v = this.liveNum(c.css);
|
|
1891
|
-
return `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield">${this.numField(c.css, v == null ? "" : String(round2(v)), c.icon, this.isChanged([c.css]), false, "\u2014")}</div><span></span></div
|
|
2300
|
+
return `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield">${this.numField(c.css, v == null ? "" : String(round2(v)), c.icon, this.isChanged([c.css]), false, "\u2014")}</div><span></span></div>` + this.tokenRowHtml(c.css, "Token");
|
|
1892
2301
|
}
|
|
1893
2302
|
if (c.kind === "dim") {
|
|
1894
2303
|
return this.dimField(c);
|
|
@@ -1900,7 +2309,7 @@ var Uivisor = class {
|
|
|
1900
2309
|
return `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield"><select class="uiv-sel${this.isChanged([c.css]) ? " changed" : ""}" data-css="${c.css}">${opts}</select></div><span></span></div>`;
|
|
1901
2310
|
}
|
|
1902
2311
|
const val = toHexInput(this.liveVal(c.css));
|
|
1903
|
-
return `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield"><input type="color" class="uiv-color${this.isChanged([c.css]) ? " changed" : ""}" data-css="${c.css}" value="${val}"></div><span></span></div
|
|
2312
|
+
return `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield"><input type="color" class="uiv-color${this.isChanged([c.css]) ? " changed" : ""}" data-css="${c.css}" value="${val}"></div><span></span></div>` + this.tokenRowHtml(c.css, "Token");
|
|
1904
2313
|
}
|
|
1905
2314
|
bindControls() {
|
|
1906
2315
|
const root = this.root;
|
|
@@ -1942,7 +2351,7 @@ var Uivisor = class {
|
|
|
1942
2351
|
this.commitValue([css], input.value);
|
|
1943
2352
|
});
|
|
1944
2353
|
});
|
|
1945
|
-
root.querySelectorAll(".uiv-sel").forEach((node) => {
|
|
2354
|
+
root.querySelectorAll(".uiv-sel:not(.uiv-tokensel)").forEach((node) => {
|
|
1946
2355
|
const sel = node;
|
|
1947
2356
|
const css = sel.getAttribute("data-css");
|
|
1948
2357
|
sel.addEventListener("change", () => {
|
|
@@ -1950,6 +2359,24 @@ var Uivisor = class {
|
|
|
1950
2359
|
this.commitValue([css], sel.value);
|
|
1951
2360
|
});
|
|
1952
2361
|
});
|
|
2362
|
+
root.querySelectorAll(".uiv-tokensel").forEach((node) => {
|
|
2363
|
+
const sel = node;
|
|
2364
|
+
const css = sel.getAttribute("data-css");
|
|
2365
|
+
sel.addEventListener("change", () => {
|
|
2366
|
+
if (!sel.value) return;
|
|
2367
|
+
const token = this.designSystem().tokens.find((t) => t.cssVar === sel.value);
|
|
2368
|
+
if (token) this.applyToken(css, token);
|
|
2369
|
+
});
|
|
2370
|
+
});
|
|
2371
|
+
root.querySelectorAll(".uiv-swatch").forEach((node) => {
|
|
2372
|
+
const btn = node;
|
|
2373
|
+
const css = btn.getAttribute("data-css");
|
|
2374
|
+
const cssVar = btn.getAttribute("data-var");
|
|
2375
|
+
btn.addEventListener("click", () => {
|
|
2376
|
+
const token = this.designSystem().tokens.find((t) => t.cssVar === cssVar);
|
|
2377
|
+
if (token) this.applyToken(css, token);
|
|
2378
|
+
});
|
|
2379
|
+
});
|
|
1953
2380
|
root.querySelectorAll(".uiv-expand").forEach((node) => {
|
|
1954
2381
|
const btn = node;
|
|
1955
2382
|
const key = btn.getAttribute("data-key");
|
|
@@ -2096,7 +2523,8 @@ var Uivisor = class {
|
|
|
2096
2523
|
const loc = id.source.confidence !== "none" ? `${id.source.file}:${id.source.line}` : id.componentName || "";
|
|
2097
2524
|
const chgs = collapseChanges(r.changes).map((c) => {
|
|
2098
2525
|
const bp = c.breakpoint === "base" ? "" : `<span class="bp">${c.breakpoint}:</span> `;
|
|
2099
|
-
const
|
|
2526
|
+
const tokLabel = c.after.token || (c.after.designToken ? `var(${c.after.designToken})` : "");
|
|
2527
|
+
const tok = tokLabel ? ` <span class="tok">${escapeHtml(tokLabel)}</span>` : "";
|
|
2100
2528
|
return `<div class="uiv-jchg">${bp}${c.property}: ${c.before.computed} \u2192 ${c.after.computed}${tok}</div>`;
|
|
2101
2529
|
}).join("");
|
|
2102
2530
|
return `<div class="uiv-jitem"><div class="jhead"><span class="jel"><${id.tagName}></span><span class="jloc">${escapeHtml(loc)}</span></div>${chgs}</div>`;
|
|
@@ -2181,7 +2609,7 @@ var Uivisor = class {
|
|
|
2181
2609
|
this.states.set(ent.el, st);
|
|
2182
2610
|
const targets = st.record.target === "all" ? this.siblingsOf(ent.el) : [ent.el];
|
|
2183
2611
|
for (const c of st.record.changes) {
|
|
2184
|
-
for (const e of targets) applyOverride(e, c.property, c.after.computed);
|
|
2612
|
+
for (const e of targets) applyOverride(e, c.property, c.live ?? c.after.computed);
|
|
2185
2613
|
st.applied.add(c.property);
|
|
2186
2614
|
}
|
|
2187
2615
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uivisor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dev-only visual UI tweaker that turns mouse edits into a precise, breakpoint-aware prompt for your AI coding agent — without touching your source.",
|
|
6
6
|
"license": "MIT",
|