@bridge-ds/core 0.18.0 → 0.20.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/LICENSE +17 -0
- package/bridge.config.schema.json +21 -0
- package/dist/audit/index.js +3 -3
- package/dist/audit/report.d.ts +17 -2
- package/dist/branch-actions.d.ts +7 -1
- package/dist/build-requests-github.d.ts +25 -0
- package/dist/build-requests.d.ts +403 -0
- package/dist/changelog-model.d.ts +102 -0
- package/dist/component-spec.d.ts +3 -1
- package/dist/config.d.ts +26 -0
- package/dist/css-color.d.ts +25 -0
- package/dist/docs-proposal.d.ts +1 -0
- package/dist/explorations.d.ts +1 -0
- package/dist/fidelity-references.d.ts +12 -0
- package/dist/fidelity.d.ts +12 -1
- package/dist/figma-fix-loop.d.ts +153 -0
- package/dist/figma-fix-run.d.ts +103 -0
- package/dist/figma-fixes.d.ts +169 -0
- package/dist/figma-push-github.d.ts +7 -2
- package/dist/figma-push.d.ts +15 -2
- package/dist/gap-case.d.ts +143 -0
- package/dist/github-client.d.ts +31 -0
- package/dist/id-map.d.ts +10 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +3996 -818
- package/dist/index.js.map +1 -1
- package/dist/layered-review.d.ts +2 -0
- package/dist/measure-location.d.ts +42 -0
- package/dist/measure-status.d.ts +127 -0
- package/dist/measure-workflow.d.ts +48 -0
- package/dist/measured-only.d.ts +30 -0
- package/dist/measured-spec.d.ts +349 -0
- package/dist/measured-tokens.d.ts +25 -0
- package/dist/motion-docs.d.ts +51 -0
- package/dist/node/audit.d.ts +11 -3
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1640 -24
- package/dist/node/index.js.map +1 -1
- package/dist/node/measure-script.d.ts +1 -0
- package/dist/node/measure.d.ts +212 -0
- package/dist/node/spec-css.d.ts +9 -1
- package/dist/node/tokens-script.d.ts +3 -0
- package/dist/pr-composer.d.ts +5 -0
- package/dist/previews.d.ts +4 -1
- package/dist/{prod-branch-DenQkr_e.js → prod-branch-CJZwMfVD.js} +223 -183
- package/dist/prod-branch-CJZwMfVD.js.map +1 -0
- package/dist/prod-branch.d.ts +1 -1
- package/dist/repo-model.d.ts +7 -1
- package/dist/{repo-source-CRfhLO87.js → repo-source-CshjjC7x.js} +1485 -629
- package/dist/repo-source-CshjjC7x.js.map +1 -0
- package/dist/repo-source-github.d.ts +8 -0
- package/dist/repo-source.d.ts +6 -0
- package/dist/{report-DVEmUr0p.js → report-CE-jHAuw.js} +17 -6
- package/dist/{report-DVEmUr0p.js.map → report-CE-jHAuw.js.map} +1 -1
- package/dist/requester.d.ts +14 -0
- package/dist/requests.d.ts +2 -0
- package/dist/review-gate.d.ts +189 -2
- package/dist/risk.d.ts +12 -0
- package/dist/share-branch.d.ts +1 -1
- package/dist/snapshot.d.ts +34 -0
- package/dist/suggestion-review.d.ts +45 -2
- package/dist/suggestions-github.d.ts +33 -1
- package/dist/suggestions.d.ts +6 -0
- package/dist/tier1-publish.d.ts +48 -0
- package/dist/token-proposal.d.ts +7 -0
- package/dist/try-in-product.d.ts +9 -0
- package/package.json +1 -1
- package/dist/prod-branch-DenQkr_e.js.map +0 -1
- package/dist/repo-source-CRfhLO87.js.map +0 -1
package/dist/node/index.js
CHANGED
|
@@ -2,10 +2,11 @@ import { execFile, execFileSync } from "node:child_process";
|
|
|
2
2
|
import { mkdtemp, rm, mkdir, writeFile, lstat, readFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join, resolve, relative, dirname, sep, posix } from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { bp as assertSafeBranch, c as collectHistory, p as packageDirCandidates, a as parseChangelog, m as mergeReleases, r as releasesFromTags, b as buildReport, di as prNumberFromSubject, dI as specHash, ef as validateComponentSpec, K as hashSpec, cp as iconComponentName, F as variantKeyOf, e9 as tokenCssVar, aG as COMPONENT_SPECS_VERSION, J as COLOR_FIELDS, dQ as suggestionAppliedComment, a2 as gitBlobSha, dg as planSuggestionApply, aq as normalizeRepoPath, dF as sharedTokenPrefix, ec as tokenVariablePath, ep as withSrgbColors, dL as storybookIframeUrl, c_ as parseBoxShadow } from "../repo-source-CshjjC7x.js";
|
|
6
|
+
import { aV, C, c6, cL, I, d1, H } from "../repo-source-CshjjC7x.js";
|
|
7
|
+
import { K as selectTokenFiles, ah as globToRegExp, N as loadConfig, L as LayeredTokenSet, V as CONFIG_FILE, a0 as layoutOptions, a1 as buildTokenSet, b9 as defaultContext, B as resolve$1, af as slugify, c2 as protectedBranchesOf, _ as baseBranchOf } from "../prod-branch-CJZwMfVD.js";
|
|
7
8
|
import { statSync, readFileSync, existsSync, writeFileSync, readdirSync } from "node:fs";
|
|
8
|
-
import { i as isAuditable, Q as planCssFixes, O as parseAllowlist, d as DesignSystemIndex, l as buildAuditReport, o as compareWithBaseline, b as AUDIT_IGNORE_DIRS } from "../report-
|
|
9
|
+
import { i as isAuditable, Q as planCssFixes, O as parseAllowlist, d as DesignSystemIndex, l as buildAuditReport, o as compareWithBaseline, b as AUDIT_IGNORE_DIRS } from "../report-CE-jHAuw.js";
|
|
9
10
|
import ts from "typescript";
|
|
10
11
|
function git(root, args, opts = {}) {
|
|
11
12
|
return new Promise((resolve2, reject) => {
|
|
@@ -295,16 +296,17 @@ function runAudit(target, opts = {}) {
|
|
|
295
296
|
);
|
|
296
297
|
return opts.baseline ? compareWithBaseline(report, opts.baseline) : report;
|
|
297
298
|
}
|
|
298
|
-
function fixCss(target, ds, write) {
|
|
299
|
-
const { root, files } = collectAuditFiles(target);
|
|
299
|
+
function fixCss(target, ds, write, opts = {}) {
|
|
300
|
+
const { root, files } = collectAuditFiles(target, opts.exclude ?? []);
|
|
300
301
|
const out = [];
|
|
301
302
|
for (const f of files) {
|
|
302
303
|
const lang = f.path.endsWith(".scss") || f.path.endsWith(".sass") ? "scss" : f.path.endsWith(".less") ? "less" : f.path.endsWith(".css") ? "css" : null;
|
|
303
304
|
if (!lang) continue;
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
if (
|
|
307
|
-
|
|
305
|
+
const allowlist = (opts.allowlist ?? []).filter((e) => toPosix(e.file) === f.path);
|
|
306
|
+
const plan = planCssFixes(f.text, lang, ds, { allowlist });
|
|
307
|
+
if (!plan.edits.length && !plan.kept.length) continue;
|
|
308
|
+
if (write && plan.edits.length) writeFileSync(join(root, f.path), plan.output);
|
|
309
|
+
out.push({ file: f.path, edits: plan.edits, kept: plan.kept });
|
|
308
310
|
}
|
|
309
311
|
return out;
|
|
310
312
|
}
|
|
@@ -429,11 +431,17 @@ function specificityOf(c) {
|
|
|
429
431
|
return sp;
|
|
430
432
|
}
|
|
431
433
|
const cmpSpec = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
|
|
434
|
+
const SPEC_VIEWPORT_WIDTH = 1200;
|
|
432
435
|
function mediaApplies(query) {
|
|
433
436
|
const q = query.replace(/\s+/g, " ").trim().toLowerCase();
|
|
434
437
|
if (q.startsWith("@supports")) return true;
|
|
435
438
|
const cond = q.replace(/^@media /, "");
|
|
436
|
-
return
|
|
439
|
+
return cond.split(" and ").every((c) => {
|
|
440
|
+
if (/^\((any-)?hover: ?hover\)$/.test(c) || c === "screen" || c === "all") return true;
|
|
441
|
+
const w = /^\((min|max)-width: ?([\d.]+)px\)$/.exec(c);
|
|
442
|
+
if (!w) return false;
|
|
443
|
+
return w[1] === "min" ? SPEC_VIEWPORT_WIDTH >= Number(w[2]) : SPEC_VIEWPORT_WIDTH <= Number(w[2]);
|
|
444
|
+
});
|
|
437
445
|
}
|
|
438
446
|
function parseCssModule(module, text, startOrder = 0) {
|
|
439
447
|
const rules = [];
|
|
@@ -1052,6 +1060,25 @@ class Reader {
|
|
|
1052
1060
|
opts;
|
|
1053
1061
|
cache = /* @__PURE__ */ new Map();
|
|
1054
1062
|
aliasCache = /* @__PURE__ */ new Map();
|
|
1063
|
+
elements = /* @__PURE__ */ new Map();
|
|
1064
|
+
/**
|
|
1065
|
+
* The element a Base UI part renders ("Increment" -> "button"), as Base UI's own docs say it
|
|
1066
|
+
* (node_modules/@base-ui/react/docs/react/components/<module>.md: "### Increment ... Renders a `<button>` element").
|
|
1067
|
+
*/
|
|
1068
|
+
baseUiElement(modules, part) {
|
|
1069
|
+
for (const m of modules) {
|
|
1070
|
+
let parts = this.elements.get(m);
|
|
1071
|
+
if (!parts) {
|
|
1072
|
+
parts = /* @__PURE__ */ new Map();
|
|
1073
|
+
const text = this.opts.read(`node_modules/@base-ui/react/docs/react/components/${m}.md`) ?? "";
|
|
1074
|
+
for (const hit of text.matchAll(/^### ([\w.]+)\n(?:(?!#)[^\n]*\n){0,6}?Renders an? `<([a-z0-9-]+)>` element/gm)) parts.set(hit[1], hit[2]);
|
|
1075
|
+
this.elements.set(m, parts);
|
|
1076
|
+
}
|
|
1077
|
+
const el = parts.get(part);
|
|
1078
|
+
if (el) return el;
|
|
1079
|
+
}
|
|
1080
|
+
return void 0;
|
|
1081
|
+
}
|
|
1055
1082
|
dirOf(name) {
|
|
1056
1083
|
return `${this.opts.componentsDir}/${name}`;
|
|
1057
1084
|
}
|
|
@@ -1424,7 +1451,11 @@ function evaluate(e, scope) {
|
|
|
1424
1451
|
if (ts.isObjectLiteralExpression(e)) {
|
|
1425
1452
|
const out = {};
|
|
1426
1453
|
for (const p of e.properties) {
|
|
1427
|
-
if (ts.isPropertyAssignment(p)
|
|
1454
|
+
if (ts.isPropertyAssignment(p) && ts.isComputedPropertyName(p.name)) {
|
|
1455
|
+
const key = evaluate(p.name.expression, scope);
|
|
1456
|
+
if (typeof key !== "string" && typeof key !== "number") return OPAQUE;
|
|
1457
|
+
out[String(key)] = evaluate(p.initializer, scope);
|
|
1458
|
+
} else if (ts.isPropertyAssignment(p)) out[unquote(p.name.getText(sf))] = evaluate(p.initializer, scope);
|
|
1428
1459
|
else if (ts.isShorthandPropertyAssignment(p)) out[p.name.text] = lookup(scope, p.name.text);
|
|
1429
1460
|
else if (ts.isSpreadAssignment(p)) {
|
|
1430
1461
|
const v = evaluate(p.expression, scope);
|
|
@@ -1436,6 +1467,12 @@ function evaluate(e, scope) {
|
|
|
1436
1467
|
if (ts.isArrayLiteralExpression(e)) return e.elements.map((x) => evaluate(x, scope));
|
|
1437
1468
|
return OPAQUE;
|
|
1438
1469
|
}
|
|
1470
|
+
function styleVarsOf(style) {
|
|
1471
|
+
if (!style || typeof style !== "object" || Array.isArray(style) || isJsx(style)) return void 0;
|
|
1472
|
+
const vars = /* @__PURE__ */ new Map();
|
|
1473
|
+
for (const [k, v] of Object.entries(style)) if (k.startsWith("--") && (typeof v === "number" || typeof v === "string")) vars.set(k, String(v));
|
|
1474
|
+
return vars.size ? vars : void 0;
|
|
1475
|
+
}
|
|
1439
1476
|
const isData = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || v === null || v === void 0 || Array.isArray(v) && v.every(isData) || !!v && typeof v === "object" && !isJsx(v) && !isClass(v) && !isStyles(v) && !isTextRef(v) && !isFnRef(v) && Object.values(v).every(isData);
|
|
1440
1477
|
function callData(fn, args) {
|
|
1441
1478
|
const data = args.map((a) => isTextRef(a) ? a.text : a);
|
|
@@ -1725,7 +1762,11 @@ function renderJsx(ref, ctx, visible) {
|
|
|
1725
1762
|
const extra = classList(attrs.className);
|
|
1726
1763
|
if (isJsx(r)) {
|
|
1727
1764
|
const nodes = renderJsx(r, ctx, visible);
|
|
1728
|
-
if (nodes[0])
|
|
1765
|
+
if (nodes[0]) {
|
|
1766
|
+
nodes[0].classes = [...nodes[0].classes, ...extra];
|
|
1767
|
+
const vars2 = styleVarsOf(attrs.style);
|
|
1768
|
+
if (vars2) nodes[0].styleVars = new Map([...nodes[0].styleVars ?? [], ...vars2]);
|
|
1769
|
+
}
|
|
1729
1770
|
return nodes;
|
|
1730
1771
|
}
|
|
1731
1772
|
const init = open.attributes.properties.find((a) => ts.isJsxAttribute(a) && a.name.getText(sf) === "render")?.initializer;
|
|
@@ -1763,22 +1804,20 @@ function renderJsx(ref, ctx, visible) {
|
|
|
1763
1804
|
children: [],
|
|
1764
1805
|
kind: "frame",
|
|
1765
1806
|
...visible ? { visible } : {},
|
|
1766
|
-
...scope.src.baseUi.has(tag.split(".")[0]) ? ctx.selected !== void 0 && typeof attrs.value === "string" ? { baseUi: true, checked: attrs.value === ctx.selected ? "true" : "false", selectedBy: true } : { baseUi: true, checked: scope.main ? "state" : scope.checked ?? "false" } : {},
|
|
1807
|
+
...scope.src.baseUi.has(tag.split(".")[0]) ? ctx.selected !== void 0 && typeof attrs.value === "string" ? { baseUi: true, checked: (Array.isArray(ctx.selected) ? ctx.selected.includes(attrs.value) : attrs.value === ctx.selected) ? "true" : "false", selectedBy: true } : { baseUi: true, checked: scope.main ? "state" : scope.checked ?? "false" } : {},
|
|
1767
1808
|
...dataAttrs.size ? { attrs: dataAttrs } : {},
|
|
1768
1809
|
.../(^img$|\.Image$)/.test(tag) ? { media: true } : {},
|
|
1769
1810
|
// Base UI indicators are only mounted while their item is checked, unless keepMounted.
|
|
1770
1811
|
.../\.(Item)?Indicator$/.test(tag) && scope.src.baseUi.has(tag.split(".")[0]) && attrs.keepMounted !== true && ctx.fraction === void 0 ? { whenChecked: true } : {}
|
|
1771
1812
|
};
|
|
1813
|
+
const element = isBaseUi ? ctx.reader.baseUiElement(scope.src.baseUiModules, tag.split(".").slice(1).join(".")) : tag;
|
|
1814
|
+
if (element === "button" || element === "select") node.borderBox = true;
|
|
1772
1815
|
if (isBaseUi && /\.Panel$/.test(tag) && node.selectedBy && node.checked === "false") node.inactive = true;
|
|
1773
1816
|
if (isBaseUi && /\.Thumb$/.test(tag) && ctx.fraction !== void 0) node.at = ctx.fraction;
|
|
1774
1817
|
const bg = attrs.style && typeof attrs.style === "object" && !Array.isArray(attrs.style) ? attrs.style.backgroundColor : void 0;
|
|
1775
1818
|
if (typeof bg === "string") node.inlineFill = bg;
|
|
1776
|
-
const
|
|
1777
|
-
if (
|
|
1778
|
-
const vars = /* @__PURE__ */ new Map();
|
|
1779
|
-
for (const [k, v] of Object.entries(style)) if (k.startsWith("--") && (typeof v === "number" || typeof v === "string")) vars.set(k, String(v));
|
|
1780
|
-
if (vars.size) node.styleVars = vars;
|
|
1781
|
-
}
|
|
1819
|
+
const vars = styleVarsOf(attrs.style);
|
|
1820
|
+
if (vars) node.styleVars = vars;
|
|
1782
1821
|
if (tag === "svg") {
|
|
1783
1822
|
const lit = {};
|
|
1784
1823
|
for (const [k, v] of Object.entries(attrs)) if ((typeof v === "string" || typeof v === "number") && k !== "className") lit[k] = String(v);
|
|
@@ -2190,6 +2229,24 @@ function collapseText(n, root = true, boxed = () => false, unseen = () => false)
|
|
|
2190
2229
|
}
|
|
2191
2230
|
return n;
|
|
2192
2231
|
}
|
|
2232
|
+
function inheritedInside(root, classes, rules, page) {
|
|
2233
|
+
const path = [];
|
|
2234
|
+
const find = (n) => {
|
|
2235
|
+
if (n !== root && classes.every((c) => n.classes.includes(c))) return true;
|
|
2236
|
+
path.push(n);
|
|
2237
|
+
for (const c of n.children) if (find(c)) return true;
|
|
2238
|
+
path.pop();
|
|
2239
|
+
return false;
|
|
2240
|
+
};
|
|
2241
|
+
if (!find(root)) return void 0;
|
|
2242
|
+
let ctx = page;
|
|
2243
|
+
for (const n of path) {
|
|
2244
|
+
if (n.kind !== "frame") continue;
|
|
2245
|
+
const el = { tag: n.tag, classes: new Set(n.classes), children: [], present: true, isRoot: false, inputLike: false };
|
|
2246
|
+
ctx = computeValues(declaredFor(rules, el, DEFAULT_STATE), ctx);
|
|
2247
|
+
}
|
|
2248
|
+
return ctx;
|
|
2249
|
+
}
|
|
2193
2250
|
function applyView(root, view) {
|
|
2194
2251
|
if (!view) return root;
|
|
2195
2252
|
const isPortal = (n) => /\.Portal$/.test(n.tag);
|
|
@@ -2209,7 +2266,8 @@ function applyView(root, view) {
|
|
|
2209
2266
|
}
|
|
2210
2267
|
function build(reader, src, props, preview, view, rules = [], tokens, examples) {
|
|
2211
2268
|
const blockers = [];
|
|
2212
|
-
const
|
|
2269
|
+
const dv = props.defaultValue;
|
|
2270
|
+
const selected = typeof dv === "string" ? dv : Array.isArray(dv) && dv.every((x) => typeof x === "string") ? dv : void 0;
|
|
2213
2271
|
const rendered = renderComponent(reader, src.name, { ...props, children: CHILDREN }, { reader, depth: 0, component: src.name, blockers, ...selected !== void 0 ? { selected } : {}, ...examples ? { examples } : {} }, void 0, preview);
|
|
2214
2272
|
let root = rendered && applyView(rendered, view);
|
|
2215
2273
|
if (!root) return void 0;
|
|
@@ -2227,10 +2285,12 @@ function build(reader, src, props, preview, view, rules = [], tokens, examples)
|
|
|
2227
2285
|
root.children.push(n);
|
|
2228
2286
|
}
|
|
2229
2287
|
}
|
|
2230
|
-
const follow = (n, inherited) => {
|
|
2288
|
+
const follow = (n, inherited, item) => {
|
|
2231
2289
|
if (n.baseUi && n.selectedBy) inherited = n.checked;
|
|
2232
2290
|
else if (n.baseUi && inherited) n.checked = inherited;
|
|
2233
|
-
|
|
2291
|
+
if (n.baseUi && /\.Item$/.test(n.tag)) item = n;
|
|
2292
|
+
if (n.baseUi && /\.Panel$/.test(n.tag) && item && item.checked !== "true" && item.checked !== "state") n.inactive = true;
|
|
2293
|
+
for (const c of n.children) follow(c, inherited, item);
|
|
2234
2294
|
};
|
|
2235
2295
|
follow(root, void 0);
|
|
2236
2296
|
decorate(root, rules, tokens);
|
|
@@ -2393,9 +2453,23 @@ function resolveValue(raw, values, tokens, depth = 0, parent, forColor = false)
|
|
|
2393
2453
|
return { unmapped: "literal value, not a token" };
|
|
2394
2454
|
}
|
|
2395
2455
|
function calcValue(v, values, tokens, depth, parent) {
|
|
2396
|
-
|
|
2456
|
+
let inner = v.slice(v.indexOf("(") + 1, v.lastIndexOf(")"));
|
|
2397
2457
|
let failed;
|
|
2458
|
+
if (/\d*\.?\d+lh\b/.test(inner)) {
|
|
2459
|
+
const fs = resolveValue(values.get("font-size"), values, tokens, depth + 1, parent);
|
|
2460
|
+
const lh = resolveValue(values.get("line-height"), values, tokens, depth + 1, parent);
|
|
2461
|
+
if (typeof fs?.value === "string" && typeof lh?.value === "string" && !fs.value.startsWith("calc(") && !lh.value.startsWith("calc(")) {
|
|
2462
|
+
inner = inner.replace(/(\d*\.?\d+)lh\b/g, (_m, n) => Number(n) === 1 ? `(${fs.value} * ${lh.value})` : `${n} * (${fs.value} * ${lh.value})`);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2398
2465
|
const substituted = inner.replace(/var\(\s*--[\w-]+\s*(?:,[^()]*)?\)/g, (m) => {
|
|
2466
|
+
let raw = m;
|
|
2467
|
+
for (let hops = 0; hops < 12 && raw; hops++) {
|
|
2468
|
+
const name = /^var\(\s*(--[\w-]+)/.exec(raw.trim())?.[1];
|
|
2469
|
+
if (!name || tokens.has(name)) break;
|
|
2470
|
+
raw = values.get(name);
|
|
2471
|
+
}
|
|
2472
|
+
if (raw !== void 0 && /^-?\d*\.?\d+$/.test(raw.trim())) return raw.trim();
|
|
2399
2473
|
const r = resolveValue(m, values, tokens, depth + 1, parent);
|
|
2400
2474
|
if (!r || r.unmapped !== void 0 || r.value === null || r.value === void 0) {
|
|
2401
2475
|
failed ??= r?.unmapped ?? `${m} has no value`;
|
|
@@ -2531,8 +2605,29 @@ function partValues(node, computed, own, tokens, parent) {
|
|
|
2531
2605
|
const v = own.get(prop);
|
|
2532
2606
|
if (v !== void 0 && /var\(/.test(v)) out.unmapped.push({ property: prop, value: v, reason });
|
|
2533
2607
|
}
|
|
2608
|
+
contentBoxMinimums(out.values, computed, node.borderBox);
|
|
2534
2609
|
return out;
|
|
2535
2610
|
}
|
|
2611
|
+
function contentBoxMinimums(values, computed, borderBoxByDefault = false) {
|
|
2612
|
+
if ((computed.get("box-sizing") ?? (borderBoxByDefault ? "border-box" : "content-box")).trim() === "border-box") return;
|
|
2613
|
+
const term = (v) => {
|
|
2614
|
+
if (v === void 0 || v === null || v === 0) return void 0;
|
|
2615
|
+
if (typeof v === "number") return String(v);
|
|
2616
|
+
if (typeof v !== "string") return void 0;
|
|
2617
|
+
return v.startsWith("calc(") ? `(${v.slice(5, -1)})` : v;
|
|
2618
|
+
};
|
|
2619
|
+
const sum = (base, extra) => {
|
|
2620
|
+
const add = extra.map(term).filter((t) => !!t);
|
|
2621
|
+
const head = term(base);
|
|
2622
|
+
if (!add.length || !head) return base;
|
|
2623
|
+
return `calc(${[head, ...add].join(" + ")})`;
|
|
2624
|
+
};
|
|
2625
|
+
const border = (side) => values[`stroke${side}Weight`] ?? values.strokeWeight;
|
|
2626
|
+
if (values.minHeight !== void 0) values.minHeight = sum(values.minHeight, [values.paddingTop, values.paddingBottom, border("Top"), border("Bottom")]);
|
|
2627
|
+
if (values.minWidth !== void 0) values.minWidth = sum(values.minWidth, [values.paddingLeft, values.paddingRight, border("Left"), border("Right")]);
|
|
2628
|
+
if (values.height !== void 0) values.height = sum(values.height, [values.paddingTop, values.paddingBottom, border("Top"), border("Bottom")]);
|
|
2629
|
+
if (values.width !== void 0) values.width = sum(values.width, [values.paddingLeft, values.paddingRight, border("Left"), border("Right")]);
|
|
2630
|
+
}
|
|
2536
2631
|
const singleCellGrid = (c) => /grid/.test(c.get("display") ?? "") && ["grid-template-columns", "grid-template-rows", "grid-template-areas", "grid-template", "grid-auto-flow", "grid-auto-columns"].every((k) => !c.get(k) || c.get(k) === "none");
|
|
2537
2632
|
const TABLE_DISPLAY = { table: "table", thead: "table-row-group", tbody: "table-row-group", tfoot: "table-row-group", tr: "table-row", td: "table-cell", th: "table-cell", caption: "table-caption" };
|
|
2538
2633
|
const gridCounter = (v) => /center/.test(v ?? "") ? "CENTER" : /end/.test(v ?? "") ? "MAX" : /start/.test(v ?? "") ? "MIN" : "STRETCH";
|
|
@@ -2944,6 +3039,14 @@ function generateComponentSpec(name, opts, view, setName = name, fixed = {}) {
|
|
|
2944
3039
|
const v = previewEl?.p?.[p.name];
|
|
2945
3040
|
if (p.kind === "string" && p.optional && typeof v === "string" && baseProps[p.name] === void 0) examples[p.name] = v;
|
|
2946
3041
|
}
|
|
3042
|
+
if (view === "without-popup" && name !== src.folder) {
|
|
3043
|
+
const own = build(reader, src, { ...baseProps, ...fixed }, previewKids, view, rules, opts.tokens)?.root.classes ?? [];
|
|
3044
|
+
const folderSrc = reader.load(src.folder);
|
|
3045
|
+
const folderPreview = previewElement(docs?.preview, src.folder) ?? storyElement(readStories(src.folder, opts), src.folder);
|
|
3046
|
+
const folderKids = folderPreview?.children?.some((c) => typeof c !== "string") ? folderPreview.children : void 0;
|
|
3047
|
+
const popup = own.length && folderSrc && folderKids ? build(reader, folderSrc, {}, folderKids, "popup", rules, opts.tokens) : void 0;
|
|
3048
|
+
if (popup) page = inheritedInside(popup.root, own, rules, page) ?? inheritedInside({ ...popup.root, children: [{ ...popup.root, classes: own, children: [] }] }, own, rules, page) ?? page;
|
|
3049
|
+
}
|
|
2947
3050
|
const evalAt = (props, state) => evaluateVariant(reader, src, rules, { ...baseProps, ...props, ...fixed }, state, opts.tokens, previewKids, page, view, Object.keys(examples).length ? examples : void 0);
|
|
2948
3051
|
const base = evalAt({}, DEFAULT_STATE);
|
|
2949
3052
|
if (!base) throw new UnsupportedComponentError(name, "renders in a way the generator cannot read yet");
|
|
@@ -3844,25 +3947,1521 @@ function fsSource(root, ref = {}) {
|
|
|
3844
3947
|
}
|
|
3845
3948
|
};
|
|
3846
3949
|
}
|
|
3950
|
+
const MEASURE_SCRIPT = String.raw`(function (arg) {
|
|
3951
|
+
arg = arg || {};
|
|
3952
|
+
var MAX_NODES = arg.maxNodes || 400;
|
|
3953
|
+
var MAX_DEPTH = arg.maxDepth || 14;
|
|
3954
|
+
var rootSel = arg.root || '#storybook-root, #root';
|
|
3955
|
+
var PROPS = ['display', 'position', 'visibility', 'opacity', 'overflow', 'box-sizing',
|
|
3956
|
+
'flex-direction', 'flex-wrap', 'justify-content', 'align-items', 'align-self', 'flex-grow', 'row-gap', 'column-gap',
|
|
3957
|
+
'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
|
|
3958
|
+
'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
|
|
3959
|
+
'width', 'height', 'min-width', 'min-height',
|
|
3960
|
+
'background-color', 'background-image',
|
|
3961
|
+
'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width',
|
|
3962
|
+
'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style',
|
|
3963
|
+
'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color',
|
|
3964
|
+
'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius',
|
|
3965
|
+
'box-shadow', 'outline-style', 'outline-width', 'outline-color',
|
|
3966
|
+
'color', 'font-family', 'font-size', 'font-weight', 'line-height', 'letter-spacing', 'text-decoration-line', 'text-transform', 'text-align', 'white-space',
|
|
3967
|
+
'fill', 'stroke', 'stroke-width', 'transform', 'grid-auto-flow', 'grid-template-columns', 'grid-template-rows', 'left', 'top', 'right', 'bottom'];
|
|
3968
|
+
// Properties a token is looked for (paint, spacing, shape, type).
|
|
3969
|
+
var TOKENED = ['row-gap', 'column-gap', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'width', 'height', 'min-width', 'min-height',
|
|
3970
|
+
'background-color', 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width',
|
|
3971
|
+
'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color',
|
|
3972
|
+
'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius',
|
|
3973
|
+
'box-shadow', 'opacity', 'color', 'font-family', 'font-size', 'font-weight', 'line-height', 'letter-spacing', 'fill', 'stroke', 'stroke-width'];
|
|
3974
|
+
// Longhand -> shorthands that may set it, with the position of the longhand in a 1 to 4 value box shorthand.
|
|
3975
|
+
var SIDES = { top: 0, right: 1, bottom: 2, left: 3 };
|
|
3976
|
+
var CORNERS = { 'top-left': 0, 'top-right': 1, 'bottom-right': 2, 'bottom-left': 3 };
|
|
3977
|
+
var LOGICAL = { top: 'block-start', bottom: 'block-end', left: 'inline-start', right: 'inline-end' };
|
|
3978
|
+
var LOGICAL_CORNER = { 'top-left': 'start-start', 'top-right': 'start-end', 'bottom-right': 'end-end', 'bottom-left': 'end-start' };
|
|
3979
|
+
function shorthandsOf(p) {
|
|
3980
|
+
var m;
|
|
3981
|
+
// Logical longhands too (padding-block-start: a horizontal writing mode, left to right).
|
|
3982
|
+
if ((m = /^padding-(top|right|bottom|left)$/.exec(p))) return [['padding-' + LOGICAL[m[1]], -1], ['padding', SIDES[m[1]]], ['padding-block', m[1] === 'top' ? 0 : m[1] === 'bottom' ? 1 : -1], ['padding-inline', m[1] === 'left' ? 0 : m[1] === 'right' ? 1 : -1]].filter(function (x) { return !/block$|inline$/.test(x[0]) || x[1] >= 0; });
|
|
3983
|
+
if ((m = /^margin-(top|right|bottom|left)$/.exec(p))) return [['margin-' + LOGICAL[m[1]], -1], ['margin', SIDES[m[1]]]];
|
|
3984
|
+
if ((m = /^border-(top-left|top-right|bottom-right|bottom-left)-radius$/.exec(p))) return [['border-' + LOGICAL_CORNER[m[1]] + '-radius', -1], ['border-radius', CORNERS[m[1]]]];
|
|
3985
|
+
if ((m = /^border-(top|right|bottom|left)-(width|color|style)$/.exec(p))) return [['border-' + LOGICAL[m[1]] + '-' + m[2], -1], ['border-' + LOGICAL[m[1]], -1], ['border-' + m[2], SIDES[m[1]]], ['border-' + m[1], -1], ['border', -1], ['border-' + (m[1] === 'top' || m[1] === 'bottom' ? 'block' : 'inline'), -1]];
|
|
3986
|
+
if (p === 'row-gap') return [['gap', 0]];
|
|
3987
|
+
if (p === 'column-gap') return [['gap', 1]];
|
|
3988
|
+
if (p === 'background-color') return [['background', -1]];
|
|
3989
|
+
if (/^font-/.test(p) || p === 'line-height') return [['font', -1]];
|
|
3990
|
+
return [];
|
|
3991
|
+
}
|
|
3992
|
+
|
|
3993
|
+
// ---- style rules, read once ----
|
|
3994
|
+
var rules = [];
|
|
3995
|
+
var order = 0;
|
|
3996
|
+
function walk(list, layered) {
|
|
3997
|
+
for (var i = 0; i < list.length; i++) {
|
|
3998
|
+
var r = list[i];
|
|
3999
|
+
try {
|
|
4000
|
+
if (r.selectorText !== undefined && r.style) {
|
|
4001
|
+
rules.push({ sel: r.selectorText, style: r.style, order: order++, layered: layered });
|
|
4002
|
+
if (r.cssRules && r.cssRules.length) walk(r.cssRules, layered); // CSS nesting
|
|
4003
|
+
} else if (r.media !== undefined && r.cssRules) {
|
|
4004
|
+
if (window.matchMedia(r.media.mediaText || 'all').matches) walk(r.cssRules, layered);
|
|
4005
|
+
} else if (r.conditionText !== undefined && r.cssRules) {
|
|
4006
|
+
walk(r.cssRules, layered);
|
|
4007
|
+
} else if (r.cssRules && r.name !== undefined) {
|
|
4008
|
+
walk(r.cssRules, true); // @layer block: unlayered rules win over it
|
|
4009
|
+
} else if (r.cssRules) {
|
|
4010
|
+
walk(r.cssRules, layered);
|
|
4011
|
+
}
|
|
4012
|
+
} catch (e) {}
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
var sheetsRead = 0, sheetsBlocked = 0;
|
|
4016
|
+
for (var s = 0; s < document.styleSheets.length; s++) {
|
|
4017
|
+
try { walk(document.styleSheets[s].cssRules, false); sheetsRead++; } catch (e) { sheetsBlocked++; }
|
|
4018
|
+
}
|
|
4019
|
+
try { for (var a = 0; a < (document.adoptedStyleSheets || []).length; a++) walk(document.adoptedStyleSheets[a].cssRules, false); } catch (e) {}
|
|
4020
|
+
|
|
4021
|
+
function splitTop(text, sepRe) {
|
|
4022
|
+
var out = [], depth = 0, cur = '', q = null;
|
|
4023
|
+
for (var i = 0; i < text.length; i++) {
|
|
4024
|
+
var c = text[i];
|
|
4025
|
+
if (q) { cur += c; if (c === q) q = null; continue; }
|
|
4026
|
+
if (c === '"' || c === "'") { q = c; cur += c; continue; }
|
|
4027
|
+
if (c === '(' || c === '[') depth++;
|
|
4028
|
+
if (c === ')' || c === ']') depth--;
|
|
4029
|
+
if (depth === 0 && sepRe.test(c)) { if (cur.trim()) out.push(cur.trim()); cur = ''; continue; }
|
|
4030
|
+
cur += c;
|
|
4031
|
+
}
|
|
4032
|
+
if (cur.trim()) out.push(cur.trim());
|
|
4033
|
+
return out;
|
|
4034
|
+
}
|
|
4035
|
+
function specificity(sel) {
|
|
4036
|
+
var s = sel.replace(/:where\([^)]*\)/g, '').replace(/::?(before|after|placeholder|selection|marker|backdrop)\b/g, '');
|
|
4037
|
+
var ids = (s.match(/#[\w-]+/g) || []).length;
|
|
4038
|
+
var cls = (s.match(/\.[\w-]+|\[[^\]]*\]|:(?!not\b|is\b|has\b)[\w-]+(\([^)]*\))?/g) || []).length;
|
|
4039
|
+
var types = (s.replace(/\[[^\]]*\]|\([^)]*\)/g, '').match(/(^|[\s>+~(])[a-zA-Z][\w-]*/g) || []).length;
|
|
4040
|
+
return ids * 10000 + cls * 100 + types;
|
|
4041
|
+
}
|
|
4042
|
+
var PSEUDO_END = /::?(before|after)\s*$/;
|
|
4043
|
+
// pseudo: the rules for el::before / el::after (the selector minus its pseudo-element); none: the element's own.
|
|
4044
|
+
function matchSpec(el, selText, pseudo) {
|
|
4045
|
+
var best = -1;
|
|
4046
|
+
var parts = splitTop(selText, /,/);
|
|
4047
|
+
for (var i = 0; i < parts.length; i++) {
|
|
4048
|
+
var part = parts[i];
|
|
4049
|
+
var pm = PSEUDO_END.exec(part);
|
|
4050
|
+
if (pseudo) {
|
|
4051
|
+
if (!pm || pm[1] !== pseudo) continue;
|
|
4052
|
+
part = part.slice(0, pm.index).trim() || '*';
|
|
4053
|
+
} else if (pm || /::/.test(part)) continue;
|
|
4054
|
+
try { if (el.matches(part)) best = Math.max(best, specificity(part) + (pseudo ? 1 : 0)); } catch (e) {}
|
|
4055
|
+
}
|
|
4056
|
+
return best;
|
|
4057
|
+
}
|
|
4058
|
+
var matchCache = { '': new Map(), before: new Map(), after: new Map() };
|
|
4059
|
+
function matching(el, pseudo) {
|
|
4060
|
+
var cache = matchCache[pseudo || ''];
|
|
4061
|
+
var m = cache.get(el);
|
|
4062
|
+
if (m) return m;
|
|
4063
|
+
m = [];
|
|
4064
|
+
for (var i = 0; i < rules.length; i++) {
|
|
4065
|
+
var sp = matchSpec(el, rules[i].sel, pseudo);
|
|
4066
|
+
if (sp >= 0) m.push({ r: rules[i], sp: sp });
|
|
4067
|
+
}
|
|
4068
|
+
cache.set(el, m);
|
|
4069
|
+
return m;
|
|
4070
|
+
}
|
|
4071
|
+
// The winning declared value of a property (longhand or the shorthand that sets it) on an element or its pseudo.
|
|
4072
|
+
function declared(el, prop, pseudo) {
|
|
4073
|
+
var best = null;
|
|
4074
|
+
function consider(value, important, layered, sp, ord, shorthand, pos) {
|
|
4075
|
+
if (!value) return;
|
|
4076
|
+
var rank = [important ? (layered ? 3 : 2) : (layered ? 0 : 1), sp, ord];
|
|
4077
|
+
if (!best || cmp(rank, best.rank) > 0) best = { value: value, rank: rank, shorthand: shorthand, pos: pos };
|
|
4078
|
+
}
|
|
4079
|
+
function cmp(x, y) { for (var i = 0; i < x.length; i++) if (x[i] !== y[i]) return x[i] - y[i]; return 0; }
|
|
4080
|
+
var short = prop.indexOf('--') === 0 ? [] : shorthandsOf(prop);
|
|
4081
|
+
var m = matching(el, pseudo);
|
|
4082
|
+
for (var i = 0; i < m.length; i++) {
|
|
4083
|
+
var st = m[i].r.style;
|
|
4084
|
+
var v = st.getPropertyValue(prop);
|
|
4085
|
+
if (v) consider(v, st.getPropertyPriority(prop) === 'important', m[i].r.layered, m[i].sp, m[i].r.order, null, -1);
|
|
4086
|
+
else for (var k = 0; k < short.length; k++) {
|
|
4087
|
+
var sv = st.getPropertyValue(short[k][0]);
|
|
4088
|
+
if (sv) consider(sv, st.getPropertyPriority(short[k][0]) === 'important', m[i].r.layered, m[i].sp, m[i].r.order, short[k][0], short[k][1]);
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
var inl = !pseudo && el.style && el.style.getPropertyValue(prop);
|
|
4092
|
+
if (inl) consider(inl, el.style.getPropertyPriority(prop) === 'important', false, 1e9, 1e9, null, -1);
|
|
4093
|
+
else if (el.style && !pseudo) for (var j = 0; j < short.length; j++) {
|
|
4094
|
+
var iv = el.style.getPropertyValue(short[j][0]);
|
|
4095
|
+
if (iv) consider(iv, false, false, 1e9, 1e9, short[j][0], short[j][1]);
|
|
4096
|
+
}
|
|
4097
|
+
return best;
|
|
4098
|
+
}
|
|
4099
|
+
function varsIn(value) {
|
|
4100
|
+
var out = [], re = /var\(\s*(--[\w-]+)/g, m;
|
|
4101
|
+
while ((m = re.exec(value))) out.push(m[1]);
|
|
4102
|
+
return out;
|
|
4103
|
+
}
|
|
4104
|
+
// The piece of a box shorthand that sets one side ("padding: var(--a) var(--b)" -> right is var(--b)).
|
|
4105
|
+
function boxPiece(value, pos) {
|
|
4106
|
+
if (pos < 0) return value;
|
|
4107
|
+
var parts = splitTop(value.replace(/\s*\/.*$/, ''), /\s/);
|
|
4108
|
+
if (parts.length === 1) return parts[0];
|
|
4109
|
+
if (parts.length === 2) return parts[pos % 2];
|
|
4110
|
+
if (parts.length === 3) return parts[pos === 3 ? 1 : pos];
|
|
4111
|
+
return parts[pos] || value;
|
|
4112
|
+
}
|
|
4113
|
+
// Custom property chain: --button-bg -> --color-action-primary-bg -> --color-orange-500.
|
|
4114
|
+
function chainOf(el, name) {
|
|
4115
|
+
var chain = [name], seen = {};
|
|
4116
|
+
seen[name] = 1;
|
|
4117
|
+
var cur = name;
|
|
4118
|
+
for (var d = 0; d < 8; d++) {
|
|
4119
|
+
var found = null;
|
|
4120
|
+
for (var e = el; e && e.nodeType === 1; e = e.parentElement) {
|
|
4121
|
+
var dv = declared(e, cur);
|
|
4122
|
+
if (dv) { found = dv.value; break; }
|
|
4123
|
+
}
|
|
4124
|
+
if (!found) break;
|
|
4125
|
+
var next = varsIn(found);
|
|
4126
|
+
if (next.length !== 1 || seen[next[0]] || found.trim().indexOf('var(') !== 0) break;
|
|
4127
|
+
seen[next[0]] = 1;
|
|
4128
|
+
chain.push(next[0]);
|
|
4129
|
+
cur = next[0];
|
|
4130
|
+
}
|
|
4131
|
+
return chain;
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4134
|
+
// ---- value normalisation through a probe element ----
|
|
4135
|
+
var probe = document.createElement('div');
|
|
4136
|
+
probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none;width:0;height:0';
|
|
4137
|
+
document.body.appendChild(probe);
|
|
4138
|
+
var colorCache = {};
|
|
4139
|
+
function normColor(v) {
|
|
4140
|
+
if (v in colorCache) return colorCache[v];
|
|
4141
|
+
probe.style.color = '';
|
|
4142
|
+
probe.style.color = v;
|
|
4143
|
+
var out = probe.style.color ? getComputedStyle(probe).color : null;
|
|
4144
|
+
colorCache[v] = out;
|
|
4145
|
+
return out;
|
|
4146
|
+
}
|
|
4147
|
+
function normLength(v) {
|
|
4148
|
+
probe.style.width = '';
|
|
4149
|
+
probe.style.width = v;
|
|
4150
|
+
if (!probe.style.width) return null;
|
|
4151
|
+
var w = getComputedStyle(probe).width;
|
|
4152
|
+
probe.style.width = '0';
|
|
4153
|
+
return w;
|
|
4154
|
+
}
|
|
4155
|
+
var isColorProp = function (p) { return /color$/.test(p) || p === 'fill' || p === 'stroke'; };
|
|
4156
|
+
|
|
4157
|
+
// Variables in scope at the component (for value matching): defined on :root, or on a provider element around the
|
|
4158
|
+
// story (Fluent's FluentProvider, a theme wrapper). Custom properties inherit, so the component root's computed style
|
|
4159
|
+
// holds both.
|
|
4160
|
+
var rootVars = null;
|
|
4161
|
+
var scopeEl = null;
|
|
4162
|
+
function rootTokens() {
|
|
4163
|
+
if (rootVars) return rootVars;
|
|
4164
|
+
rootVars = { colors: {}, lengths: {}, count: 0, scoped: 0 };
|
|
4165
|
+
var cs = getComputedStyle(scopeEl || document.documentElement);
|
|
4166
|
+
var top = scopeEl ? getComputedStyle(document.documentElement) : cs;
|
|
4167
|
+
var names = {};
|
|
4168
|
+
for (var i = 0; i < rules.length; i++) {
|
|
4169
|
+
var st = rules[i].style;
|
|
4170
|
+
for (var k = 0; k < st.length; k++) if (st[k].indexOf('--') === 0) names[st[k]] = 1;
|
|
4171
|
+
}
|
|
4172
|
+
for (var i2 = 0; i2 < cs.length; i2++) if (cs[i2].indexOf('--') === 0) names[cs[i2]] = 1;
|
|
4173
|
+
for (var i3 = 0; scopeEl && i3 < top.length; i3++) if (top[i3].indexOf('--') === 0) names[top[i3]] = 1;
|
|
4174
|
+
for (var n in names) {
|
|
4175
|
+
var v = cs.getPropertyValue(n).trim();
|
|
4176
|
+
if (!v) continue;
|
|
4177
|
+
rootVars.count++;
|
|
4178
|
+
if (scopeEl && !top.getPropertyValue(n).trim()) rootVars.scoped++;
|
|
4179
|
+
if (/^(#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(v)) {
|
|
4180
|
+
var c = normColor(v);
|
|
4181
|
+
if (c) (rootVars.colors[c] = rootVars.colors[c] || []).push(n);
|
|
4182
|
+
} else if (/^-?[\d.]+(px|rem|em)$/.test(v)) {
|
|
4183
|
+
var l = normLength(v);
|
|
4184
|
+
if (l) (rootVars.lengths[l] = rootVars.lengths[l] || []).push(n);
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
return rootVars;
|
|
4188
|
+
}
|
|
4189
|
+
|
|
4190
|
+
function tokenFor(el, prop, computed, pseudo) {
|
|
4191
|
+
var d = declared(el, prop, pseudo);
|
|
4192
|
+
// A pseudo-element inherits from its element, an element from its parent.
|
|
4193
|
+
var parentOf = pseudo ? el : el.parentElement;
|
|
4194
|
+
if (d) {
|
|
4195
|
+
var piece = d.shorthand && /^(padding|margin|border-radius|border-width|border-color|border-style|gap)$/.test(d.shorthand) ? boxPiece(d.value, d.pos) : d.value;
|
|
4196
|
+
var vars = varsIn(piece);
|
|
4197
|
+
if (vars.length) {
|
|
4198
|
+
var pick = vars[0];
|
|
4199
|
+
if (vars.length > 1) {
|
|
4200
|
+
var cs = getComputedStyle(el, pseudo ? '::' + pseudo : null);
|
|
4201
|
+
for (var i = 0; i < vars.length; i++) {
|
|
4202
|
+
var rv = cs.getPropertyValue(vars[i]).trim();
|
|
4203
|
+
var same = isColorProp(prop) ? normColor(rv) === computed : normLength(rv) === computed;
|
|
4204
|
+
if (same) { pick = vars[i]; break; }
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
var chain = chainOf(el, pick);
|
|
4208
|
+
// A color function around channels alone ("hsl(var(--primary))") gives the variable's color: tied to it too.
|
|
4209
|
+
var channels = isColorProp(prop) && vars.length === 1 ? /^(rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\(\s*var\(\s*--[\w-]+\s*\)\s*\)$/i.exec(piece.trim()) : null;
|
|
4210
|
+
var direct = (piece.trim().indexOf('var(') === 0 && vars.length === 1) || !!channels;
|
|
4211
|
+
// A declaration that does not give the computed value lost the cascade somewhere this script does not model:
|
|
4212
|
+
// the value is not tied to it (it may still match a variable by value below).
|
|
4213
|
+
if (direct && !/^(line-height|font-weight|opacity|font-family)$/.test(prop)) {
|
|
4214
|
+
var own = getComputedStyle(el, pseudo ? '::' + pseudo : null).getPropertyValue(pick).trim();
|
|
4215
|
+
var got = isColorProp(prop) ? normColor(channels ? channels[1] + '(' + own + ')' : own) : /px$/.test(computed) ? normLength(own) : null;
|
|
4216
|
+
if (own && got && got !== computed) d = null;
|
|
4217
|
+
}
|
|
4218
|
+
if (d) return { via: 'declared', chain: chain, exact: direct, declared: piece.trim() };
|
|
4219
|
+
}
|
|
4220
|
+
if (d && /^(inherit|currentcolor)$/i.test(d.value.trim()) && parentOf && prop !== 'background-color') {
|
|
4221
|
+
var cp = prop === 'fill' || prop === 'stroke' || /border-.*-color/.test(prop) ? 'color' : prop;
|
|
4222
|
+
// currentcolor on another property reads this element's (or pseudo's) own color; inherit, and color:
|
|
4223
|
+
// currentcolor, read the parent's (a pseudo-element's parent is its element).
|
|
4224
|
+
var up = /currentcolor/i.test(d.value) && cp !== prop
|
|
4225
|
+
? tokenFor(el, cp, getComputedStyle(el, pseudo ? '::' + pseudo : null).getPropertyValue(cp), pseudo)
|
|
4226
|
+
: parentOf ? tokenFor(parentOf, cp, getComputedStyle(parentOf).getPropertyValue(cp)) : null;
|
|
4227
|
+
if (up) return up;
|
|
4228
|
+
}
|
|
4229
|
+
} else if (/^(color|font-family|font-size|font-weight|line-height|letter-spacing)$/.test(prop) && parentOf) {
|
|
4230
|
+
// Inherited: the token comes from the nearest ancestor that declares it.
|
|
4231
|
+
return tokenFor(parentOf, prop, computed);
|
|
4232
|
+
}
|
|
4233
|
+
var rt = rootTokens();
|
|
4234
|
+
var hit = isColorProp(prop) ? rt.colors[computed] : rt.lengths[computed];
|
|
4235
|
+
if (hit && hit.length) return { via: 'matched', chain: hit.slice(0, 3), exact: false };
|
|
4236
|
+
return null;
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
// ---- the rendered tree ----
|
|
4240
|
+
var count = 0;
|
|
4241
|
+
function own(el, cs) {
|
|
4242
|
+
var bg = cs.backgroundColor;
|
|
4243
|
+
var hasBg = bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent';
|
|
4244
|
+
var hasBorder = ['Top', 'Right', 'Bottom', 'Left'].some(function (s) { return parseFloat(cs['border' + s + 'Width']) > 0 && cs['border' + s + 'Style'] !== 'none'; });
|
|
4245
|
+
var pad = ['Top', 'Right', 'Bottom', 'Left'].some(function (s) { return parseFloat(cs['padding' + s]) > 0; });
|
|
4246
|
+
var paints = function (v) { return !!v && v !== 'none'; };
|
|
4247
|
+
return hasBg || hasBorder || pad || paints(cs.boxShadow) || paints(cs.backgroundImage);
|
|
4248
|
+
}
|
|
4249
|
+
function directText(el) {
|
|
4250
|
+
var t = '';
|
|
4251
|
+
for (var c = el.firstChild; c; c = c.nextSibling) if (c.nodeType === 3) t += c.nodeValue;
|
|
4252
|
+
return t.replace(/\s+/g, ' ').trim();
|
|
4253
|
+
}
|
|
4254
|
+
function visible(el, cs) {
|
|
4255
|
+
if (cs.display === 'none' || cs.visibility === 'hidden' || cs.visibility === 'collapse') return false;
|
|
4256
|
+
// Closed or hidden content is not a layer: transparent, hidden, inert, clipped away, or a hidden popover.
|
|
4257
|
+
if (parseFloat(cs.opacity) === 0 || el.hidden || el.hasAttribute('inert')) return false;
|
|
4258
|
+
if (/inset\((50|100)%/.test(cs.clipPath || '')) return false;
|
|
4259
|
+
if (el.getAttribute('aria-hidden') === 'true' && (/^(tooltip|dialog|menu|listbox)$/.test(el.getAttribute('role') || '') || /popover|tooltip/i.test(String(el.className && el.className.baseVal !== undefined ? el.className.baseVal : el.className)))) return false;
|
|
4260
|
+
var r = el.getBoundingClientRect();
|
|
4261
|
+
if (r.width === 0 && r.height === 0 && !el.children.length) return false;
|
|
4262
|
+
// Visually hidden text for screen readers (1 px, clipped): not drawn, not a layer.
|
|
4263
|
+
if ((cs.position === 'absolute' || cs.position === 'fixed') && r.width <= 1 && r.height <= 1 && (/hidden|clip/.test(cs.overflow) || cs.clip !== 'auto' && cs.clip !== '' || cs.clipPath !== 'none')) return false;
|
|
4264
|
+
return true;
|
|
4265
|
+
}
|
|
4266
|
+
function round(n) { return Math.round(n * 100) / 100; }
|
|
4267
|
+
// An inline SVG as markup Figma can draw: every shape's computed fill and stroke written on it, currentColor
|
|
4268
|
+
// resolved, the rendered size set.
|
|
4269
|
+
function svgMarkup(el, r) {
|
|
4270
|
+
if (el.outerHTML.length > 12000) return null;
|
|
4271
|
+
var strokes = [];
|
|
4272
|
+
var clone = el.cloneNode(true);
|
|
4273
|
+
var src = [el].concat(Array.prototype.slice.call(el.querySelectorAll('*')));
|
|
4274
|
+
var dst = [clone].concat(Array.prototype.slice.call(clone.querySelectorAll('*')));
|
|
4275
|
+
var color = getComputedStyle(el).color;
|
|
4276
|
+
for (var i = 0; i < src.length && i < dst.length; i++) {
|
|
4277
|
+
var cs = getComputedStyle(src[i]);
|
|
4278
|
+
if (/^(path|circle|rect|ellipse|line|polyline|polygon|use|text)$/.test(src[i].tagName.toLowerCase()) || i === 0) {
|
|
4279
|
+
var f = cs.fill, k = cs.stroke;
|
|
4280
|
+
if (f) dst[i].setAttribute('fill', /url\(/.test(f) ? (src[i].getAttribute('fill') || 'none') : f);
|
|
4281
|
+
if (k && k !== 'none') {
|
|
4282
|
+
dst[i].setAttribute('stroke', k);
|
|
4283
|
+
if (cs.strokeWidth) dst[i].setAttribute('stroke-width', parseFloat(cs.strokeWidth));
|
|
4284
|
+
if (i > 0) strokes.push(k);
|
|
4285
|
+
}
|
|
4286
|
+
else if (i > 0 && k === 'none' && src[i].getAttribute('stroke')) dst[i].setAttribute('stroke', 'none');
|
|
4287
|
+
}
|
|
4288
|
+
dst[i].removeAttribute('class');
|
|
4289
|
+
dst[i].removeAttribute('style');
|
|
4290
|
+
}
|
|
4291
|
+
clone.setAttribute('width', round(r.width));
|
|
4292
|
+
clone.setAttribute('height', round(r.height));
|
|
4293
|
+
if (!clone.getAttribute('xmlns')) clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
|
4294
|
+
return { svg: clone.outerHTML.replace(/currentColor/gi, color), strokes: strokes };
|
|
4295
|
+
}
|
|
4296
|
+
// ::before / ::after drawn as a box (a switch knob, a checkbox's box, a radio's circle): a frame part with its box,
|
|
4297
|
+
// paint, border, radius and position. Text-only or empty pseudo-elements are not parts.
|
|
4298
|
+
function pseudoNode(el, which, hostRect) {
|
|
4299
|
+
var cs = getComputedStyle(el, '::' + which);
|
|
4300
|
+
var content = cs.content;
|
|
4301
|
+
if (!content || content === 'none' || content === 'normal' || cs.display === 'none' || cs.visibility === 'hidden') return null;
|
|
4302
|
+
var w = parseFloat(cs.width), h = parseFloat(cs.height);
|
|
4303
|
+
if (!(w > 0) || !(h > 0) || !/px$/.test(cs.width) || !/px$/.test(cs.height)) return null;
|
|
4304
|
+
var bg = cs.backgroundColor;
|
|
4305
|
+
var paints = (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') || (cs.backgroundImage && cs.backgroundImage !== 'none') || (cs.boxShadow && cs.boxShadow !== 'none');
|
|
4306
|
+
var bordered = ['Top', 'Right', 'Bottom', 'Left'].some(function (s) { return parseFloat(cs['border' + s + 'Width']) > 0 && cs['border' + s + 'Style'] !== 'none'; });
|
|
4307
|
+
if (!paints && !bordered) return null;
|
|
4308
|
+
// Border box: CSS width/height are content-box unless box-sizing says otherwise.
|
|
4309
|
+
if (cs.boxSizing !== 'border-box') {
|
|
4310
|
+
w += (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0) + (parseFloat(cs.borderLeftWidth) || 0) + (parseFloat(cs.borderRightWidth) || 0);
|
|
4311
|
+
h += (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0) + (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0);
|
|
4312
|
+
}
|
|
4313
|
+
var hcs = getComputedStyle(el);
|
|
4314
|
+
var padX = hostRect.left + (parseFloat(hcs.borderLeftWidth) || 0), padY = hostRect.top + (parseFloat(hcs.borderTopWidth) || 0);
|
|
4315
|
+
var padW = hostRect.width - (parseFloat(hcs.borderLeftWidth) || 0) - (parseFloat(hcs.borderRightWidth) || 0);
|
|
4316
|
+
var padH = hostRect.height - (parseFloat(hcs.borderTopWidth) || 0) - (parseFloat(hcs.borderBottomWidth) || 0);
|
|
4317
|
+
var x, y;
|
|
4318
|
+
if (cs.position === 'absolute' || cs.position === 'fixed') {
|
|
4319
|
+
x = /px$/.test(cs.left) ? padX + parseFloat(cs.left) : /px$/.test(cs.right) ? padX + padW - parseFloat(cs.right) - w : padX;
|
|
4320
|
+
y = /px$/.test(cs.top) ? padY + parseFloat(cs.top) : /px$/.test(cs.bottom) ? padY + padH - parseFloat(cs.bottom) - h : padY;
|
|
4321
|
+
} else {
|
|
4322
|
+
// In flow: before at the start of the content box, after at its end.
|
|
4323
|
+
var cx = padX + (parseFloat(hcs.paddingLeft) || 0), cy = padY + (parseFloat(hcs.paddingTop) || 0);
|
|
4324
|
+
x = which === 'before' ? cx : padX + padW - (parseFloat(hcs.paddingRight) || 0) - w;
|
|
4325
|
+
y = cy;
|
|
4326
|
+
}
|
|
4327
|
+
var m = /matrix\(([^)]+)\)/.exec(cs.transform || '');
|
|
4328
|
+
if (m) { var mv = m[1].split(',').map(parseFloat); x += mv[4] || 0; y += mv[5] || 0; }
|
|
4329
|
+
var style = {};
|
|
4330
|
+
for (var i = 0; i < PROPS.length; i++) style[PROPS[i]] = cs.getPropertyValue(PROPS[i]);
|
|
4331
|
+
style.width = round(w) + 'px';
|
|
4332
|
+
style.height = round(h) + 'px';
|
|
4333
|
+
var tokens = {};
|
|
4334
|
+
for (var j = 0; j < TOKENED.length; j++) {
|
|
4335
|
+
var p = TOKENED[j], v = style[p];
|
|
4336
|
+
if (!v || v === 'none' || v === 'normal' || v === 'auto' || v === 'rgba(0, 0, 0, 0)') continue;
|
|
4337
|
+
if (/width$/.test(p) && /^border-/.test(p) && v === '0px') continue;
|
|
4338
|
+
if (/^border-.*-color$/.test(p) && parseFloat(style[p.replace('color', 'width')]) === 0) continue;
|
|
4339
|
+
var t = tokenFor(el, p, v, which);
|
|
4340
|
+
if (t) tokens[p] = t;
|
|
4341
|
+
}
|
|
4342
|
+
count++;
|
|
4343
|
+
return { tag: '::' + which, kind: 'frame', pseudo: which, sized: { width: true, height: true }, classes: [], box: { x: round(x - originX), y: round(y - originY), width: round(w), height: round(h) }, style: style, tokens: tokens, children: [] };
|
|
4344
|
+
}
|
|
4345
|
+
var originX = 0, originY = 0;
|
|
4346
|
+
function node(el, depth) {
|
|
4347
|
+
count++;
|
|
4348
|
+
var cs = getComputedStyle(el);
|
|
4349
|
+
var r = el.getBoundingClientRect();
|
|
4350
|
+
var tag = el.tagName.toLowerCase();
|
|
4351
|
+
var style = {};
|
|
4352
|
+
for (var i = 0; i < PROPS.length; i++) style[PROPS[i]] = cs.getPropertyValue(PROPS[i]);
|
|
4353
|
+
var tokens = {};
|
|
4354
|
+
for (var j = 0; j < TOKENED.length; j++) {
|
|
4355
|
+
var p = TOKENED[j], v = style[p];
|
|
4356
|
+
if (!v || v === 'none' || v === 'normal' || v === 'auto' || v === 'rgba(0, 0, 0, 0)') continue;
|
|
4357
|
+
if (/width$/.test(p) && /^border-/.test(p) && v === '0px') continue;
|
|
4358
|
+
if (/^border-.*-color$/.test(p) && parseFloat(style[p.replace('color', 'width')]) === 0) continue;
|
|
4359
|
+
var t = tokenFor(el, p, v);
|
|
4360
|
+
if (t) tokens[p] = t;
|
|
4361
|
+
}
|
|
4362
|
+
// A width or height the CSS sets (not auto, a percentage or content-sized): the pull keeps it fixed.
|
|
4363
|
+
var sized = {};
|
|
4364
|
+
['width', 'height'].forEach(function (k) {
|
|
4365
|
+
var dv = declared(el, k);
|
|
4366
|
+
var v = dv ? dv.value.trim() : (el.style && el.style.getPropertyValue(k)) || '';
|
|
4367
|
+
if (v && !/^(auto|inherit|initial|unset|revert|fit-content|max-content|min-content|stretch|-webkit-fill-available)/.test(v) && !/%/.test(v)) sized[k] = true;
|
|
4368
|
+
});
|
|
4369
|
+
var n = { tag: tag, classes: Array.prototype.slice.call(el.classList || []).slice(0, 8), box: { x: round(r.left - originX), y: round(r.top - originY), width: round(r.width), height: round(r.height) }, style: style, tokens: tokens, children: [] };
|
|
4370
|
+
var role = el.getAttribute('role');
|
|
4371
|
+
if (role) n.role = role;
|
|
4372
|
+
if (sized.width || sized.height) n.sized = sized;
|
|
4373
|
+
var dataState = {};
|
|
4374
|
+
for (var ai = 0; ai < el.attributes.length; ai++) {
|
|
4375
|
+
var an = el.attributes[ai].name;
|
|
4376
|
+
if (/^(data-(state|variant|size|disabled|checked|selected|tone|appearance)|aria-(checked|pressed|disabled|selected|invalid))$/.test(an)) dataState[an] = el.attributes[ai].value;
|
|
4377
|
+
}
|
|
4378
|
+
if (Object.keys(dataState).length) n.attrs = dataState;
|
|
4379
|
+
if (tag === 'svg') {
|
|
4380
|
+
n.kind = r.width <= 48 && r.height <= 48 ? 'icon' : 'vector';
|
|
4381
|
+
var mk = svgMarkup(el, r);
|
|
4382
|
+
if (mk) { n.svg = mk.svg; n.svgStrokes = mk.strokes; }
|
|
4383
|
+
return n;
|
|
4384
|
+
}
|
|
4385
|
+
if (tag === 'img') { n.kind = 'frame'; n.media = true; return n; }
|
|
4386
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'select') {
|
|
4387
|
+
n.kind = 'frame';
|
|
4388
|
+
n.input = { type: el.type || tag, value: el.value || '', placeholder: el.getAttribute('placeholder') || '', checked: !!el.checked };
|
|
4389
|
+
}
|
|
4390
|
+
var hasEl = false;
|
|
4391
|
+
var before = pseudoNode(el, 'before', r), after = pseudoNode(el, 'after', r);
|
|
4392
|
+
if (before) { n.children.push(before); hasEl = true; }
|
|
4393
|
+
for (var c = el.firstChild; c; c = c.nextSibling) {
|
|
4394
|
+
if (count >= MAX_NODES) { n.truncated = true; break; }
|
|
4395
|
+
if (c.nodeType === 3) {
|
|
4396
|
+
var tx = c.nodeValue.replace(/\s+/g, ' ').trim();
|
|
4397
|
+
if (!tx) continue;
|
|
4398
|
+
var range = document.createRange();
|
|
4399
|
+
range.selectNodeContents(c);
|
|
4400
|
+
var tr = range.getBoundingClientRect();
|
|
4401
|
+
n.children.push({ tag: '#text', kind: 'text', text: tx, box: { x: round(tr.left - originX), y: round(tr.top - originY), width: round(tr.width), height: round(tr.height) }, style: {}, tokens: {}, children: [] });
|
|
4402
|
+
} else if (c.nodeType === 1) {
|
|
4403
|
+
var ccs = getComputedStyle(c);
|
|
4404
|
+
if (!visible(c, ccs)) continue;
|
|
4405
|
+
if (depth + 1 > MAX_DEPTH) { hasEl = true; n.truncated = true; continue; }
|
|
4406
|
+
var cn = node(c, depth + 1);
|
|
4407
|
+
// A box with no area and nothing drawn inside (a closed popover's shell) is not a layer.
|
|
4408
|
+
if (cn.kind === 'frame' && !cn.children.length && !(cn.box.width * cn.box.height) && !cn.input && !cn.media) continue;
|
|
4409
|
+
hasEl = true;
|
|
4410
|
+
n.children.push(cn);
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
if (after) { n.children.push(after); hasEl = true; }
|
|
4414
|
+
// An element holding only text is the text layer itself.
|
|
4415
|
+
if (!hasEl && n.children.length === 1 && n.children[0].kind === 'text' && !own(el, cs)) {
|
|
4416
|
+
n.kind = 'text';
|
|
4417
|
+
n.text = n.children[0].text;
|
|
4418
|
+
n.children = [];
|
|
4419
|
+
} else if (!n.kind) n.kind = 'frame';
|
|
4420
|
+
return n;
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
var host = document.querySelector(rootSel);
|
|
4424
|
+
if (!host) return { error: 'no element matches ' + rootSel + ' in the page' };
|
|
4425
|
+
// Popups portaled to the body (a menu, a dialog, a toast region): visible elements outside the story root.
|
|
4426
|
+
var portals = [];
|
|
4427
|
+
for (var b = document.body.firstElementChild; b; b = b.nextElementSibling) {
|
|
4428
|
+
if (b === probe || b.contains(host) || /^(SCRIPT|STYLE|LINK|TEMPLATE)$/.test(b.tagName)) continue;
|
|
4429
|
+
if (/sb-(wrapper|errordisplay|nopreview|preparing)|sb-show-main/.test(b.className || '')) continue;
|
|
4430
|
+
var bcs = getComputedStyle(b);
|
|
4431
|
+
if (!visible(b, bcs)) continue;
|
|
4432
|
+
// A portal container can be zero-size around its positioned popup: it counts when anything in it has a box.
|
|
4433
|
+
var br = b.getBoundingClientRect();
|
|
4434
|
+
if (br.width > 0 && br.height > 0) { portals.push(b); continue; }
|
|
4435
|
+
var inner = b.querySelectorAll('*');
|
|
4436
|
+
for (var q = 0; q < inner.length && q < 200; q++) { var ir = inner[q].getBoundingClientRect(); if (ir.width > 0 && ir.height > 0) { portals.push(b); break; } }
|
|
4437
|
+
}
|
|
4438
|
+
var storyRoot = host;
|
|
4439
|
+
// target 'portal': the component is the open popup (the newest portal), not the trigger in the story root.
|
|
4440
|
+
if (arg.target === 'portal') {
|
|
4441
|
+
if (!portals.length) { probe.remove(); return { error: 'no popup is open outside the story root' }; }
|
|
4442
|
+
host = portals[portals.length - 1];
|
|
4443
|
+
portals = portals.slice(0, -1);
|
|
4444
|
+
// A modal portal holds a backdrop beside the popup: the popup is the element with a popup role, when there is one.
|
|
4445
|
+
var roled = host.querySelector('[role="dialog"], [role="alertdialog"], [role="menu"], [role="listbox"], [role="tooltip"], [role="tree"], [role="grid"]');
|
|
4446
|
+
if (roled && visible(roled, getComputedStyle(roled))) host = roled;
|
|
4447
|
+
}
|
|
4448
|
+
// Decorators and plain wrappers: go down while an element has one child and draws nothing itself.
|
|
4449
|
+
var el = host, wrappers = 0;
|
|
4450
|
+
// A decorator canvas the size of the viewport (a theme frame with a background and padding) is a wrapper too.
|
|
4451
|
+
// So is a full-width band around one narrower child (a theme provider painting the page background).
|
|
4452
|
+
function canvas(e) {
|
|
4453
|
+
var r = e.getBoundingClientRect();
|
|
4454
|
+
if (r.width >= window.innerWidth * 0.9 && r.height >= window.innerHeight * 0.9) return true;
|
|
4455
|
+
if (r.width < window.innerWidth * 0.9) return false;
|
|
4456
|
+
var c = e.children[0].getBoundingClientRect();
|
|
4457
|
+
if (c.width < r.width * 0.9) return true;
|
|
4458
|
+
// A full-width background with no border, radius or shadow: a theme surface, not a component.
|
|
4459
|
+
var cs = getComputedStyle(e);
|
|
4460
|
+
var noBorder = ['Top', 'Right', 'Bottom', 'Left'].every(function (x) { return !(parseFloat(cs['border' + x + 'Width']) > 0) || cs['border' + x + 'Style'] === 'none'; });
|
|
4461
|
+
return noBorder && !(parseFloat(cs.borderTopLeftRadius) > 0) && (!cs.boxShadow || cs.boxShadow === 'none');
|
|
4462
|
+
}
|
|
4463
|
+
while (arg.unwrap !== false && el.children.length === 1 && !directText(el) && (!own(el, getComputedStyle(el)) || canvas(el)) && el.children[0].tagName.toLowerCase() !== 'svg') {
|
|
4464
|
+
var only = el.children[0];
|
|
4465
|
+
var ocs = getComputedStyle(only);
|
|
4466
|
+
if (!visible(only, ocs)) break;
|
|
4467
|
+
el = only;
|
|
4468
|
+
wrappers++;
|
|
4469
|
+
}
|
|
4470
|
+
// within: a part that only renders inside its parent or a popup (a menu item, an accordion item, a toast) is measured
|
|
4471
|
+
// alone: the first visible match in the component, then in the popups.
|
|
4472
|
+
if (arg.within) {
|
|
4473
|
+
var pool = [el].concat(portals), hit = null;
|
|
4474
|
+
for (var wi = 0; wi < pool.length && !hit; wi++) {
|
|
4475
|
+
var cands = [];
|
|
4476
|
+
try { if (pool[wi].matches(arg.within)) cands.push(pool[wi]); cands = cands.concat(Array.prototype.slice.call(pool[wi].querySelectorAll(arg.within))); } catch (e) { probe.remove(); return { error: 'not a CSS selector: ' + arg.within }; }
|
|
4477
|
+
for (var ci = 0; ci < cands.length && !hit; ci++) if (visible(cands[ci], getComputedStyle(cands[ci])) && cands[ci].getBoundingClientRect().width > 0) hit = cands[ci];
|
|
4478
|
+
}
|
|
4479
|
+
if (!hit) { probe.remove(); return { error: 'no element matches ' + arg.within + ' in the story or its popups' }; }
|
|
4480
|
+
portals = portals.filter(function (p) { return !p.contains(hit); });
|
|
4481
|
+
el = hit;
|
|
4482
|
+
}
|
|
4483
|
+
// mark: tag the component element (for a forced :hover / :focus-visible from the browser driver) and stop.
|
|
4484
|
+
if (arg.mark) {
|
|
4485
|
+
var prev = document.querySelectorAll('[data-bridge-measure-root]');
|
|
4486
|
+
for (var mi = 0; mi < prev.length; mi++) prev[mi].removeAttribute('data-bridge-measure-root');
|
|
4487
|
+
el.setAttribute('data-bridge-measure-root', '');
|
|
4488
|
+
probe.remove();
|
|
4489
|
+
return { marked: true };
|
|
4490
|
+
}
|
|
4491
|
+
scopeEl = el;
|
|
4492
|
+
var hr = el.getBoundingClientRect();
|
|
4493
|
+
// Fill or hug: a block-level root that spans its container's content box (or is declared width: 100%) fills it.
|
|
4494
|
+
var rootFill = false;
|
|
4495
|
+
(function () {
|
|
4496
|
+
var pe = el.parentElement;
|
|
4497
|
+
var ecs = getComputedStyle(el);
|
|
4498
|
+
var inner = window.innerWidth;
|
|
4499
|
+
if (pe) {
|
|
4500
|
+
var pcs = getComputedStyle(pe);
|
|
4501
|
+
inner = pe.getBoundingClientRect().width - (parseFloat(pcs.paddingLeft) || 0) - (parseFloat(pcs.paddingRight) || 0) - (parseFloat(pcs.borderLeftWidth) || 0) - (parseFloat(pcs.borderRightWidth) || 0);
|
|
4502
|
+
}
|
|
4503
|
+
var dw = declared(el, 'width');
|
|
4504
|
+
var full = (dw && /^100%$/.test(dw.value.trim())) || (el.style && el.style.width === '100%');
|
|
4505
|
+
var blockish = /^(block|flex|grid|table|list-item|flow-root)$/.test(ecs.display);
|
|
4506
|
+
rootFill = !!full || (inner > 0 && Math.abs(hr.width - inner) <= 1 && (blockish || hr.width >= window.innerWidth * 0.5));
|
|
4507
|
+
})();
|
|
4508
|
+
originX = hr.left; originY = hr.top;
|
|
4509
|
+
var tree = arg.unwrap !== false && el === storyRoot && !storyRoot.children.length && !directText(storyRoot) ? null : node(el, 0);
|
|
4510
|
+
var portalTrees = [];
|
|
4511
|
+
for (var pi = 0; pi < portals.length && pi < 3; pi++) portalTrees.push(node(portals[pi], 0));
|
|
4512
|
+
probe.remove();
|
|
4513
|
+
var rt = rootVars || { count: 0 };
|
|
4514
|
+
return {
|
|
4515
|
+
root: tree,
|
|
4516
|
+
portals: portalTrees,
|
|
4517
|
+
wrappers: wrappers,
|
|
4518
|
+
nodes: count,
|
|
4519
|
+
rules: rules.length,
|
|
4520
|
+
sheets: { read: sheetsRead, blocked: sheetsBlocked },
|
|
4521
|
+
rootFill: rootFill,
|
|
4522
|
+
rootVariables: rt.count,
|
|
4523
|
+
scopedVariables: rt.scoped || 0,
|
|
4524
|
+
viewport: { width: window.innerWidth, height: window.innerHeight },
|
|
4525
|
+
error: document.body.classList.contains('sb-show-errordisplay') ? (document.querySelector('#error-message') || {}).textContent || 'the story threw' : undefined
|
|
4526
|
+
};
|
|
4527
|
+
})`;
|
|
4528
|
+
const TOKENS_SCRIPT = String.raw`(function (arg) {
|
|
4529
|
+
arg = arg || {};
|
|
4530
|
+
var rootSel = arg.root || '#storybook-root, #root';
|
|
4531
|
+
var host = document.querySelector(rootSel) || document.body;
|
|
4532
|
+
var at = host.firstElementChild || host;
|
|
4533
|
+
var decls = {};
|
|
4534
|
+
var order = 0;
|
|
4535
|
+
// Every var() use: the color function around it (rgb, hsl...), or a bare use; and the properties that alias it.
|
|
4536
|
+
var COLOR_FN = /^(rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)$/i;
|
|
4537
|
+
var useFn = {}, useBare = {}, aliasUses = {};
|
|
4538
|
+
function enclosing(s, pos) {
|
|
4539
|
+
for (var i = pos - 1, depth = 0; i >= 0; i--) {
|
|
4540
|
+
if (s[i] === ')') depth++;
|
|
4541
|
+
else if (s[i] === '(') {
|
|
4542
|
+
if (depth) { depth--; continue; }
|
|
4543
|
+
var j = i;
|
|
4544
|
+
while (j > 0 && /[\w-]/.test(s[j - 1])) j--;
|
|
4545
|
+
var fn = s.slice(j, i).toLowerCase();
|
|
4546
|
+
// A fallback (var(--a, var(--b))): the function around the outer var.
|
|
4547
|
+
if (fn !== 'var') return fn;
|
|
4548
|
+
}
|
|
4549
|
+
}
|
|
4550
|
+
return '';
|
|
4551
|
+
}
|
|
4552
|
+
function scanDecl(d) {
|
|
4553
|
+
var c = d.indexOf(':');
|
|
4554
|
+
if (c < 0) return;
|
|
4555
|
+
var prop = d.slice(0, c).trim(), val = d.slice(c + 1).replace(/!important\s*$/, '').trim();
|
|
4556
|
+
var alias = /^var\(\s*(--[\w-]+)\s*\)$/.exec(val);
|
|
4557
|
+
if (alias && prop.indexOf('--') === 0) { (aliasUses[alias[1]] = aliasUses[alias[1]] || []).push(prop); return; }
|
|
4558
|
+
var re = /var\(\s*(--[\w-]+)/g, m;
|
|
4559
|
+
while ((m = re.exec(val))) {
|
|
4560
|
+
var fn = enclosing(val, m.index);
|
|
4561
|
+
if (COLOR_FN.test(fn)) (useFn[m[1]] = useFn[m[1]] || {})[fn === 'rgba' || fn === 'hsla' ? fn.slice(0, 3) : fn] = 1;
|
|
4562
|
+
else useBare[m[1]] = 1;
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4565
|
+
function scanUses(text) {
|
|
4566
|
+
for (var i = 0, depth = 0, start = 0; i <= text.length; i++) {
|
|
4567
|
+
var ch = text[i];
|
|
4568
|
+
if (ch === '(') depth++;
|
|
4569
|
+
else if (ch === ')') depth--;
|
|
4570
|
+
else if (i === text.length || (ch === ';' && depth <= 0)) { scanDecl(text.slice(start, i)); start = i + 1; depth = 0; }
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
// The one color function every use of a property wraps it in, through the properties that alias it: '' unused, null
|
|
4574
|
+
// when a use is bare or two functions disagree.
|
|
4575
|
+
function channelFn(name, seen) {
|
|
4576
|
+
if (seen[name]) return '';
|
|
4577
|
+
seen[name] = 1;
|
|
4578
|
+
if (useBare[name]) return null;
|
|
4579
|
+
var fns = {};
|
|
4580
|
+
for (var f in useFn[name] || {}) fns[f] = 1;
|
|
4581
|
+
var al = aliasUses[name] || [];
|
|
4582
|
+
for (var i = 0; i < al.length; i++) {
|
|
4583
|
+
var g = channelFn(al[i], seen);
|
|
4584
|
+
if (g === null) return null;
|
|
4585
|
+
if (g) fns[g] = 1;
|
|
4586
|
+
}
|
|
4587
|
+
var k = Object.keys(fns);
|
|
4588
|
+
return k.length === 1 ? k[0] : k.length ? null : '';
|
|
4589
|
+
}
|
|
4590
|
+
function add(sel, style) {
|
|
4591
|
+
try { scanUses(style.cssText || ''); } catch (e) {}
|
|
4592
|
+
for (var k = 0; k < style.length; k++) {
|
|
4593
|
+
var n = style[k];
|
|
4594
|
+
if (n.indexOf('--') !== 0 || n.indexOf('--_') === 0 || n.indexOf('--sb-') === 0) continue;
|
|
4595
|
+
(decls[n] = decls[n] || []).push({ sel: sel, raw: style.getPropertyValue(n).trim(), order: order++ });
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
function walk(list) {
|
|
4599
|
+
for (var i = 0; i < list.length; i++) {
|
|
4600
|
+
var r = list[i];
|
|
4601
|
+
try {
|
|
4602
|
+
if (r.selectorText !== undefined && r.style) {
|
|
4603
|
+
add(r.selectorText, r.style);
|
|
4604
|
+
if (r.cssRules && r.cssRules.length) walk(r.cssRules);
|
|
4605
|
+
} else if (r.media !== undefined && r.cssRules) {
|
|
4606
|
+
if (window.matchMedia(r.media.mediaText || 'all').matches) walk(r.cssRules);
|
|
4607
|
+
} else if (r.cssRules) walk(r.cssRules);
|
|
4608
|
+
} catch (e) {}
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
var blocked = 0;
|
|
4612
|
+
for (var s = 0; s < document.styleSheets.length; s++) {
|
|
4613
|
+
try { walk(document.styleSheets[s].cssRules); } catch (e) { blocked++; }
|
|
4614
|
+
}
|
|
4615
|
+
try { for (var a = 0; a < (document.adoptedStyleSheets || []).length; a++) walk(document.adoptedStyleSheets[a].cssRules); } catch (e) {}
|
|
4616
|
+
// Inline styles on the story's ancestors (a provider that sets variables in style="").
|
|
4617
|
+
for (var up = at; up && up.nodeType === 1; up = up.parentElement) if (up.style && up.style.length) add('[style]', up.style);
|
|
4618
|
+
// Inline styles in the story use variables too.
|
|
4619
|
+
var inline = host.querySelectorAll('[style]');
|
|
4620
|
+
for (var q = 0; q < inline.length; q++) try { scanUses(inline[q].style.cssText || ''); } catch (e) {}
|
|
4621
|
+
|
|
4622
|
+
function specificity(sel) {
|
|
4623
|
+
var x = sel.replace(/:where\([^)]*\)/g, '');
|
|
4624
|
+
var ids = (x.match(/#[\w-]+/g) || []).length;
|
|
4625
|
+
var cls = (x.match(/\.[\w-]+|\[[^\]]*\]|:(?!not\b|is\b|has\b|root\b)[\w-]+(\([^)]*\))?/g) || []).length + (x.match(/:root/g) || []).length;
|
|
4626
|
+
var types = (x.replace(/\[[^\]]*\]|\([^)]*\)/g, '').match(/(^|[\s>+~(])[a-zA-Z][\w-]*/g) || []).length;
|
|
4627
|
+
return ids * 10000 + cls * 100 + types;
|
|
4628
|
+
}
|
|
4629
|
+
function matchSpec(el, selText) {
|
|
4630
|
+
var best = -1, parts = selText.split(/,(?![^(]*\))/);
|
|
4631
|
+
for (var i = 0; i < parts.length; i++) {
|
|
4632
|
+
var p = parts[i].trim();
|
|
4633
|
+
if (!p || /::/.test(p)) continue;
|
|
4634
|
+
try { if (el.matches(p)) best = Math.max(best, specificity(p)); } catch (e) {}
|
|
4635
|
+
}
|
|
4636
|
+
return best;
|
|
4637
|
+
}
|
|
4638
|
+
// The declaration that applies at the story: the nearest element up from it with a matching rule, then specificity
|
|
4639
|
+
// and order; inline style wins at its element.
|
|
4640
|
+
function winning(name) {
|
|
4641
|
+
var list = decls[name];
|
|
4642
|
+
for (var el = at; el && el.nodeType === 1; el = el.parentElement) {
|
|
4643
|
+
var best = null, bestRank = null;
|
|
4644
|
+
if (el.style && el.style.getPropertyValue(name)) return { sel: '[style]', raw: el.style.getPropertyValue(name).trim() };
|
|
4645
|
+
for (var i = 0; i < list.length; i++) {
|
|
4646
|
+
if (list[i].sel === '[style]') continue;
|
|
4647
|
+
var sp = matchSpec(el, list[i].sel);
|
|
4648
|
+
if (sp < 0) continue;
|
|
4649
|
+
if (!best || sp > bestRank[0] || (sp === bestRank[0] && list[i].order > bestRank[1])) { best = list[i]; bestRank = [sp, list[i].order]; }
|
|
4650
|
+
}
|
|
4651
|
+
if (best) return best;
|
|
4652
|
+
}
|
|
4653
|
+
return null;
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
var probe = document.createElement('div');
|
|
4657
|
+
probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none;width:0;height:0';
|
|
4658
|
+
(at.parentElement || document.body).appendChild(probe);
|
|
4659
|
+
function norm(v) {
|
|
4660
|
+
if (!v) return { type: 'string', value: '' };
|
|
4661
|
+
probe.style.color = '';
|
|
4662
|
+
probe.style.color = v;
|
|
4663
|
+
if (probe.style.color) return { type: 'color', value: getComputedStyle(probe).color };
|
|
4664
|
+
if (/^-?[\d.]+$/.test(v)) return { type: 'number', value: Number(v) };
|
|
4665
|
+
probe.style.width = '';
|
|
4666
|
+
probe.style.width = v;
|
|
4667
|
+
if (probe.style.width && !/auto|%/.test(v)) {
|
|
4668
|
+
var w = getComputedStyle(probe).width;
|
|
4669
|
+
if (/px$/.test(w)) return { type: 'length', value: Math.round(parseFloat(w) * 100) / 100 };
|
|
4670
|
+
}
|
|
4671
|
+
return { type: 'string', value: v };
|
|
4672
|
+
}
|
|
4673
|
+
var cs = getComputedStyle(at), rootCs = getComputedStyle(document.documentElement);
|
|
4674
|
+
var out = [];
|
|
4675
|
+
var ROOTISH = /^(:root|html|:host|body|\*)(\s*,\s*(:root|html|:host|body|\*))*$/;
|
|
4676
|
+
for (var name in decls) {
|
|
4677
|
+
var w = winning(name);
|
|
4678
|
+
var resolved = cs.getPropertyValue(name).trim() || rootCs.getPropertyValue(name).trim();
|
|
4679
|
+
var r = norm(resolved);
|
|
4680
|
+
var fn = r.type === 'string' && resolved ? channelFn(name, {}) : '';
|
|
4681
|
+
if (fn) {
|
|
4682
|
+
probe.style.color = '';
|
|
4683
|
+
probe.style.color = fn + '(' + resolved + ')';
|
|
4684
|
+
if (probe.style.color) r = { type: 'color', value: getComputedStyle(probe).color };
|
|
4685
|
+
}
|
|
4686
|
+
var scopes = [];
|
|
4687
|
+
for (var j = 0; j < decls[name].length && scopes.length < 6; j++) {
|
|
4688
|
+
var sel = decls[name][j].sel;
|
|
4689
|
+
if (!ROOTISH.test(sel.trim()) && scopes.indexOf(sel) < 0) scopes.push(sel.length > 120 ? sel.slice(0, 120) : sel);
|
|
4690
|
+
}
|
|
4691
|
+
out.push({ name: name, raw: w ? w.raw : decls[name][0].raw, applies: !!w, type: r.type, value: r.value, scopes: scopes });
|
|
4692
|
+
}
|
|
4693
|
+
probe.remove();
|
|
4694
|
+
return { properties: out, blocked: blocked };
|
|
4695
|
+
})`;
|
|
4696
|
+
const GLOBALS_SCRIPT = String.raw`(function () {
|
|
4697
|
+
var p = window.__STORYBOOK_PREVIEW__;
|
|
4698
|
+
if (!p) return null;
|
|
4699
|
+
var store = p.storyStoreValue || {};
|
|
4700
|
+
var ann = store.projectAnnotations || p.projectAnnotations || {};
|
|
4701
|
+
var types = ann.globalTypes || (store.globals && store.globals.globalTypes) || {};
|
|
4702
|
+
var current = (store.userGlobals && store.userGlobals.get && store.userGlobals.get()) || (store.globals && store.globals.get && store.globals.get()) || ann.initialGlobals || ann.globals || {};
|
|
4703
|
+
var out = [];
|
|
4704
|
+
for (var k in types) {
|
|
4705
|
+
var t = types[k] || {};
|
|
4706
|
+
var items = (t.toolbar && t.toolbar.items) || t.options || [];
|
|
4707
|
+
var values = [];
|
|
4708
|
+
for (var i = 0; i < items.length; i++) {
|
|
4709
|
+
var it = items[i];
|
|
4710
|
+
var v = typeof it === 'string' ? it : it && (it.value !== undefined ? it.value : it.title);
|
|
4711
|
+
if (typeof v === 'string' && v && values.indexOf(v) < 0) values.push(v);
|
|
4712
|
+
}
|
|
4713
|
+
if (values.length < 2 || values.length > 12) continue;
|
|
4714
|
+
var def = current[k] !== undefined ? String(current[k]) : (t.defaultValue !== undefined ? String(t.defaultValue) : values[0]);
|
|
4715
|
+
out.push({ global: k, values: values, default: def });
|
|
4716
|
+
}
|
|
4717
|
+
return out;
|
|
4718
|
+
})()`;
|
|
4719
|
+
async function markMeasuredRoot(page, o = {}) {
|
|
4720
|
+
const arg = { root: o.root ?? "#storybook-root, #root", unwrap: o.unwrap, within: o.within, target: o.target ?? (o.open && !o.within ? "portal" : void 0), mark: true };
|
|
4721
|
+
const r = await page.evaluate(`(${MEASURE_SCRIPT})(${JSON.stringify(arg)})`).catch(() => null);
|
|
4722
|
+
return !!r?.marked;
|
|
4723
|
+
}
|
|
4724
|
+
const WAIT_SCRIPT = (rootSel, timeout, self = false) => `(async () => {
|
|
4725
|
+
const t0 = performance.now();
|
|
4726
|
+
const frame = () => new Promise((r) => requestAnimationFrame(() => r(null)));
|
|
4727
|
+
const host = () => document.querySelector(${JSON.stringify(rootSel)});
|
|
4728
|
+
let state = 'timeout';
|
|
4729
|
+
while (performance.now() - t0 < ${timeout}) {
|
|
4730
|
+
if (document.body && document.body.classList.contains('sb-show-errordisplay')) { state = 'error'; break; }
|
|
4731
|
+
const h = host();
|
|
4732
|
+
if (h && (${self} || h.children.length || (h.textContent || '').trim())) { state = 'rendered'; break; }
|
|
4733
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
4734
|
+
}
|
|
4735
|
+
try { await Promise.race([document.fonts.ready, new Promise((r) => setTimeout(r, 3000))]); } catch (e) {}
|
|
4736
|
+
// Settle briefly: the markup stops changing for a few frames, or 1.5 s passes (a spinner never stops).
|
|
4737
|
+
let last = '', same = 0;
|
|
4738
|
+
const settle0 = performance.now();
|
|
4739
|
+
while (state === 'rendered' && same < 3 && performance.now() - settle0 < 1500) {
|
|
4740
|
+
await frame();
|
|
4741
|
+
await new Promise((r) => setTimeout(r, 60));
|
|
4742
|
+
const s = document.body.innerHTML.length + ':' + document.querySelectorAll('*').length;
|
|
4743
|
+
same = s === last ? same + 1 : 0;
|
|
4744
|
+
last = s;
|
|
4745
|
+
}
|
|
4746
|
+
// Animations: finished ones jump to their end, endless ones (a loading spinner) are paused where they are.
|
|
4747
|
+
try { (document.getAnimations ? document.getAnimations() : []).forEach((a) => { try { a.finish(); } catch (e) { a.pause(); } }); } catch (e) {}
|
|
4748
|
+
return state;
|
|
4749
|
+
})()`;
|
|
4750
|
+
const OPEN_SCRIPT = (rootSel) => `(async () => {
|
|
4751
|
+
const root = document.querySelector(${JSON.stringify(rootSel)});
|
|
4752
|
+
if (!root) return 'none';
|
|
4753
|
+
const shown = () => Array.prototype.filter.call(document.body.children, (b) => {
|
|
4754
|
+
if (b.contains(root) || /^(SCRIPT|STYLE|LINK|TEMPLATE)$/.test(b.tagName) || /sb-/.test(String(b.className || ''))) return false;
|
|
4755
|
+
const cs = getComputedStyle(b), r = b.getBoundingClientRect();
|
|
4756
|
+
if (cs.display === 'none' || cs.visibility === 'hidden') return false;
|
|
4757
|
+
return r.width > 0 && r.height > 0 || Array.prototype.some.call(b.querySelectorAll('*'), (c) => { const x = c.getBoundingClientRect(); return x.width > 0 && x.height > 0; });
|
|
4758
|
+
}).length;
|
|
4759
|
+
const settle = async () => {
|
|
4760
|
+
for (let i = 0; i < 20; i++) {
|
|
4761
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
4762
|
+
const running = (document.getAnimations ? document.getAnimations() : []).filter((a) => a.playState === 'running');
|
|
4763
|
+
if (!running.length) break;
|
|
4764
|
+
await Promise.race([Promise.all(running.map((a) => a.finished.catch(() => null))), new Promise((r) => setTimeout(r, 1500))]);
|
|
4765
|
+
}
|
|
4766
|
+
};
|
|
4767
|
+
if (shown()) { await settle(); return 'already'; }
|
|
4768
|
+
const trigger = root.querySelector('[aria-haspopup]:not([aria-expanded="true"]), [aria-expanded="false"]') || root.querySelector('button, [role="button"], [role="combobox"], a[href], [tabindex="0"]');
|
|
4769
|
+
if (!trigger) return 'none';
|
|
4770
|
+
const wait = async (ms) => { const t0 = performance.now(); while (performance.now() - t0 < ms) { if (shown()) { await settle(); return true; } await new Promise((r) => setTimeout(r, 50)); } return false; };
|
|
4771
|
+
const r = trigger.getBoundingClientRect();
|
|
4772
|
+
const at = { bubbles: true, cancelable: true, composed: true, clientX: r.left + r.width / 2, clientY: r.top + r.height / 2, button: 0, pointerId: 1, pointerType: 'mouse', isPrimary: true };
|
|
4773
|
+
const fire = (type, Ctor) => trigger.dispatchEvent(new Ctor(type, type === 'pointerdown' || type === 'mousedown' ? { ...at, buttons: 1 } : at));
|
|
4774
|
+
fire('pointerdown', PointerEvent); fire('mousedown', MouseEvent); fire('pointerup', PointerEvent); fire('mouseup', MouseEvent); fire('click', MouseEvent);
|
|
4775
|
+
if (await wait(800)) return 'click';
|
|
4776
|
+
fire('pointerover', PointerEvent); fire('pointerenter', PointerEvent); fire('mouseover', MouseEvent); fire('mouseenter', MouseEvent); fire('pointermove', PointerEvent); fire('mousemove', MouseEvent);
|
|
4777
|
+
if (await wait(1200)) return 'hover';
|
|
4778
|
+
try { trigger.focus(); } catch (e) {}
|
|
4779
|
+
if (await wait(800)) return 'focus';
|
|
4780
|
+
return 'none';
|
|
4781
|
+
})()`;
|
|
4782
|
+
const PROPS_SCRIPT = (id) => `(async () => {
|
|
4783
|
+
const p = window.__STORYBOOK_PREVIEW__;
|
|
4784
|
+
if (!p) return null;
|
|
4785
|
+
const want = ${JSON.stringify(id ?? null)};
|
|
4786
|
+
let story = p.currentRender && p.currentRender.story;
|
|
4787
|
+
if (want && (!story || story.id !== want)) { try { story = await p.storyStoreValue.loadStory({ storyId: want }); } catch (e) { story = story || null; } }
|
|
4788
|
+
if (!story) return null;
|
|
4789
|
+
const plain = (v) => ['string', 'number', 'boolean'].includes(typeof v);
|
|
4790
|
+
const clean = (o) => { const out = {}; for (const k in o || {}) if (plain(o[k])) out[k] = o[k]; return out; };
|
|
4791
|
+
let live;
|
|
4792
|
+
try { live = p.storyStoreValue && p.storyStoreValue.args && p.storyStoreValue.args.get(story.id); } catch (e) {}
|
|
4793
|
+
const args = clean(live || story.initialArgs);
|
|
4794
|
+
const lit = (v) => {
|
|
4795
|
+
if (v === undefined || v === null) return undefined;
|
|
4796
|
+
if (typeof v !== 'string') return plain(v) ? v : undefined;
|
|
4797
|
+
const t = v.trim();
|
|
4798
|
+
if (t === 'true' || t === 'false') return t === 'true';
|
|
4799
|
+
if (/^-?\\d+(\\.\\d+)?$/.test(t)) return Number(t);
|
|
4800
|
+
const q = /^(['"\`])(.*)\\1$/.exec(t);
|
|
4801
|
+
return q ? q[2] : undefined;
|
|
4802
|
+
};
|
|
4803
|
+
const argTypes = {}, defaults = {};
|
|
4804
|
+
for (const name in story.argTypes || {}) {
|
|
4805
|
+
const a = story.argTypes[name] || {};
|
|
4806
|
+
if (a.table && a.table.disable) continue;
|
|
4807
|
+
const t = a.type || {};
|
|
4808
|
+
const tn = typeof t === 'string' ? t : t.name;
|
|
4809
|
+
let options = Array.isArray(a.options) ? a.options : tn === 'enum' && Array.isArray(t.value) ? t.value : undefined;
|
|
4810
|
+
if (!options && tn === 'union' && Array.isArray(t.value) && t.value.every((x) => x && x.name === 'literal')) options = t.value.map((x) => x.value);
|
|
4811
|
+
if (options) options = options.filter(plain).map((x) => String(x).replace(/^(['"])(.*)\\1$/, '$2'));
|
|
4812
|
+
const control = a.control && typeof a.control === 'object' ? a.control.type : typeof a.control === 'string' ? a.control : undefined;
|
|
4813
|
+
const kind = options && options.length ? 'enum' : tn === 'boolean' || control === 'boolean' ? 'boolean' : tn === 'string' || control === 'text' ? 'text' : tn === 'number' || control === 'number' || control === 'range' ? 'number' : 'other';
|
|
4814
|
+
const d = lit(a.defaultValue !== undefined ? a.defaultValue : a.table && a.table.defaultValue && a.table.defaultValue.summary);
|
|
4815
|
+
argTypes[name] = { kind };
|
|
4816
|
+
if (options && options.length) argTypes[name].options = options;
|
|
4817
|
+
if (d !== undefined) { argTypes[name].default = d; defaults[name] = d; }
|
|
4818
|
+
if (control) argTypes[name].control = control;
|
|
4819
|
+
}
|
|
4820
|
+
const c = story.component;
|
|
4821
|
+
const component = c && (c.displayName || c.name) || undefined;
|
|
4822
|
+
return { props: Object.assign({}, defaults, args), args, argTypes, component };
|
|
4823
|
+
})()`;
|
|
4824
|
+
async function resolveTokenValues(page, vars) {
|
|
4825
|
+
const expr = `(() => {
|
|
4826
|
+
const vars = ${JSON.stringify(vars)};
|
|
4827
|
+
const el = document.querySelector('[data-bridge-measure-root]') || document.querySelector('#storybook-root > *, #root > *') || document.documentElement;
|
|
4828
|
+
const cs = getComputedStyle(el);
|
|
4829
|
+
const probe = document.createElement('div');
|
|
4830
|
+
probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none';
|
|
4831
|
+
(el.parentElement || document.body).appendChild(probe);
|
|
4832
|
+
const out = {};
|
|
4833
|
+
for (const path in vars) {
|
|
4834
|
+
const raw = cs.getPropertyValue(vars[path]).trim();
|
|
4835
|
+
if (!raw) continue;
|
|
4836
|
+
probe.style.color = ''; probe.style.width = '';
|
|
4837
|
+
probe.style.color = raw;
|
|
4838
|
+
if (probe.style.color) { out[path] = getComputedStyle(probe).color; continue; }
|
|
4839
|
+
probe.style.width = raw;
|
|
4840
|
+
out[path] = probe.style.width ? getComputedStyle(probe).width : raw;
|
|
4841
|
+
}
|
|
4842
|
+
probe.remove();
|
|
4843
|
+
return out;
|
|
4844
|
+
})()`;
|
|
4845
|
+
return await page.evaluate(expr) ?? {};
|
|
4846
|
+
}
|
|
4847
|
+
const STATE_TARGETS = "[data-bridge-measure-root], [data-bridge-measure-root] *";
|
|
4848
|
+
const PSEUDO_CLASSES = { hover: ["hover"], "focus-visible": ["focus-visible", "focus"], active: ["active", "hover"] };
|
|
4849
|
+
const MODE_GLOBAL = /theme|scheme|mode|brand|density|appearance/i;
|
|
4850
|
+
const ALIAS = /^var\(\s*(--[\w-]+)\s*(?:,[^)]*)?\)$/;
|
|
4851
|
+
async function harvestTokens(page, storybook, story, o = {}) {
|
|
4852
|
+
const timeout = o.timeout ?? 15e3;
|
|
4853
|
+
const read = async (globals) => {
|
|
4854
|
+
const iframe = { ...o.iframe ?? {}, globals: { ...o.iframe?.globals ?? {}, ...globals } };
|
|
4855
|
+
await page.goto(storybookIframeUrl(storybook, story, iframe), { waitUntil: "domcontentloaded", timeout: timeout + 15e3 });
|
|
4856
|
+
await page.evaluate(WAIT_SCRIPT("#storybook-root, #root", timeout));
|
|
4857
|
+
const r = await page.evaluate(`(${TOKENS_SCRIPT})({})`);
|
|
4858
|
+
return withSrgbColors(r?.properties ?? []);
|
|
4859
|
+
};
|
|
4860
|
+
const base = await read({});
|
|
4861
|
+
let moved = false;
|
|
4862
|
+
const readWithAttribute = async (attr, value) => {
|
|
4863
|
+
if (moved) {
|
|
4864
|
+
await read({});
|
|
4865
|
+
moved = false;
|
|
4866
|
+
}
|
|
4867
|
+
await page.evaluate(`(async () => { const els = document.querySelectorAll('[${attr}]'); (els.length ? Array.from(els) : [document.documentElement]).forEach((e) => e.setAttribute('${attr}', ${JSON.stringify(value)})); await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); })()`);
|
|
4868
|
+
const r = await page.evaluate(`(${TOKENS_SCRIPT})({})`);
|
|
4869
|
+
return withSrgbColors(r?.properties ?? []);
|
|
4870
|
+
};
|
|
4871
|
+
const found = o.modes === false ? [] : await page.evaluate(GLOBALS_SCRIPT).catch(() => null) ?? [];
|
|
4872
|
+
const modes = found.filter((m) => MODE_GLOBAL.test(m.global)).map((m) => ({ ...m, values: [m.default, ...m.values.filter((v) => v !== m.default)].filter((v) => !/^(all|side-?by-?side|stacked|both|none)$/i.test(v)) })).filter((m) => m.values.length >= 2);
|
|
4873
|
+
if (o.modes !== false && !modes.some((m) => /theme|scheme|mode/i.test(m.global))) {
|
|
4874
|
+
const attrs = /* @__PURE__ */ new Map();
|
|
4875
|
+
for (const p of base)
|
|
4876
|
+
for (const sel of p.scopes)
|
|
4877
|
+
for (const part of sel.split(","))
|
|
4878
|
+
for (const m of part.trim().matchAll(/^(?::root|html|body)?\[([\w-]+)=["']?([\w-]+)["']?\]$/g)) {
|
|
4879
|
+
const vals = attrs.get(m[1]) ?? /* @__PURE__ */ new Map();
|
|
4880
|
+
vals.set(m[2], (vals.get(m[2]) ?? 0) + 1);
|
|
4881
|
+
attrs.set(m[1], vals);
|
|
4882
|
+
}
|
|
4883
|
+
for (const [attr, vals] of attrs) {
|
|
4884
|
+
const values = [...vals.entries()].filter(([, n]) => n >= 10).map(([v]) => v);
|
|
4885
|
+
if (values.length < 2 || values.length > 12 || !MODE_GLOBAL.test(attr)) continue;
|
|
4886
|
+
const current = await page.evaluate(`(() => { const e = document.querySelector('[${attr}]'); return e && e.getAttribute('${attr}'); })()`).catch(() => null);
|
|
4887
|
+
const def = current ?? values[0];
|
|
4888
|
+
modes.push({ global: attr, attribute: true, values: [def, ...values.filter((v) => v !== def)], default: def });
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
const prefix = sharedTokenPrefix(base.map((p) => p.name));
|
|
4892
|
+
const props = base.map((p) => {
|
|
4893
|
+
const alias = ALIAS.exec(p.raw)?.[1];
|
|
4894
|
+
const kind = alias ? "alias" : /var\(/.test(p.raw) ? "expression" : "literal";
|
|
4895
|
+
return {
|
|
4896
|
+
name: p.name,
|
|
4897
|
+
path: tokenVariablePath(p.name, prefix),
|
|
4898
|
+
tier: alias ? "semantic" : "primitive",
|
|
4899
|
+
kind,
|
|
4900
|
+
type: p.type,
|
|
4901
|
+
raw: p.raw,
|
|
4902
|
+
...alias ? { aliasOf: alias } : {},
|
|
4903
|
+
value: p.value,
|
|
4904
|
+
...p.scopes.length ? { scopes: p.scopes } : {}
|
|
4905
|
+
};
|
|
4906
|
+
});
|
|
4907
|
+
const byName = new Map(props.map((p) => [p.name, p]));
|
|
4908
|
+
for (const m of modes) {
|
|
4909
|
+
for (const value of m.values) {
|
|
4910
|
+
const key = `${m.global}:${value}`;
|
|
4911
|
+
const rows = value === m.default ? base : m.attribute ? await readWithAttribute(m.global, value) : (moved = true, await read({ [m.global]: value }));
|
|
4912
|
+
for (const r of rows) {
|
|
4913
|
+
const p = byName.get(r.name);
|
|
4914
|
+
if (!p) continue;
|
|
4915
|
+
(p.values ??= {})[key] = r.value;
|
|
4916
|
+
const alias = ALIAS.exec(r.raw)?.[1];
|
|
4917
|
+
if (p.tier === "semantic" && alias && alias !== p.aliasOf) (p.aliasOfByMode ??= {})[key] = alias;
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
}
|
|
4921
|
+
for (const p of props) {
|
|
4922
|
+
for (const m of modes) {
|
|
4923
|
+
const keys = m.values.map((v) => `${m.global}:${v}`);
|
|
4924
|
+
if (new Set(keys.map((k) => JSON.stringify(p.values?.[k]))).size <= 1) for (const k of keys) delete p.values?.[k];
|
|
4925
|
+
}
|
|
4926
|
+
if (p.values && !Object.keys(p.values).length) delete p.values;
|
|
4927
|
+
}
|
|
4928
|
+
const live = modes.filter((m) => props.some((p) => p.values && `${m.global}:${m.default}` in p.values));
|
|
4929
|
+
if (live.length !== modes.length) {
|
|
4930
|
+
const dead = new Set(modes.filter((m) => !live.includes(m)).map((m) => m.global));
|
|
4931
|
+
for (const p of props) {
|
|
4932
|
+
for (const k of Object.keys(p.values ?? {})) if (dead.has(k.split(":")[0])) delete p.values[k];
|
|
4933
|
+
for (const k of Object.keys(p.aliasOfByMode ?? {})) if (dead.has(k.split(":")[0])) delete p.aliasOfByMode[k];
|
|
4934
|
+
if (p.values && !Object.keys(p.values).length) delete p.values;
|
|
4935
|
+
if (p.aliasOfByMode && !Object.keys(p.aliasOfByMode).length) delete p.aliasOfByMode;
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
const keyOf = (p, v) => `${p.type}:${v}`;
|
|
4939
|
+
const primitiveFor = /* @__PURE__ */ new Map();
|
|
4940
|
+
for (const p of [...props].sort((a, b) => a.name.length - b.name.length || a.name.localeCompare(b.name)))
|
|
4941
|
+
if (p.kind === "literal" && !p.values && (p.type === "color" || p.type === "length") && !primitiveFor.has(keyOf(p, p.value))) primitiveFor.set(keyOf(p, p.value), p.name);
|
|
4942
|
+
let inferred = 0;
|
|
4943
|
+
for (const p of props) {
|
|
4944
|
+
if (p.kind !== "literal" || !p.values) continue;
|
|
4945
|
+
const def = primitiveFor.get(keyOf(p, p.value));
|
|
4946
|
+
const byMode = Object.entries(p.values).map(([k, v]) => [k, primitiveFor.get(keyOf(p, v))]);
|
|
4947
|
+
if (!def || def === p.name || byMode.some(([, n]) => !n)) continue;
|
|
4948
|
+
p.tier = "semantic";
|
|
4949
|
+
p.kind = "alias";
|
|
4950
|
+
p.aliasOf = def;
|
|
4951
|
+
p.inferred = true;
|
|
4952
|
+
const changes = byMode.filter(([, n]) => n !== def);
|
|
4953
|
+
if (changes.length) p.aliasOfByMode = Object.fromEntries(byMode);
|
|
4954
|
+
inferred++;
|
|
4955
|
+
}
|
|
4956
|
+
return {
|
|
4957
|
+
story,
|
|
4958
|
+
...prefix ? { prefix } : {},
|
|
4959
|
+
modes: live,
|
|
4960
|
+
properties: props,
|
|
4961
|
+
counts: {
|
|
4962
|
+
properties: props.length,
|
|
4963
|
+
primitives: props.filter((p) => p.tier === "primitive").length,
|
|
4964
|
+
semantic: props.filter((p) => p.tier === "semantic").length,
|
|
4965
|
+
used: 0,
|
|
4966
|
+
scoped: props.filter((p) => p.scopes?.length).length,
|
|
4967
|
+
inferred
|
|
4968
|
+
}
|
|
4969
|
+
};
|
|
4970
|
+
}
|
|
4971
|
+
const APPLY_ARGS_SCRIPT = (id, args, timeout) => `(async () => {
|
|
4972
|
+
const want = ${JSON.stringify(args)};
|
|
4973
|
+
const t0 = performance.now();
|
|
4974
|
+
let p = window.__STORYBOOK_PREVIEW__;
|
|
4975
|
+
while ((!p || !p.currentRender || !p.storyStoreValue) && performance.now() - t0 < ${timeout}) { await new Promise((r) => setTimeout(r, 50)); p = window.__STORYBOOK_PREVIEW__; }
|
|
4976
|
+
if (!p || !p.storyStoreValue) return 'failed';
|
|
4977
|
+
const id = ${JSON.stringify(id)};
|
|
4978
|
+
const held = () => { let a = {}; try { a = p.storyStoreValue.args.get(id) || {}; } catch (e) {} return Object.keys(want).every((k) => a[k] === want[k]); };
|
|
4979
|
+
// Let the first render finish (an update sent during it is lost), then check again.
|
|
4980
|
+
const root = () => document.querySelector('#storybook-root, #root');
|
|
4981
|
+
while (performance.now() - t0 < ${timeout} && !(root() && (root().children.length || (root().textContent || '').trim()))) await new Promise((r) => setTimeout(r, 50));
|
|
4982
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
4983
|
+
if (held()) return 'url';
|
|
4984
|
+
const ch = window.__STORYBOOK_ADDONS_CHANNEL__;
|
|
4985
|
+
if (!ch) return 'failed';
|
|
4986
|
+
const done = await new Promise((resolve) => {
|
|
4987
|
+
const t = setTimeout(() => finish(false), 5000);
|
|
4988
|
+
const ok = () => finish(true);
|
|
4989
|
+
const bad = () => finish(false);
|
|
4990
|
+
function finish(v) { clearTimeout(t); ch.off('storyRendered', ok); ch.off('storyErrored', bad); ch.off('storyThrewException', bad); resolve(v); }
|
|
4991
|
+
ch.on('storyRendered', ok); ch.on('storyErrored', bad); ch.on('storyThrewException', bad);
|
|
4992
|
+
ch.emit('updateStoryArgs', { storyId: id, updatedArgs: want });
|
|
4993
|
+
});
|
|
4994
|
+
return done && held() ? 'channel' : 'failed';
|
|
4995
|
+
})()`;
|
|
4996
|
+
async function measureStory(page, storybook, id, o = {}) {
|
|
4997
|
+
const iframe = { ...o.iframe ?? {} };
|
|
4998
|
+
if (o.args && Object.keys(o.args).length) iframe.args = { ...iframe.args ?? {}, ...Object.fromEntries(Object.entries(o.args).map(([k, v]) => [k, typeof v === "boolean" ? `!${v}` : String(v)])) };
|
|
4999
|
+
const url = storybookIframeUrl(storybook, id, iframe);
|
|
5000
|
+
const t0 = Date.now();
|
|
5001
|
+
await page.goto(url, { waitUntil: "domcontentloaded", timeout: (o.timeout ?? 15e3) + 15e3 });
|
|
5002
|
+
if (o.args && Object.keys(o.args).length) await page.evaluate(APPLY_ARGS_SCRIPT(id, o.args, o.timeout ?? 15e3)).catch(() => "failed");
|
|
5003
|
+
const m = await measureRendered(page, o);
|
|
5004
|
+
let props = null;
|
|
5005
|
+
if (o.props !== false && m.root) props = await page.evaluate(PROPS_SCRIPT(id)).catch(() => null);
|
|
5006
|
+
return { id, url, ...m, ...props && typeof props === "object" ? { props } : {}, ms: Date.now() - t0 };
|
|
5007
|
+
}
|
|
5008
|
+
async function measureRendered(page, o = {}) {
|
|
5009
|
+
const t0 = Date.now();
|
|
5010
|
+
const root = o.root ?? "#storybook-root, #root";
|
|
5011
|
+
const timeout = o.timeout ?? 15e3;
|
|
5012
|
+
const rendered = await page.evaluate(WAIT_SCRIPT(root, timeout, o.unwrap === false));
|
|
5013
|
+
let opened;
|
|
5014
|
+
if (o.open && rendered === "rendered") opened = await page.evaluate(OPEN_SCRIPT(root));
|
|
5015
|
+
const target = o.target ?? (o.open && !o.within ? "portal" : void 0);
|
|
5016
|
+
const arg = { root, maxNodes: o.maxNodes, maxDepth: o.maxDepth, unwrap: o.unwrap, target, within: o.within };
|
|
5017
|
+
let state;
|
|
5018
|
+
if (o.state && page.forcePseudo && rendered === "rendered") {
|
|
5019
|
+
const marked = await page.evaluate(`(${MEASURE_SCRIPT})(${JSON.stringify({ ...arg, mark: true })})`);
|
|
5020
|
+
if (marked?.marked && await page.forcePseudo(STATE_TARGETS, PSEUDO_CLASSES[o.state]).catch(() => false)) {
|
|
5021
|
+
state = o.state;
|
|
5022
|
+
await page.evaluate("new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => setTimeout(r, 120))))");
|
|
5023
|
+
}
|
|
5024
|
+
}
|
|
5025
|
+
const r = await page.evaluate(`(${MEASURE_SCRIPT})(${JSON.stringify(arg)})`);
|
|
5026
|
+
let base = "root" in r ? r : { root: null, portals: [], wrappers: 0, nodes: 0, rules: 0, sheets: { read: 0, blocked: 0 }, rootVariables: 0, viewport: { width: 0, height: 0 }, error: r.error };
|
|
5027
|
+
const fillWidth = o.fillWidth ?? 400;
|
|
5028
|
+
if (fillWidth && base.root && base.rootFill && base.root.box.width > fillWidth + 1 && (state || await markMeasuredRoot(page, { ...o, root }))) {
|
|
5029
|
+
await page.evaluate(`(async () => { const e = document.querySelector('[data-bridge-measure-root]'); if (e) { e.style.width = '${fillWidth}px'; e.style.maxWidth = 'none'; e.style.minWidth = '0'; } await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); })()`);
|
|
5030
|
+
const again = await page.evaluate(`(${MEASURE_SCRIPT})(${JSON.stringify(arg)})`);
|
|
5031
|
+
if ("root" in again && again.root) base = { ...again, rootFill: true, fillWidth };
|
|
5032
|
+
}
|
|
5033
|
+
if (opened) base.opened = opened;
|
|
5034
|
+
if (opened === "none" && !base.root) base.error = "the popup did not open: no trigger in the story opened it";
|
|
5035
|
+
if (rendered === "timeout" && !base.error && !base.root) base.error = `the story did not render within ${timeout} ms`;
|
|
5036
|
+
if (rendered === "error" && !base.error) base.error = "the story threw";
|
|
5037
|
+
let shot;
|
|
5038
|
+
if (o.shot && page.screenshot && base.root) {
|
|
5039
|
+
if (state || await markMeasuredRoot(page, { ...o, root })) {
|
|
5040
|
+
const size = await page.screenshot("[data-bridge-measure-root]", o.shot).catch(() => null);
|
|
5041
|
+
if (size) shot = { file: o.shot, ...size };
|
|
5042
|
+
}
|
|
5043
|
+
}
|
|
5044
|
+
if (state) await page.forcePseudo?.(STATE_TARGETS, []).catch(() => false);
|
|
5045
|
+
return { ...withSrgbColors(base), ...state ? { state } : {}, ...shot ? { shot } : {}, ms: Date.now() - t0 };
|
|
5046
|
+
}
|
|
5047
|
+
function pickStoriesToMeasure(index, o = {}) {
|
|
5048
|
+
if (o.ids?.length) {
|
|
5049
|
+
const byId = new Map(index.entries.map((e) => [e.id, e]));
|
|
5050
|
+
return o.ids.map((id) => {
|
|
5051
|
+
const e = byId.get(id);
|
|
5052
|
+
return { id, title: e?.title ?? "", name: e?.name ?? id };
|
|
5053
|
+
});
|
|
5054
|
+
}
|
|
5055
|
+
const want = (o.only ?? []).map((x) => x.trim().toLowerCase()).filter(Boolean);
|
|
5056
|
+
const per = o.perComponent ?? 3;
|
|
5057
|
+
return index.components.filter((c) => c.stories.length && (!want.length || want.includes(c.name.toLowerCase()) || want.includes(c.title.toLowerCase()))).flatMap((c) => c.stories.slice(0, per).map((e) => ({ id: e.id, title: c.title, name: e.name })));
|
|
5058
|
+
}
|
|
5059
|
+
const SEMANTIC_CONTAINER = /^(fieldset|ul|ol|nav|form|menu|dl|select|header|footer|button|a|label|input|textarea)$/;
|
|
5060
|
+
function plainLayout(n, anyRole = false) {
|
|
5061
|
+
if (n.kind !== "frame" || n.input || n.media || !anyRole && (n.role || SEMANTIC_CONTAINER.test(n.tag))) return false;
|
|
5062
|
+
const st = n.style;
|
|
5063
|
+
const painted = !transparent(st["background-color"]) || st["background-image"] && st["background-image"] !== "none" || st["box-shadow"] && st["box-shadow"] !== "none";
|
|
5064
|
+
const bordered = ["top", "right", "bottom", "left"].some((x) => st[`border-${x}-style`] !== "none" && (px(st[`border-${x}-width`]) ?? 0) > 0);
|
|
5065
|
+
return !painted && !bordered && !((px(st["border-top-left-radius"]) ?? 0) > 0);
|
|
5066
|
+
}
|
|
5067
|
+
function sameComponent(a, b) {
|
|
5068
|
+
if (a.tag !== b.tag || a.kind !== b.kind || a.role !== b.role) return false;
|
|
5069
|
+
const ca = new Set((a.classes ?? []).map(localClassName));
|
|
5070
|
+
const cb = (b.classes ?? []).map(localClassName);
|
|
5071
|
+
if (!ca.size && !cb.length) return true;
|
|
5072
|
+
return cb.some((c) => ca.has(c));
|
|
5073
|
+
}
|
|
5074
|
+
function rebase(n, dx = n.box.x, dy = n.box.y) {
|
|
5075
|
+
return { ...n, box: { ...n.box, x: Math.round((n.box.x - dx) * 100) / 100, y: Math.round((n.box.y - dy) * 100) / 100 }, children: n.children.map((c) => rebase(c, dx, dy)) };
|
|
5076
|
+
}
|
|
5077
|
+
function splitInstances(root) {
|
|
5078
|
+
if (!root || !plainLayout(root)) return [];
|
|
5079
|
+
const found = [];
|
|
5080
|
+
const collect = (n, depth) => {
|
|
5081
|
+
for (const c of n.children) {
|
|
5082
|
+
if (c.kind === "text" && (c.text ?? "").length <= 24) continue;
|
|
5083
|
+
if (c.kind === "text") {
|
|
5084
|
+
found.push(c);
|
|
5085
|
+
continue;
|
|
5086
|
+
}
|
|
5087
|
+
if (plainLayout(c, true) && depth < 8 && c.children.length) collect(c, depth + 1);
|
|
5088
|
+
else if (!plainLayout(c, true)) found.push(c);
|
|
5089
|
+
}
|
|
5090
|
+
};
|
|
5091
|
+
collect(root, 0);
|
|
5092
|
+
if (found.length < 2) return [];
|
|
5093
|
+
let best = [];
|
|
5094
|
+
for (const k of found) {
|
|
5095
|
+
if (best.includes(k)) continue;
|
|
5096
|
+
const run = found.filter((c) => sameComponent(k, c));
|
|
5097
|
+
if (run.length > best.length) best = run;
|
|
5098
|
+
}
|
|
5099
|
+
if (best.length < 2 || best.length * 2 <= found.length) return [];
|
|
5100
|
+
return best.map((n) => ({ ...rebase(n), at: { x: n.box.x - root.box.x, y: n.box.y - root.box.y } }));
|
|
5101
|
+
}
|
|
5102
|
+
function localClassName(cls) {
|
|
5103
|
+
const hashed = (h) => !!h && /[0-9A-Z]/.test(h);
|
|
5104
|
+
const m = /^_([A-Za-z][\w-]*?)_[A-Za-z0-9]{5,8}_\d+$/.exec(cls) ?? [/^[A-Za-z][\w-]*?(?:-module)?_{1,2}([A-Za-z][\w-]*?)__([\w-]{5,8})$/.exec(cls)].find((x) => x && hashed(x[2])) ?? /^(?:[a-z]+-)?[A-Z][A-Za-z0-9]*-([A-Za-z]\w*)-[A-Za-z0-9_]{5}$/.exec(cls) ?? [/^_?([A-Za-z][\w-]*?)_([A-Za-z0-9-]{5,8})$/.exec(cls)].find((x) => x && hashed(x[2]));
|
|
5105
|
+
return m ? m[1] : cls;
|
|
5106
|
+
}
|
|
5107
|
+
const UTILITY_KEYWORDS = new Set(
|
|
5108
|
+
"flex inline-flex grid inline-grid block inline-block inline hidden contents table relative absolute fixed sticky static truncate uppercase lowercase capitalize normal-case italic not-italic underline overline line-through no-underline grow shrink border rounded shadow outline ring transition transform visible invisible collapse isolate container antialiased subpixel-antialiased group peer sr-only not-sr-only resize filter blur".split(" ")
|
|
5109
|
+
);
|
|
5110
|
+
const UTILITY_SHAPE = /^(?:p|px|py|pt|pr|pb|pl|ps|pe|m|mx|my|mt|mr|mb|ml|ms|me|w|h|min-w|min-h|max-w|max-h|size|gap|gap-x|gap-y|space-x|space-y|text|bg|from|via|to|border|border-[trblxyse]|rounded|rounded-[trblse]{1,2}|font|leading|tracking|z|top|right|bottom|left|start|end|inset|inset-x|inset-y|opacity|shadow|ring|ring-offset|outline|outline-offset|items|justify|justify-items|justify-self|content|self|place-items|place-content|place-self|flex|basis|grow|shrink|order|col|col-span|col-start|col-end|row|row-span|row-start|row-end|grid-cols|grid-rows|grid-flow|auto-cols|auto-rows|overflow|overflow-x|overflow-y|cursor|select|pointer-events|transition|duration|ease|delay|animate|scale|scale-x|scale-y|rotate|translate-x|translate-y|skew-x|skew-y|origin|fill|stroke|object|aspect|line-clamp|whitespace|break|decoration|underline-offset|list|align|appearance|backdrop|brightness|contrast|drop-shadow|grayscale|invert|saturate|sepia|hue-rotate|tabular|caret|accent|scroll|snap|touch|will-change|columns|divide|divide-x|divide-y|indent|box|float|clear|mix-blend|bg-blend)-[\w.-]+$/;
|
|
5111
|
+
function isUtilityClass(cls) {
|
|
5112
|
+
if (/[:[\]/!]/.test(cls) || /^-[a-z]/.test(cls) || /\.\d/.test(cls)) return true;
|
|
5113
|
+
if (/^css-[a-z0-9]{5,8}$/.test(cls) || /^(?:emotion|sc|jsx|svelte|astro)-[A-Za-z0-9_-]{4,}$/.test(cls) && /\d|[A-Z]/.test(cls)) return true;
|
|
5114
|
+
return UTILITY_KEYWORDS.has(cls) || UTILITY_SHAPE.test(cls);
|
|
5115
|
+
}
|
|
5116
|
+
const defaultTokenOf = (v) => /^--_/.test(v) ? void 0 : v.replace(/^--/, "").split("-").filter(Boolean).join(".");
|
|
5117
|
+
const px = (v) => {
|
|
5118
|
+
if (!v) return void 0;
|
|
5119
|
+
const m = /^(-?[\d.]+)px$/.exec(v.trim());
|
|
5120
|
+
return m ? Math.round(Number(m[1]) * 100) / 100 : void 0;
|
|
5121
|
+
};
|
|
5122
|
+
const transparent = (v) => !v || v === "transparent" || /^rgba\([^)]*,\s*0\)$/.test(v);
|
|
5123
|
+
function arrangement(children) {
|
|
5124
|
+
const kids = children.filter((c) => c.width > 0 || c.height > 0);
|
|
5125
|
+
if (kids.length < 2) return void 0;
|
|
5126
|
+
const stacked = kids.every((c, i) => i === 0 || c.y >= kids[i - 1].y + kids[i - 1].height - 1);
|
|
5127
|
+
const row = kids.every((c, i) => i === 0 || c.x >= kids[i - 1].x + kids[i - 1].width - 1);
|
|
5128
|
+
return stacked && !row ? "stacked" : row && !stacked ? "row" : void 0;
|
|
5129
|
+
}
|
|
5130
|
+
function alignOf(style) {
|
|
5131
|
+
const a = style["align-items"] ?? "normal";
|
|
5132
|
+
return /center/.test(a) ? "CENTER" : /end/.test(a) ? "MAX" : /^(flex-)?start|baseline/.test(a) ? "MIN" : "STRETCH";
|
|
5133
|
+
}
|
|
5134
|
+
function measuredLayout(style, children = []) {
|
|
5135
|
+
const d = style.display ?? "";
|
|
5136
|
+
const arranged = arrangement(children);
|
|
5137
|
+
if (!/flex|grid|block|inline-block|list-item/.test(d)) return arranged ? { direction: arranged === "stacked" ? "VERTICAL" : "HORIZONTAL", primary: "MIN", counter: "MIN" } : void 0;
|
|
5138
|
+
const flex = /flex/.test(d);
|
|
5139
|
+
const grid = /grid/.test(d);
|
|
5140
|
+
const dir = style["flex-direction"] ?? "row";
|
|
5141
|
+
let direction = flex && dir.startsWith("row") ? "HORIZONTAL" : "VERTICAL";
|
|
5142
|
+
if (grid) {
|
|
5143
|
+
const tracks = (v) => v && v !== "none" ? v.trim().split(/\s+(?![^(]*\))/).length : 0;
|
|
5144
|
+
const cols = tracks(style["grid-template-columns"]);
|
|
5145
|
+
const rows = tracks(style["grid-template-rows"]);
|
|
5146
|
+
const sideBySide = children.length >= 2 && children.every((c) => Math.abs(c.y + c.height / 2 - (children[0].y + children[0].height / 2)) <= Math.max(2, children[0].height / 2)) && new Set(children.map((c) => Math.round(c.x))).size === children.length;
|
|
5147
|
+
direction = /column/.test(style["grid-auto-flow"] ?? "") || cols >= 2 && rows <= 1 || cols < 2 && rows < 2 && sideBySide ? "HORIZONTAL" : "VERTICAL";
|
|
5148
|
+
if (cols >= 2 && rows >= 2) direction = sideBySide ? "HORIZONTAL" : "VERTICAL";
|
|
5149
|
+
if (cols >= 2 && rows >= 2 && !sideBySide && !/column/.test(style["grid-auto-flow"] ?? "")) return { direction: "HORIZONTAL", primary: "MIN", counter: alignOf(style), wrap: true };
|
|
5150
|
+
}
|
|
5151
|
+
const j = style["justify-content"] ?? "normal";
|
|
5152
|
+
const primary = !flex && !grid ? "MIN" : /space-between/.test(j) ? "SPACE_BETWEEN" : /center/.test(j) ? "CENTER" : /end|right/.test(j) ? "MAX" : "MIN";
|
|
5153
|
+
const counter = alignOf(style);
|
|
5154
|
+
if (arranged === "stacked" && direction === "HORIZONTAL" && !(flex && style["flex-wrap"] === "wrap")) direction = "VERTICAL";
|
|
5155
|
+
else if (arranged === "row" && direction === "VERTICAL" && !flex) direction = "HORIZONTAL";
|
|
5156
|
+
const out = { direction, primary, counter };
|
|
5157
|
+
if (flex && /reverse/.test(dir)) out.reverse = true;
|
|
5158
|
+
if (flex && direction === "HORIZONTAL" && style["flex-wrap"] === "wrap") out.wrap = true;
|
|
5159
|
+
return out;
|
|
5160
|
+
}
|
|
5161
|
+
const FIELD_MAP = [
|
|
5162
|
+
["fill", "background-color"],
|
|
5163
|
+
["cornerRadius", "border-top-left-radius"],
|
|
5164
|
+
["paddingTop", "padding-top"],
|
|
5165
|
+
["paddingRight", "padding-right"],
|
|
5166
|
+
["paddingBottom", "padding-bottom"],
|
|
5167
|
+
["paddingLeft", "padding-left"],
|
|
5168
|
+
["minWidth", "min-width"],
|
|
5169
|
+
["minHeight", "min-height"],
|
|
5170
|
+
["opacity", "opacity"]
|
|
5171
|
+
];
|
|
5172
|
+
const TEXT_MAP = [
|
|
5173
|
+
["textFill", "color"],
|
|
5174
|
+
["fontFamily", "font-family"],
|
|
5175
|
+
["fontSize", "font-size"],
|
|
5176
|
+
["fontWeight", "font-weight"],
|
|
5177
|
+
["lineHeight", "line-height"],
|
|
5178
|
+
["letterSpacing", "letter-spacing"]
|
|
5179
|
+
];
|
|
5180
|
+
function measuredToSpec(m, o = {}) {
|
|
5181
|
+
const tokenOf = o.tokenOf ?? defaultTokenOf;
|
|
5182
|
+
const out = { story: m.id, parts: [], values: {}, raw: {}, tokens: {}, boxes: {}, coverage: { fields: 0, declared: 0, matched: 0, literal: 0 } };
|
|
5183
|
+
if (!m.root) return out;
|
|
5184
|
+
const used = /* @__PURE__ */ new Set();
|
|
5185
|
+
const idFor = (n, isRoot, inherited) => {
|
|
5186
|
+
if (isRoot) {
|
|
5187
|
+
used.add("root");
|
|
5188
|
+
return "root";
|
|
5189
|
+
}
|
|
5190
|
+
const cls = (n.classes ?? []).map(localClassName).find((c) => /^[A-Za-z]/.test(c) && c.length < 40 && !isUtilityClass(c));
|
|
5191
|
+
let base = cls ?? (n.pseudo ? `${inherited ?? "root"}-${n.pseudo}` : n.kind === "text" ? inherited ? `${inherited}-text` : "text" : n.kind === "icon" ? "icon" : n.tag);
|
|
5192
|
+
base = base.replace(/[^A-Za-z0-9-]+/g, "-").toLowerCase() || "part";
|
|
5193
|
+
let id = base;
|
|
5194
|
+
for (let i = 2; used.has(id); i++) id = `${base}-${i}`;
|
|
5195
|
+
used.add(id);
|
|
5196
|
+
return id;
|
|
5197
|
+
};
|
|
5198
|
+
const visit = (n, parent, parentStyle, parentBox) => {
|
|
5199
|
+
const id = idFor(n, !parent, parent);
|
|
5200
|
+
const style = n.kind === "text" && n.tag === "#text" ? parentStyle ?? {} : n.style;
|
|
5201
|
+
const tokens = n.kind === "text" && n.tag === "#text" ? {} : n.tokens;
|
|
5202
|
+
const part = { id, name: id === "root" ? "Root" : id.replace(/-/g, " ").replace(/^./, (c) => c.toUpperCase()), kind: n.kind };
|
|
5203
|
+
if (parent) part.parent = parent;
|
|
5204
|
+
const named = (n.classes ?? []).map(localClassName).filter((c) => !isUtilityClass(c));
|
|
5205
|
+
if (named.length) part.source = named.join(" ");
|
|
5206
|
+
if (n.kind === "frame") {
|
|
5207
|
+
const l = measuredLayout(n.style, n.children.filter((c) => c.style.position !== "absolute" && c.style.position !== "fixed").map((c) => c.box));
|
|
5208
|
+
if (l) part.layout = l;
|
|
5209
|
+
if (/^(hidden|clip)/.test(n.style.overflow ?? "")) part.clip = true;
|
|
5210
|
+
if ((n.style.position === "absolute" || n.style.position === "fixed") && parent) {
|
|
5211
|
+
const zero = (v) => v !== void 0 && /^0(px)?$/.test(v.trim());
|
|
5212
|
+
if (["top", "right", "bottom", "left"].every((k) => zero(n.style[k]))) part.cover = true;
|
|
5213
|
+
else {
|
|
5214
|
+
const pb = parentBox ?? { x: 0, y: 0 };
|
|
5215
|
+
part.pin = { top: Math.round((n.box.y - pb.y) * 100) / 100, left: Math.round((n.box.x - pb.x) * 100) / 100 };
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
if (Number(n.style["flex-grow"]) > 0) part.grow = true;
|
|
5219
|
+
}
|
|
5220
|
+
if (n.kind === "text") part.characters = n.text ?? "";
|
|
5221
|
+
if (!parent && m.rootFill) part.fill = true;
|
|
5222
|
+
const margins = Object.fromEntries(["top", "right", "bottom", "left"].map((k) => [k, px(n.style[`margin-${k}`]) ?? 0]).filter(([, v]) => Math.abs(v) > 0.5));
|
|
5223
|
+
if (Object.keys(margins).length) part.margins = margins;
|
|
5224
|
+
out.parts.push(part);
|
|
5225
|
+
partById.set(id, part);
|
|
5226
|
+
out.boxes[id] = n.box;
|
|
5227
|
+
const values = {};
|
|
5228
|
+
const raw = {};
|
|
5229
|
+
const ev = {};
|
|
5230
|
+
const put = (field, prop, literal) => {
|
|
5231
|
+
if (literal === void 0) return;
|
|
5232
|
+
out.coverage.fields++;
|
|
5233
|
+
if (literal !== null) raw[field] = literal;
|
|
5234
|
+
const t2 = tokens[prop];
|
|
5235
|
+
if (t2) ev[field] = t2;
|
|
5236
|
+
if (t2?.via === "declared" && t2.exact) {
|
|
5237
|
+
out.coverage.declared++;
|
|
5238
|
+
const path = t2.chain.map(tokenOf).find((x) => !!x);
|
|
5239
|
+
if (path) return void (values[field] = path);
|
|
5240
|
+
} else if (t2?.via === "declared") out.coverage.declared++;
|
|
5241
|
+
else if (t2?.via === "matched") out.coverage.matched++;
|
|
5242
|
+
else out.coverage.literal++;
|
|
5243
|
+
if (literal === null) values[field] = null;
|
|
5244
|
+
else if (typeof literal === "number") values[field] = literal;
|
|
5245
|
+
};
|
|
5246
|
+
if (n.kind === "frame") {
|
|
5247
|
+
for (const [field, prop] of FIELD_MAP) {
|
|
5248
|
+
const v = n.style[prop];
|
|
5249
|
+
if (field === "fill") put(field, prop, transparent(v) ? n.style["background-image"] && n.style["background-image"] !== "none" ? n.style["background-image"] : void 0 : v);
|
|
5250
|
+
else if (field === "opacity") put(field, prop, v && Number(v) < 1 ? Number(v) : void 0);
|
|
5251
|
+
else if (field === "minWidth" || field === "minHeight") {
|
|
5252
|
+
const sides = field === "minWidth" ? ["left", "right"] : ["top", "bottom"];
|
|
5253
|
+
const extra = n.style["box-sizing"] === "content-box" ? sides.reduce((a, x) => a + (px(n.style[`padding-${x}`]) ?? 0) + (n.style[`border-${x}-style`] === "none" ? 0 : px(n.style[`border-${x}-width`]) ?? 0), 0) : 0;
|
|
5254
|
+
const min = px(v);
|
|
5255
|
+
if (!min) continue;
|
|
5256
|
+
if (extra) {
|
|
5257
|
+
out.coverage.fields++;
|
|
5258
|
+
out.coverage.literal++;
|
|
5259
|
+
raw[field] = min + extra;
|
|
5260
|
+
values[field] = min + extra;
|
|
5261
|
+
} else put(field, prop, min);
|
|
5262
|
+
} else if (field === "cornerRadius" && v && /%$/.test(v.trim())) {
|
|
5263
|
+
const half = Math.min(n.box.width, n.box.height) / 2;
|
|
5264
|
+
const r = Math.min(half, Math.round(Math.min(n.box.width, n.box.height) * Number.parseFloat(v) / 100 * 100) / 100);
|
|
5265
|
+
if (r >= half - 0.5) part.fullRadius = true;
|
|
5266
|
+
if (r > 0) {
|
|
5267
|
+
out.coverage.fields++;
|
|
5268
|
+
out.coverage.literal++;
|
|
5269
|
+
raw[field] = r;
|
|
5270
|
+
values[field] = part.fullRadius ? 999 : r;
|
|
5271
|
+
}
|
|
5272
|
+
} else {
|
|
5273
|
+
const half = Math.min(n.box.width, n.box.height) / 2;
|
|
5274
|
+
if (field === "cornerRadius" && (px(v) ?? 0) >= half - 0.5 && half > 0) part.fullRadius = true;
|
|
5275
|
+
put(field, prop, px(v) || void 0);
|
|
5276
|
+
if (part.fullRadius && field === "cornerRadius" && typeof values.cornerRadius === "number") values.cornerRadius = 999;
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
const widths = ["top", "right", "bottom", "left"].map((s) => n.style[`border-${s}-style`] === "none" ? 0 : px(n.style[`border-${s}-width`]) ?? 0);
|
|
5280
|
+
if (widths.some((w) => w > 0)) {
|
|
5281
|
+
const side = widths.findIndex((w) => w > 0);
|
|
5282
|
+
const s = ["top", "right", "bottom", "left"][side];
|
|
5283
|
+
const color = n.style[`border-${s}-color`];
|
|
5284
|
+
put("stroke", `border-${s}-color`, transparent(color) ? null : color);
|
|
5285
|
+
if (widths.every((w) => w === widths[0])) put("strokeWeight", "border-top-width", widths[0]);
|
|
5286
|
+
else ["top", "right", "bottom", "left"].forEach((x, i) => put({ top: "strokeTopWeight", right: "strokeRightWeight", bottom: "strokeBottomWeight", left: "strokeLeftWeight" }[x], `border-${x}-width`, widths[i]));
|
|
5287
|
+
}
|
|
5288
|
+
if (parseBoxShadow(n.style["box-shadow"]).length) put("shadow", "box-shadow", n.style["box-shadow"]);
|
|
5289
|
+
const l = part.layout;
|
|
5290
|
+
if (l && /flex|grid/.test(n.style.display ?? "")) {
|
|
5291
|
+
const gap = l.direction === "HORIZONTAL" ? n.style["column-gap"] : n.style["row-gap"];
|
|
5292
|
+
put("itemSpacing", l.direction === "HORIZONTAL" ? "column-gap" : "row-gap", px(gap) || void 0);
|
|
5293
|
+
if (l.wrap) put("counterAxisSpacing", "row-gap", px(n.style["row-gap"]) || void 0);
|
|
5294
|
+
}
|
|
5295
|
+
put("width", "width", n.box.width);
|
|
5296
|
+
put("height", "height", n.box.height);
|
|
5297
|
+
}
|
|
5298
|
+
if (n.kind === "text") {
|
|
5299
|
+
for (const [field, prop] of TEXT_MAP) {
|
|
5300
|
+
const v = style[prop];
|
|
5301
|
+
if (!v || v === "normal") continue;
|
|
5302
|
+
put(field, prop, field === "textFill" || field === "fontFamily" ? v : field === "fontWeight" ? Number(v) : px(v));
|
|
5303
|
+
}
|
|
5304
|
+
const deco = style["text-decoration-line"];
|
|
5305
|
+
if (deco && /underline|line-through/.test(deco)) raw.textDecoration = /underline/.test(deco) ? "UNDERLINE" : "STRIKETHROUGH";
|
|
5306
|
+
}
|
|
5307
|
+
if ((n.kind === "icon" || n.kind === "vector") && n.svg) (out.vectors ??= {})[id] = { svg: n.svg, strokes: n.svgStrokes ?? [] };
|
|
5308
|
+
if (n.kind === "icon" || n.kind === "vector") {
|
|
5309
|
+
put("width", "width", n.box.width);
|
|
5310
|
+
put("height", "height", n.box.height);
|
|
5311
|
+
const stroked = !!n.style.stroke && n.style.stroke !== "none";
|
|
5312
|
+
const prop = stroked ? "stroke" : "fill";
|
|
5313
|
+
const paint = n.style[prop];
|
|
5314
|
+
if (paint && paint !== "none") put(stroked ? "stroke" : "fill", n.tokens[prop] ? prop : "color", /currentcolor/i.test(paint) ? n.style.color : paint);
|
|
5315
|
+
if (stroked) put("strokeWeight", "stroke-width", px(n.style["stroke-width"]) ?? (Number(n.style["stroke-width"]) || void 0));
|
|
5316
|
+
}
|
|
5317
|
+
if (Object.keys(values).length) out.values[id] = values;
|
|
5318
|
+
if (Object.keys(raw).length) out.raw[id] = raw;
|
|
5319
|
+
if (Object.keys(ev).length) out.tokens[id] = ev;
|
|
5320
|
+
if (n.sized && (n.sized.width || n.sized.height)) (out.sized ??= {})[id] = { ...n.sized.width ? { width: n.box.width } : {}, ...n.sized.height ? { height: n.box.height } : {} };
|
|
5321
|
+
const kids = n.children.map((c) => [c, visit(c, id, n.style, n.box)]);
|
|
5322
|
+
if (part.layout?.wrap && /grid/.test(n.style.display ?? "")) {
|
|
5323
|
+
for (const [c, cid] of [[n, id], ...kids]) if (c === n || !/absolute|fixed/.test(c.style.position ?? "")) (out.sized ??= {})[cid] = { ...out.sized?.[cid], width: c.box.width };
|
|
5324
|
+
}
|
|
5325
|
+
if (part.layout) spacing(id, n, part.layout, kids);
|
|
5326
|
+
if (n.kind === "frame") positioned(id, part, n, kids);
|
|
5327
|
+
const t = /matrix\(([^)]+)\)/.exec(n.style.transform ?? "")?.[1]?.split(",").map(Number);
|
|
5328
|
+
if (parent && parentBox && t && t.length === 6 && Math.abs(t[1]) < 1e-6 && Math.abs(t[2]) < 1e-6 && (Math.abs(t[4]) >= 0.5 || Math.abs(t[5]) >= 0.5 || Math.abs(t[0] - 1) > 0.01 || Math.abs(t[3] - 1) > 0.01) && !part.cover) {
|
|
5329
|
+
part.pin = { top: Math.round((n.box.y - parentBox.y) * 100) / 100, left: Math.round((n.box.x - parentBox.x) * 100) / 100 };
|
|
5330
|
+
if (Math.abs(t[0] - 1) > 0.01 || Math.abs(t[3] - 1) > 0.01) (out.sized ??= {})[id] = { width: n.box.width, height: n.box.height };
|
|
5331
|
+
}
|
|
5332
|
+
return id;
|
|
5333
|
+
};
|
|
5334
|
+
const partById = /* @__PURE__ */ new Map();
|
|
5335
|
+
const byId = (id) => partById.get(id) ?? out.parts.find((p) => p.id === id);
|
|
5336
|
+
const positioned = (id, parentPart, n, kids) => {
|
|
5337
|
+
const abs = kids.filter(([c]) => c.style.position === "absolute" || c.style.position === "fixed");
|
|
5338
|
+
if (!abs.length) return;
|
|
5339
|
+
const flow = kids.filter(([c]) => !(c.style.position === "absolute" || c.style.position === "fixed") && (c.box.width > 0 || c.box.height > 0));
|
|
5340
|
+
const st = n.style;
|
|
5341
|
+
const b = (k) => st[`border-${k}-style`] === "none" ? 0 : px(st[`border-${k}-width`]) ?? 0;
|
|
5342
|
+
const inner = { x: n.box.x + b("left"), y: n.box.y + b("top"), r: n.box.x + n.box.width - b("right"), bottom: n.box.y + n.box.height - b("bottom") };
|
|
5343
|
+
const r2 = (x) => Math.round(x * 100) / 100;
|
|
5344
|
+
if (abs.length === 1 && !flow.length) {
|
|
5345
|
+
const [c, cid] = abs[0];
|
|
5346
|
+
const p = byId(cid);
|
|
5347
|
+
if (p && !p.cover) {
|
|
5348
|
+
const left = r2(c.box.x - inner.x), right = r2(inner.r - (c.box.x + c.box.width));
|
|
5349
|
+
const top = r2(c.box.y - inner.y), bottom = r2(inner.bottom - (c.box.y + c.box.height));
|
|
5350
|
+
const ax = (a, z) => Math.abs(a - z) <= 1 ? "center" : a <= z ? "start" : "end";
|
|
5351
|
+
const x = ax(left, right), y = ax(top, bottom);
|
|
5352
|
+
if (left >= -0.5 && right >= -0.5 && top >= -0.5 && bottom >= -0.5) {
|
|
5353
|
+
delete p.pin;
|
|
5354
|
+
const map = { start: "MIN", center: "CENTER", end: "MAX" };
|
|
5355
|
+
parentPart.layout = { direction: "HORIZONTAL", primary: map[x], counter: map[y], align: { [cid]: { primary: map[x], counter: map[y] } } };
|
|
5356
|
+
const vals = out.values[id] ??= {};
|
|
5357
|
+
const raws = out.raw[id] ??= {};
|
|
5358
|
+
const set = (k, v) => {
|
|
5359
|
+
if (v > 0.5) {
|
|
5360
|
+
vals[k] = v;
|
|
5361
|
+
raws[k] = v;
|
|
5362
|
+
} else {
|
|
5363
|
+
delete vals[k];
|
|
5364
|
+
delete raws[k];
|
|
5365
|
+
}
|
|
5366
|
+
};
|
|
5367
|
+
set("paddingLeft", x === "start" ? left : 0);
|
|
5368
|
+
set("paddingRight", x === "end" ? right : 0);
|
|
5369
|
+
set("paddingTop", y === "start" ? top : 0);
|
|
5370
|
+
set("paddingBottom", y === "end" ? bottom : 0);
|
|
5371
|
+
return;
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
const overlaps = (a, z) => a.x < z.x + z.width - 0.5 && z.x < a.x + a.width - 0.5 && a.y < z.y + z.height - 0.5 && z.y < a.y + a.height - 0.5;
|
|
5376
|
+
for (const [c, cid] of abs) {
|
|
5377
|
+
const p = byId(cid);
|
|
5378
|
+
if (!p || p.cover) continue;
|
|
5379
|
+
const outside = c.box.x < inner.x - 0.5 || c.box.y < inner.y - 0.5 || c.box.x + c.box.width > inner.r + 0.5 || c.box.y + c.box.height > inner.bottom + 0.5;
|
|
5380
|
+
if (outside || flow.some(([f]) => overlaps(c.box, f.box))) p.overlay = true;
|
|
5381
|
+
}
|
|
5382
|
+
};
|
|
5383
|
+
const spacing = (id, n, layout, kids) => {
|
|
5384
|
+
if (layout.primary !== "MIN" || layout.wrap || layout.reverse) return;
|
|
5385
|
+
const flow = kids.filter(([c]) => c.style.position !== "absolute" && c.style.position !== "fixed" && (c.box.width > 0 || c.box.height > 0));
|
|
5386
|
+
if (!flow.length) return;
|
|
5387
|
+
const v = layout.direction === "VERTICAL";
|
|
5388
|
+
const st = n.style;
|
|
5389
|
+
const side = v ? ["top", "bottom"] : ["left", "right"];
|
|
5390
|
+
const num = (x) => px(x) ?? 0;
|
|
5391
|
+
const startEdge = (v ? n.box.y : n.box.x) + (st[`border-${side[0]}-style`] === "none" ? 0 : num(st[`border-${side[0]}-width`])) + num(st[`padding-${side[0]}`]);
|
|
5392
|
+
const endEdge = (v ? n.box.y + n.box.height : n.box.x + n.box.width) - (st[`border-${side[1]}-style`] === "none" ? 0 : num(st[`border-${side[1]}-width`])) - num(st[`padding-${side[1]}`]);
|
|
5393
|
+
const lo = (b) => v ? b.y : b.x;
|
|
5394
|
+
const hi = (b) => v ? b.y + b.height : b.x + b.width;
|
|
5395
|
+
const gaps = flow.slice(1).map(([c], i) => Math.round((lo(c.box) - hi(flow[i][0].box)) * 100) / 100);
|
|
5396
|
+
if (gaps.some((g) => g < -0.5)) return;
|
|
5397
|
+
const vals = out.values[id] ??= {};
|
|
5398
|
+
const raws = out.raw[id] ??= {};
|
|
5399
|
+
const padKey = (k) => ({ top: "paddingTop", bottom: "paddingBottom", left: "paddingLeft", right: "paddingRight" })[k];
|
|
5400
|
+
const first = flow[0][0];
|
|
5401
|
+
const last = flow[flow.length - 1][0];
|
|
5402
|
+
const before = Math.min(num(first.style[`margin-${side[0]}`]), Math.round((lo(first.box) - startEdge) * 100) / 100);
|
|
5403
|
+
const after = Math.min(num(last.style[`margin-${side[1]}`]), Math.round((endEdge - hi(last.box)) * 100) / 100);
|
|
5404
|
+
for (const [k, extra] of [[side[0], before], [side[1], after]]) {
|
|
5405
|
+
if (!(extra > 0.5)) continue;
|
|
5406
|
+
const total = Math.round((num(st[`padding-${k}`]) + extra) * 100) / 100;
|
|
5407
|
+
vals[padKey(k)] = total;
|
|
5408
|
+
raws[padKey(k)] = total;
|
|
5409
|
+
}
|
|
5410
|
+
if (!gaps.length) return;
|
|
5411
|
+
const marginBetween = flow.slice(1).some(([c], i) => num(flow[i][0].style[`margin-${side[1]}`]) > 0.5 || num(c.style[`margin-${side[0]}`]) > 0.5);
|
|
5412
|
+
if (!marginBetween) return;
|
|
5413
|
+
const declaredGap = num(v ? st["row-gap"] : st["column-gap"]);
|
|
5414
|
+
const min = Math.min(...gaps);
|
|
5415
|
+
const uniform = gaps.every((g) => Math.abs(g - gaps[0]) <= 0.5);
|
|
5416
|
+
if (uniform && Math.abs(gaps[0] - declaredGap) <= 0.5) return;
|
|
5417
|
+
vals.itemSpacing = uniform ? gaps[0] : min;
|
|
5418
|
+
raws.itemSpacing = vals.itemSpacing;
|
|
5419
|
+
if (!uniform)
|
|
5420
|
+
flow.slice(1).forEach(([c, cid], i) => {
|
|
5421
|
+
const extra = Math.round((gaps[i] - min) * 100) / 100;
|
|
5422
|
+
if (!(extra > 0.5)) return;
|
|
5423
|
+
(out.spacers ??= {})[cid] = extra;
|
|
5424
|
+
const [prev, pid] = flow[i];
|
|
5425
|
+
const onPrev = num(prev.style[`margin-${side[1]}`]) > 0.5 && !(num(c.style[`margin-${side[0]}`]) > num(prev.style[`margin-${side[1]}`]));
|
|
5426
|
+
const owner = byId(onPrev ? pid : cid);
|
|
5427
|
+
if (owner) owner.wrap = { padding: { ...owner.wrap?.padding ?? {}, [onPrev ? side[1] : side[0]]: extra } };
|
|
5428
|
+
});
|
|
5429
|
+
};
|
|
5430
|
+
visit(m.root, void 0, void 0);
|
|
5431
|
+
for (const k of Object.keys(out.values)) if (!Object.keys(out.values[k]).length) delete out.values[k];
|
|
5432
|
+
for (const k of Object.keys(out.raw)) if (!Object.keys(out.raw[k]).length) delete out.raw[k];
|
|
5433
|
+
return out;
|
|
5434
|
+
}
|
|
3847
5435
|
export {
|
|
5436
|
+
APPLY_ARGS_SCRIPT,
|
|
3848
5437
|
COMMON_ICONS,
|
|
3849
5438
|
DEFAULT_STATE,
|
|
5439
|
+
GLOBALS_SCRIPT,
|
|
3850
5440
|
ICON_STYLE,
|
|
3851
5441
|
INHERITED,
|
|
5442
|
+
MEASURE_SCRIPT,
|
|
3852
5443
|
MEDIA_SLOT,
|
|
5444
|
+
aV as MeasuredSpecsError,
|
|
5445
|
+
OPEN_SCRIPT,
|
|
5446
|
+
PROPS_SCRIPT,
|
|
5447
|
+
SPEC_VIEWPORT_WIDTH,
|
|
5448
|
+
TOKENS_SCRIPT,
|
|
3853
5449
|
UnsupportedComponentError,
|
|
5450
|
+
WAIT_SCRIPT,
|
|
3854
5451
|
applySuggestionLocally,
|
|
3855
5452
|
branchExists,
|
|
3856
5453
|
changedProperties,
|
|
3857
5454
|
collectAuditFiles,
|
|
3858
5455
|
commitToNewLocalBranch,
|
|
3859
5456
|
commitTree,
|
|
5457
|
+
C as compareSpecToMeasured,
|
|
3860
5458
|
computeValues,
|
|
3861
5459
|
currentBranch,
|
|
3862
5460
|
declaredFor,
|
|
3863
5461
|
draftedCodeHash,
|
|
3864
5462
|
draftedSpec,
|
|
3865
5463
|
entryFor,
|
|
5464
|
+
c6 as evalCalc,
|
|
3866
5465
|
expandDecl,
|
|
3867
5466
|
fileDiff,
|
|
3868
5467
|
findDesignSystemRoot,
|
|
@@ -3876,37 +5475,54 @@ export {
|
|
|
3876
5475
|
generateSlots,
|
|
3877
5476
|
git,
|
|
3878
5477
|
gitWorkspace,
|
|
5478
|
+
harvestTokens,
|
|
3879
5479
|
isGitRepo,
|
|
5480
|
+
isUtilityClass,
|
|
3880
5481
|
jsxText,
|
|
3881
5482
|
listFilesAt,
|
|
3882
5483
|
loadAllowlist,
|
|
3883
5484
|
loadDesignSystem,
|
|
3884
5485
|
loadLocalHistory,
|
|
5486
|
+
localClassName,
|
|
3885
5487
|
localGitHistoryBackend,
|
|
3886
5488
|
localRepoRef,
|
|
3887
5489
|
localTags,
|
|
5490
|
+
markMeasuredRoot,
|
|
5491
|
+
cL as markUsedTokens,
|
|
3888
5492
|
matchComplex,
|
|
5493
|
+
measureRendered,
|
|
5494
|
+
measureStory,
|
|
5495
|
+
measuredLayout,
|
|
5496
|
+
measuredToSpec,
|
|
3889
5497
|
mediaApplies,
|
|
3890
5498
|
mergeText,
|
|
3891
5499
|
motionNotes,
|
|
3892
5500
|
openingTransitions,
|
|
3893
5501
|
originRepo,
|
|
3894
5502
|
overridesDirOf,
|
|
5503
|
+
I as pairParts,
|
|
3895
5504
|
parseCssModule,
|
|
5505
|
+
d1 as parseMeasuredSpecsFile,
|
|
3896
5506
|
parseSelector,
|
|
3897
5507
|
parseTransitions,
|
|
5508
|
+
pickStoriesToMeasure,
|
|
3898
5509
|
repoSpecOptions,
|
|
3899
5510
|
resolveDuration,
|
|
3900
5511
|
resolveEasing,
|
|
5512
|
+
resolveTokenValues,
|
|
3901
5513
|
runAudit,
|
|
3902
5514
|
sentenceCase,
|
|
3903
5515
|
serializeComponentSpecs,
|
|
5516
|
+
sharedTokenPrefix,
|
|
3904
5517
|
shorthandOf,
|
|
3905
5518
|
showFile,
|
|
3906
5519
|
specDrawsSomething,
|
|
5520
|
+
splitInstances,
|
|
3907
5521
|
splitTop,
|
|
3908
5522
|
substituteVars,
|
|
3909
5523
|
tokenCssIndex,
|
|
3910
|
-
|
|
5524
|
+
tokenVariablePath,
|
|
5525
|
+
transitionBetween,
|
|
5526
|
+
H as withoutAddedWrappers
|
|
3911
5527
|
};
|
|
3912
5528
|
//# sourceMappingURL=index.js.map
|