uivisor 0.1.6 → 0.1.7
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 +72 -36
- package/package.json +1 -1
package/dist/overlay/index.js
CHANGED
|
@@ -1191,8 +1191,12 @@ var CSS = (
|
|
|
1191
1191
|
.uiv-rk { color: #71717a; }
|
|
1192
1192
|
.uiv-rv { color: #fff; word-break: break-all; display: flex; align-items: center; gap: 6px; }
|
|
1193
1193
|
.uiv-rv.changed { color: #4ade80; } /* edited in uivisor \u2192 green */
|
|
1194
|
-
|
|
1195
|
-
|
|
1194
|
+
|
|
1195
|
+
/* control-row state: file (authored) \xB7 edited (this breakpoint) \xB7 auto (computed) */
|
|
1196
|
+
.uiv-ctl.st-file > .clabel { color: #e4e4e7; }
|
|
1197
|
+
.uiv-ctl.st-edited > .clabel { color: #4ade80; }
|
|
1198
|
+
.uiv-ctl.st-auto > .clabel { color: #6b7280; }
|
|
1199
|
+
.uiv-leg { display: flex; gap: 12px; padding: 8px 12px 2px; font-size: 9px;
|
|
1196
1200
|
text-transform: uppercase; letter-spacing: .4px; }
|
|
1197
1201
|
.uiv-lg { color: #e4e4e7; display: flex; align-items: center; gap: 4px; } /* file = white */
|
|
1198
1202
|
.uiv-lg::before { content: ''; width: 7px; height: 7px; border-radius: 2px; background: currentColor; }
|
|
@@ -1299,6 +1303,15 @@ var CSS = (
|
|
|
1299
1303
|
// src/overlay/index.ts
|
|
1300
1304
|
var counter = 0;
|
|
1301
1305
|
var round2 = (n) => Math.round(n * 100) / 100;
|
|
1306
|
+
var INHERITED_PROPS = /* @__PURE__ */ new Set([
|
|
1307
|
+
"font-size",
|
|
1308
|
+
"font-weight",
|
|
1309
|
+
"line-height",
|
|
1310
|
+
"letter-spacing",
|
|
1311
|
+
"color",
|
|
1312
|
+
"text-align",
|
|
1313
|
+
"font-family"
|
|
1314
|
+
]);
|
|
1302
1315
|
var Uivisor = class {
|
|
1303
1316
|
constructor() {
|
|
1304
1317
|
this.enabled = false;
|
|
@@ -1379,7 +1392,10 @@ var Uivisor = class {
|
|
|
1379
1392
|
const winBp = currentBreakpoint(this.bpSystem()).name;
|
|
1380
1393
|
if (winBp !== this.lastWinBp) {
|
|
1381
1394
|
this.lastWinBp = winBp;
|
|
1382
|
-
if (this.enabled && this.selected)
|
|
1395
|
+
if (this.enabled && this.selected) {
|
|
1396
|
+
this.reapplyScope();
|
|
1397
|
+
this.renderBody();
|
|
1398
|
+
}
|
|
1383
1399
|
}
|
|
1384
1400
|
};
|
|
1385
1401
|
this.reposition = () => {
|
|
@@ -1645,6 +1661,7 @@ var Uivisor = class {
|
|
|
1645
1661
|
const up = () => {
|
|
1646
1662
|
handle.removeEventListener("pointermove", move);
|
|
1647
1663
|
handle.removeEventListener("pointerup", up);
|
|
1664
|
+
this.reapplyScope();
|
|
1648
1665
|
this.renderBody();
|
|
1649
1666
|
};
|
|
1650
1667
|
handle.addEventListener("pointermove", move);
|
|
@@ -1680,6 +1697,7 @@ var Uivisor = class {
|
|
|
1680
1697
|
dimUnit: {}
|
|
1681
1698
|
});
|
|
1682
1699
|
}
|
|
1700
|
+
if (el) this.reapplyScope();
|
|
1683
1701
|
this.reposition();
|
|
1684
1702
|
this.renderBody();
|
|
1685
1703
|
}
|
|
@@ -1706,6 +1724,12 @@ var Uivisor = class {
|
|
|
1706
1724
|
const el = this.selected;
|
|
1707
1725
|
const st = this.st();
|
|
1708
1726
|
if (!el || !st) return "";
|
|
1727
|
+
const scope = this.activeScope();
|
|
1728
|
+
const ch = st.record.changes.find((c) => c.property === css && c.breakpoint === scope.name);
|
|
1729
|
+
if (ch) {
|
|
1730
|
+
const v = ch.live ?? ch.after.computed;
|
|
1731
|
+
return v.includes("var(") ? this.computedVal(css) || v : v;
|
|
1732
|
+
}
|
|
1709
1733
|
const inline = el.style.getPropertyValue(css);
|
|
1710
1734
|
if (inline && !inline.includes("var(")) return inline;
|
|
1711
1735
|
return this.computedVal(css) || st.original[css] || "";
|
|
@@ -1728,7 +1752,10 @@ var Uivisor = class {
|
|
|
1728
1752
|
isChanged(cssList) {
|
|
1729
1753
|
const st = this.st();
|
|
1730
1754
|
if (!st) return false;
|
|
1731
|
-
|
|
1755
|
+
const scope = this.activeScope();
|
|
1756
|
+
return cssList.some(
|
|
1757
|
+
(c) => st.record.changes.some((ch) => ch.property === c && ch.breakpoint === scope.name)
|
|
1758
|
+
);
|
|
1732
1759
|
}
|
|
1733
1760
|
selectCurrent(css) {
|
|
1734
1761
|
let v = this.liveVal(css).trim();
|
|
@@ -1773,16 +1800,27 @@ var Uivisor = class {
|
|
|
1773
1800
|
}
|
|
1774
1801
|
/** Re-apply recorded overrides after the target (all ↔ one) changes. */
|
|
1775
1802
|
reapplyForTarget() {
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1803
|
+
this.reapplyScope();
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Project the live preview for the ACTIVE breakpoint: strip every override we
|
|
1807
|
+
* applied, then re-apply ONLY the changes recorded for the current scope. This
|
|
1808
|
+
* is what makes per-breakpoint edits behave — set padding 20 at xl, 10 at md,
|
|
1809
|
+
* and each breakpoint shows (and previews) its own value instead of one global
|
|
1810
|
+
* inline override leaking across all of them.
|
|
1811
|
+
*/
|
|
1812
|
+
reapplyScope() {
|
|
1813
|
+
const scope = this.activeScope();
|
|
1814
|
+
for (const [el, st] of this.states) {
|
|
1815
|
+
const sibs = this.siblingsOf(el);
|
|
1816
|
+
const targets = st.record.target === "all" ? sibs : [el];
|
|
1817
|
+
for (const css of st.applied) for (const e of sibs) removeOverride(e, css);
|
|
1818
|
+
st.applied = /* @__PURE__ */ new Set();
|
|
1819
|
+
for (const c of st.record.changes) {
|
|
1820
|
+
if (c.breakpoint !== scope.name) continue;
|
|
1821
|
+
for (const e of targets) applyOverride(e, c.property, c.live ?? c.after.computed);
|
|
1822
|
+
st.applied.add(c.property);
|
|
1823
|
+
}
|
|
1786
1824
|
}
|
|
1787
1825
|
this.reposition();
|
|
1788
1826
|
}
|
|
@@ -1974,6 +2012,13 @@ var Uivisor = class {
|
|
|
1974
2012
|
cache.set(el, out);
|
|
1975
2013
|
return out;
|
|
1976
2014
|
}
|
|
2015
|
+
/** State class for an editable control's row: edited (green, at this breakpoint)
|
|
2016
|
+
* · file (white, authored in CSS) · auto (grey, browser-computed/default). */
|
|
2017
|
+
controlStateClass(props) {
|
|
2018
|
+
if (this.isChanged(props)) return " st-edited";
|
|
2019
|
+
const inherit = props.some((p) => INHERITED_PROPS.has(p));
|
|
2020
|
+
return this.isAuthored(props, inherit) ? " st-file" : " st-auto";
|
|
2021
|
+
}
|
|
1977
2022
|
/** Is any of `props` authored in the project CSS? For inherited properties we
|
|
1978
2023
|
* also walk ancestors (a body/parent font rule still counts as "from the file"). */
|
|
1979
2024
|
isAuthored(props, inherit) {
|
|
@@ -2014,14 +2059,9 @@ var Uivisor = class {
|
|
|
2014
2059
|
};
|
|
2015
2060
|
const px4 = (pre, suf = "") => [`${pre}-top${suf}`, `${pre}-right${suf}`, `${pre}-bottom${suf}`, `${pre}-left${suf}`];
|
|
2016
2061
|
const clip = (s, n = 30) => s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
|
|
2017
|
-
const changedSet = new Set(this.st()?.record.changes.map((c) => c.property) ?? []);
|
|
2018
|
-
const stateCls = (props, inherit = false) => {
|
|
2019
|
-
if (props.some((p) => changedSet.has(p))) return " changed";
|
|
2020
|
-
return this.isAuthored(props, inherit) ? "" : " auto";
|
|
2021
|
-
};
|
|
2022
2062
|
const rows = [];
|
|
2023
|
-
const add = (k, v,
|
|
2024
|
-
if (v !== "" && v != null) rows.push({ k, v
|
|
2063
|
+
const add = (k, v, _props = [], _inherit = false) => {
|
|
2064
|
+
if (v !== "" && v != null) rows.push({ k, v });
|
|
2025
2065
|
};
|
|
2026
2066
|
const disp = g("display");
|
|
2027
2067
|
add("display", disp, ["display"]);
|
|
@@ -2108,10 +2148,7 @@ var Uivisor = class {
|
|
|
2108
2148
|
const tr = g("transform");
|
|
2109
2149
|
if (tr && tr !== "none") add("transform", clip(tr, 22), ["transform"]);
|
|
2110
2150
|
const collapsed = this.collapsedSecs.has("Current styles");
|
|
2111
|
-
const
|
|
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("");
|
|
2151
|
+
const items = collapsed ? "" : rows.map((r) => `<div class="uiv-rrow"><span class="uiv-rk">${r.k}</span><span class="uiv-rv">${r.v}</span></div>`).join("");
|
|
2115
2152
|
return `<div class="uiv-sec">${this.accordionTitle("Current styles")}<div class="uiv-readout">${items}</div></div>`;
|
|
2116
2153
|
}
|
|
2117
2154
|
/** Breakpoint scope switcher: shows the PROJECT's breakpoints + the live window one. */
|
|
@@ -2165,12 +2202,14 @@ var Uivisor = class {
|
|
|
2165
2202
|
return true;
|
|
2166
2203
|
}
|
|
2167
2204
|
controlsHtml(ctx) {
|
|
2168
|
-
|
|
2205
|
+
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>`;
|
|
2206
|
+
const secs = SECTIONS.map((sec) => {
|
|
2169
2207
|
const controls = sec.controls.filter((c) => this.relevant(c, ctx));
|
|
2170
2208
|
if (!controls.length) return "";
|
|
2171
2209
|
const rows = this.collapsedSecs.has(sec.title) ? "" : controls.map((c) => this.controlRow(c)).join("");
|
|
2172
2210
|
return `<div class="uiv-sec">${this.accordionTitle(sec.title)}${rows}</div>`;
|
|
2173
2211
|
}).join("");
|
|
2212
|
+
return legend + secs;
|
|
2174
2213
|
}
|
|
2175
2214
|
/** A collapsible section header. Clicking it hides/shows the section's controls. */
|
|
2176
2215
|
accordionTitle(title) {
|
|
@@ -2245,7 +2284,7 @@ var Uivisor = class {
|
|
|
2245
2284
|
const d = this.dimDisplay(c);
|
|
2246
2285
|
const changed = this.isChanged([c.css]);
|
|
2247
2286
|
const units = c.units.map((u) => `<option value="${u}"${u === d.unit ? " selected" : ""}>${UNIT_LABELS[u] ?? u}</option>`).join("");
|
|
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>`;
|
|
2287
|
+
return `<div class="uiv-ctl${this.controlStateClass([c.css])}"><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>`;
|
|
2249
2288
|
}
|
|
2250
2289
|
/** A design-token picker row for a property, shown only when the project exposes
|
|
2251
2290
|
* tokens for that category. Picking a token applies its value + tags the prompt. */
|
|
@@ -2279,7 +2318,7 @@ var Uivisor = class {
|
|
|
2279
2318
|
const info = this.numInfo(cssList);
|
|
2280
2319
|
const changed = this.isChanged(cssList);
|
|
2281
2320
|
const open = this.expanded.has(c.key);
|
|
2282
|
-
let html = `<div class="uiv-ctl"><span class="clabel">${c.label}</span><div class="cfield">${this.numField(cssList.join(","), info.mixed ? "" : info.value, c.icon, changed, false, info.mixed ? "Mixed" : "\u2014")}</div><button class="uiv-expand${open ? " on" : ""}" data-key="${c.key}" title="Edit each side individually">${open ? ICONS.collapse : ICONS.expand}</button></div>`;
|
|
2321
|
+
let html = `<div class="uiv-ctl${this.controlStateClass(cssList)}"><span class="clabel">${c.label}</span><div class="cfield">${this.numField(cssList.join(","), info.mixed ? "" : info.value, c.icon, changed, false, info.mixed ? "Mixed" : "\u2014")}</div><button class="uiv-expand${open ? " on" : ""}" data-key="${c.key}" title="Edit each side individually">${open ? ICONS.collapse : ICONS.expand}</button></div>`;
|
|
2283
2322
|
if (open) {
|
|
2284
2323
|
html += `<div class="uiv-sides">` + c.sides.map((s) => {
|
|
2285
2324
|
const v = this.liveNum(s.css);
|
|
@@ -2297,7 +2336,7 @@ var Uivisor = class {
|
|
|
2297
2336
|
}
|
|
2298
2337
|
if (c.kind === "len") {
|
|
2299
2338
|
const v = this.liveNum(c.css);
|
|
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");
|
|
2339
|
+
return `<div class="uiv-ctl${this.controlStateClass([c.css])}"><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");
|
|
2301
2340
|
}
|
|
2302
2341
|
if (c.kind === "dim") {
|
|
2303
2342
|
return this.dimField(c);
|
|
@@ -2306,10 +2345,10 @@ var Uivisor = class {
|
|
|
2306
2345
|
const cur = this.selectCurrent(c.css);
|
|
2307
2346
|
const optList = cur && !c.options.includes(cur) ? [cur, ...c.options] : c.options;
|
|
2308
2347
|
const opts = optList.map((o) => `<option value="${o}"${o === cur ? " selected" : ""}>${o}</option>`).join("");
|
|
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>`;
|
|
2348
|
+
return `<div class="uiv-ctl${this.controlStateClass([c.css])}"><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>`;
|
|
2310
2349
|
}
|
|
2311
2350
|
const val = toHexInput(this.liveVal(c.css));
|
|
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");
|
|
2351
|
+
return `<div class="uiv-ctl${this.controlStateClass([c.css])}"><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");
|
|
2313
2352
|
}
|
|
2314
2353
|
bindControls() {
|
|
2315
2354
|
const root = this.root;
|
|
@@ -2410,6 +2449,7 @@ var Uivisor = class {
|
|
|
2410
2449
|
this.toggleResponsive(true);
|
|
2411
2450
|
} else {
|
|
2412
2451
|
this.setFrameWidth(w);
|
|
2452
|
+
this.reapplyScope();
|
|
2413
2453
|
this.renderBody();
|
|
2414
2454
|
}
|
|
2415
2455
|
});
|
|
@@ -2607,13 +2647,9 @@ var Uivisor = class {
|
|
|
2607
2647
|
for (const ent of snap.entries) {
|
|
2608
2648
|
const st = { record: clone(ent.record), original: { ...ent.original }, applied: /* @__PURE__ */ new Set(), dimUnit: { ...ent.dimUnit } };
|
|
2609
2649
|
this.states.set(ent.el, st);
|
|
2610
|
-
const targets = st.record.target === "all" ? this.siblingsOf(ent.el) : [ent.el];
|
|
2611
|
-
for (const c of st.record.changes) {
|
|
2612
|
-
for (const e of targets) applyOverride(e, c.property, c.live ?? c.after.computed);
|
|
2613
|
-
st.applied.add(c.property);
|
|
2614
|
-
}
|
|
2615
2650
|
}
|
|
2616
2651
|
this.selected = snap.selected && this.states.has(snap.selected) ? snap.selected : null;
|
|
2652
|
+
this.reapplyScope();
|
|
2617
2653
|
this.reposition();
|
|
2618
2654
|
this.renderBody();
|
|
2619
2655
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uivisor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
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",
|