@domandigital/craft 0.20.5 → 0.21.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/CHANGELOG.md +17 -0
- package/CHARACTER.md +2 -1
- package/COPY.md +6 -2
- package/README.md +73 -3
- package/dist/{audit-5I2WWTL6.js → audit-LQ2TDISV.js} +3 -3
- package/dist/audit.cjs +64 -1
- package/dist/audit.js +64 -1
- package/dist/{chunk-TSO5W32N.js → chunk-4WAIOZ4W.js} +14 -14
- package/dist/{chunk-YFS32BZ2.js → chunk-6DRBFDWT.js} +1 -1
- package/dist/chunk-BQ7H23QP.js +261 -0
- package/dist/{chunk-DMAMGFV7.js → chunk-BYXDX66D.js} +4 -4
- package/dist/{chunk-PFVSKIPM.js → chunk-DE2ZAV4G.js} +4 -2
- package/dist/{chunk-BBJOLR3R.js → chunk-FNB3NP57.js} +5 -5
- package/dist/{chunk-GJY2VMPD.js → chunk-G47ZCBD5.js} +2 -2
- package/dist/{chunk-FBWBDBW4.js → chunk-ONA73THJ.js} +61 -0
- package/dist/{chunk-N32UUN3S.js → chunk-STWH5EYU.js} +5 -5
- package/dist/{cli-SQC27VYC.js → cli-5QI6NIZN.js} +6 -6
- package/dist/{cli-BI6XCMCL.js → cli-5VHX5EJF.js} +5 -5
- package/dist/{cli-NIH3WTNE.js → cli-7QL26YPR.js} +1 -1
- package/dist/cli-EYHRJJAX.js +241 -0
- package/dist/{cli-V4QXTBWR.js → cli-PBCU7Z64.js} +4 -4
- package/dist/{cli-JQYZXFRH.js → cli-RHDNHL4U.js} +5 -5
- package/dist/{cli-OH6427MC.js → cli-XAWJWK7I.js} +6 -6
- package/dist/{cli-W6FNSHRN.js → cli-YSGPGQ7R.js} +9 -9
- package/dist/cli.js +3 -3
- package/dist/index.cjs +64 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +64 -1
- package/dist/phone.cjs +137 -11
- package/dist/phone.d.cts +86 -12
- package/dist/phone.d.ts +86 -12
- package/dist/phone.js +128 -11
- package/dist/{viewports-cli-C4DWICYI.js → viewports-cli-XYYX4SKV.js} +12 -8
- package/package.json +1 -1
- package/word-lists.json +1 -1
- package/dist/chunk-IJUZ7RV4.js +0 -151
- package/dist/cli-56H5IPWT.js +0 -122
package/dist/phone.cjs
CHANGED
|
@@ -33,8 +33,13 @@ __export(phone_exports, {
|
|
|
33
33
|
WIDE_WIDTHS: () => WIDE_WIDTHS,
|
|
34
34
|
bandOf: () => bandOf,
|
|
35
35
|
checkExceptions: () => checkExceptions,
|
|
36
|
+
cleanRoute: () => cleanRoute,
|
|
36
37
|
formatWidths: () => formatWidths,
|
|
38
|
+
hasReason: () => hasReason,
|
|
39
|
+
hasUnexcusedEntries: () => hasUnexcusedEntries,
|
|
40
|
+
judgeGrowth: () => judgeGrowth,
|
|
37
41
|
judgeMeasured: () => judgeMeasured,
|
|
42
|
+
judgeRoutes: () => judgeRoutes,
|
|
38
43
|
judgeStatic: () => judgeStatic,
|
|
39
44
|
mainActionFor: () => mainActionFor,
|
|
40
45
|
measurePhone: () => measurePhone,
|
|
@@ -45,8 +50,12 @@ __export(phone_exports, {
|
|
|
45
50
|
measureViewports: () => measureViewports,
|
|
46
51
|
mergeViewportFindings: () => mergeViewportFindings,
|
|
47
52
|
normaliseElement: () => normaliseElement,
|
|
53
|
+
parseBaseline: () => parseBaseline,
|
|
48
54
|
reasonOf: () => reasonOf,
|
|
49
55
|
routeFile: () => routeFile,
|
|
56
|
+
routeMatches: () => routeMatches,
|
|
57
|
+
routesFromManifest: () => routesFromManifest,
|
|
58
|
+
routesFromPages: () => routesFromPages,
|
|
50
59
|
scanPhoneFirst: () => scanPhoneFirst,
|
|
51
60
|
sweepWidths: () => sweepWidths,
|
|
52
61
|
writeBaseline: () => writeBaseline
|
|
@@ -62,13 +71,14 @@ var PHONE = {
|
|
|
62
71
|
isMobile: true,
|
|
63
72
|
hasTouch: true
|
|
64
73
|
};
|
|
65
|
-
var PHONE_FLOORS = { targetPx: 44, fieldFontPx: 16, textPx: 12 };
|
|
74
|
+
var PHONE_FLOORS = { targetPx: 44, fieldFontPx: 16, textPx: 12, fieldHeightPx: 48 };
|
|
66
75
|
var DEFAULT_MEASURED_DIR = "phone-first/measured";
|
|
67
76
|
var routeFile = (route) => `${route === "/" ? "home" : route.replace(/^\/+|\/+$/g, "").replace(/[^\w.-]+/g, "-")}.json`;
|
|
68
77
|
|
|
69
78
|
// src/phone/measure-in-page.ts
|
|
70
79
|
function measurePhoneInPage(floors) {
|
|
71
80
|
const out = [];
|
|
81
|
+
const fieldHeightPx = floors.fieldHeightPx ?? 48;
|
|
72
82
|
const only = floors.only;
|
|
73
83
|
const on = (c) => !only || only.includes(c);
|
|
74
84
|
const vw = document.documentElement.clientWidth;
|
|
@@ -112,6 +122,9 @@ function measurePhoneInPage(floors) {
|
|
|
112
122
|
if (!shown(e) || quiet(e) || e.tagName === "INPUT" && NOT_TEXT.has(e.type)) continue;
|
|
113
123
|
const px = parseFloat(getComputedStyle(e).fontSize);
|
|
114
124
|
if (px < floors.fieldFontPx) out.push({ check: "field", element: describe(e), detail: `set at ${px}px, under ${floors.fieldFontPx}px, so Safari on iOS zooms on focus` });
|
|
125
|
+
const box = e.getBoundingClientRect();
|
|
126
|
+
const height = Math.round(box.height);
|
|
127
|
+
if (box.width > 1 && height > 1 && height < fieldHeightPx) out.push({ check: "field", element: describe(e), detail: `${height}px tall, under ${fieldHeightPx}px (use min-h-12)` });
|
|
115
128
|
}
|
|
116
129
|
for (const e of on("text") ? Array.from(document.body.querySelectorAll("*")) : []) {
|
|
117
130
|
if (!shown(e) || quiet(e) || ["SCRIPT", "STYLE", "NOSCRIPT", "TEMPLATE"].includes(e.tagName)) continue;
|
|
@@ -419,17 +432,26 @@ function measureViewportInPage(arg) {
|
|
|
419
432
|
}
|
|
420
433
|
|
|
421
434
|
// src/phone/judge.ts
|
|
435
|
+
var hasReason = (entry) => typeof entry.reason === "string" && entry.reason.trim() !== "";
|
|
436
|
+
function parseBaseline(raw, where) {
|
|
437
|
+
const b = raw ?? {};
|
|
438
|
+
const entries = [...b.static ?? [], ...b.measured ?? []];
|
|
439
|
+
const bad = entries.find((e) => e.reason !== void 0 && typeof e.reason !== "string");
|
|
440
|
+
if (bad) throw new Error(`${where}: an entry has a "reason" that is not text: ${JSON.stringify(bad)}`);
|
|
441
|
+
return { ...b.note ? { note: b.note } : {}, static: b.static ?? [], measured: b.measured ?? [] };
|
|
442
|
+
}
|
|
422
443
|
var EMPTY_BASELINE = { static: [], measured: [] };
|
|
423
444
|
var MEDIA = /@(?:custom-)?media\b([^{;]*)/g;
|
|
424
445
|
var CAPS_WIDTH = /\bmax-(?:device-)?width\s*:|\bwidth\s*<|>=?\s*(?:device-)?width\b/i;
|
|
425
446
|
var VARIANT = /(?<![\w@-])max-(\[[^\]\s]+\]|[a-z0-9]+):/g;
|
|
426
447
|
var NOT_VARIANTS = /* @__PURE__ */ new Set(["width", "height", "lines", "resolution", "zoom", "inline-size", "block-size"]);
|
|
427
448
|
var OK = /mobile-first-ok\b:?(.*)/;
|
|
449
|
+
var VAR_OPACITY = /[^\s"'`]*var\([^)]*\)\]\/[0-9]+/g;
|
|
428
450
|
function reasonOf(line) {
|
|
429
451
|
const m = line?.match(OK);
|
|
430
452
|
return m ? m[1].replace(/\*\/|-->|[{}]/g, "").trim() : null;
|
|
431
453
|
}
|
|
432
|
-
function scanPhoneFirst(files, exceptions = []) {
|
|
454
|
+
function scanPhoneFirst(files, exceptions = [], options = {}) {
|
|
433
455
|
const excusedFiles = new Set(exceptions.filter((e) => e.reason?.trim()).map((e) => e.file));
|
|
434
456
|
const findings = [];
|
|
435
457
|
let excused = 0;
|
|
@@ -444,7 +466,18 @@ function scanPhoneFirst(files, exceptions = []) {
|
|
|
444
466
|
for (const m of text.matchAll(VARIANT)) {
|
|
445
467
|
if (!NOT_VARIANTS.has(m[1])) found.push({ line: lineOf(m.index), what: m[0] });
|
|
446
468
|
}
|
|
447
|
-
|
|
469
|
+
const silent = /* @__PURE__ */ new Set();
|
|
470
|
+
if (options.tailwind3?.(path)) {
|
|
471
|
+
for (const m of text.matchAll(VAR_OPACITY)) {
|
|
472
|
+
silent.add(found.push({ line: lineOf(m.index), what: `${m[0]} (Tailwind 3 emits no CSS for opacity on a var() colour)` }) - 1);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const order = found.map((f, i) => ({ ...f, silent: silent.has(i) })).sort((a, b) => a.line - b.line);
|
|
476
|
+
for (const { line, what, silent: cannotExcuse } of order) {
|
|
477
|
+
if (cannotExcuse) {
|
|
478
|
+
findings.push({ file: path, line, what });
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
448
481
|
const here = reasonOf(lines[line - 1]);
|
|
449
482
|
const above = reasonOf(lines[line - 2]);
|
|
450
483
|
if (here || above) {
|
|
@@ -549,17 +582,101 @@ var LABEL = {
|
|
|
549
582
|
tel: "phone number is not a link",
|
|
550
583
|
linelength: "line too long"
|
|
551
584
|
};
|
|
552
|
-
function writeBaseline(findings, routes, note) {
|
|
585
|
+
function writeBaseline(findings, routes, note, previous) {
|
|
553
586
|
const byFile = tally(findings, (f) => f.file);
|
|
554
587
|
const measured = routes.flatMap(
|
|
555
588
|
({ route, findings: findings2 }) => [...tally(findings2, (f) => measuredKey(route, f.check, normaliseElement(f.element))).values()].map(({ item, count }) => ({ route, check: item.check, element: normaliseElement(item.element), count }))
|
|
556
589
|
);
|
|
590
|
+
const staticReasons = new Map((previous?.static ?? []).filter(hasReason).map((b) => [b.file, b.reason]));
|
|
591
|
+
const measuredReasons = new Map((previous?.measured ?? []).filter(hasReason).map((b) => [measuredKey(b.route, b.check, b.element), b.reason]));
|
|
557
592
|
return {
|
|
558
593
|
...note ? { note } : {},
|
|
559
|
-
static: [...byFile.values()].map(({ item, count }) => ({ file: item.file, count, found: findings.filter((f) => f.file === item.file).map((f) => f.what) })).sort((a, b) => a.file.localeCompare(b.file)),
|
|
560
|
-
measured: measured.sort((a, b) => a.route.localeCompare(b.route) || a.check.localeCompare(b.check) || a.element.localeCompare(b.element))
|
|
594
|
+
static: [...byFile.values()].map(({ item, count }) => ({ file: item.file, count, found: findings.filter((f) => f.file === item.file).map((f) => f.what), ...staticReasons.has(item.file) ? { reason: staticReasons.get(item.file) } : {} })).sort((a, b) => a.file.localeCompare(b.file)),
|
|
595
|
+
measured: measured.map((m) => measuredReasons.has(measuredKey(m.route, m.check, m.element)) ? { ...m, reason: measuredReasons.get(measuredKey(m.route, m.check, m.element)) } : m).sort((a, b) => a.route.localeCompare(b.route) || a.check.localeCompare(b.check) || a.element.localeCompare(b.element))
|
|
561
596
|
};
|
|
562
597
|
}
|
|
598
|
+
function judgeGrowth(current, base, baseName = "main") {
|
|
599
|
+
const out = [];
|
|
600
|
+
const baseStatic = new Map(base.static.map((b) => [b.file, b.count]));
|
|
601
|
+
for (const b of current.static) {
|
|
602
|
+
const was = baseStatic.get(b.file) ?? 0;
|
|
603
|
+
if (b.count > was && !hasReason(b)) out.push(`${b.file}: ${was ? `${b.count} desktop-first rules, ${baseName} allows ${was}` : `${b.count} desktop-first rule${b.count === 1 ? "" : "s"} added to the baseline`}`);
|
|
604
|
+
}
|
|
605
|
+
const baseMeasured = new Map(base.measured.map((b) => [measuredKey(b.route, b.check, b.element), b.count]));
|
|
606
|
+
for (const b of current.measured) {
|
|
607
|
+
const was = baseMeasured.get(measuredKey(b.route, b.check, b.element)) ?? 0;
|
|
608
|
+
if (b.count > was && !hasReason(b)) out.push(`${b.route}: ${LABEL[b.check]} ${b.element}: ${was ? `${b.count} in the baseline, ${baseName} allows ${was}` : `added to the baseline (${b.count})`}`);
|
|
609
|
+
}
|
|
610
|
+
return out;
|
|
611
|
+
}
|
|
612
|
+
var hasUnexcusedEntries = (b) => [...b.static, ...b.measured].some((e) => !hasReason(e));
|
|
613
|
+
var PAGE_FILE = /(?:^|\/)page\.(?:tsx|ts|jsx|js|mdx)$/;
|
|
614
|
+
var INTERCEPTING = /^\(\.{1,3}\)/;
|
|
615
|
+
function routesFromPages(files) {
|
|
616
|
+
const routes = /* @__PURE__ */ new Set();
|
|
617
|
+
for (const file of files) {
|
|
618
|
+
const rel = file.replace(/\\/g, "/");
|
|
619
|
+
if (!PAGE_FILE.test(rel)) continue;
|
|
620
|
+
const dirs = rel.split("/").slice(0, -1);
|
|
621
|
+
if (dirs.some((d) => INTERCEPTING.test(d) || d.startsWith("_"))) continue;
|
|
622
|
+
const url = dirs.filter((d) => !/^\(.*\)$/.test(d) && !d.startsWith("@"));
|
|
623
|
+
routes.add(`/${url.join("/")}`);
|
|
624
|
+
}
|
|
625
|
+
return [...routes].sort();
|
|
626
|
+
}
|
|
627
|
+
function routesFromManifest(manifest) {
|
|
628
|
+
const routes = /* @__PURE__ */ new Set();
|
|
629
|
+
for (const [key, route] of Object.entries(manifest ?? {})) {
|
|
630
|
+
if (!/(?:^|\/)page$/.test(key) || typeof route !== "string") continue;
|
|
631
|
+
if (route.split("/").some((d) => d.startsWith("_"))) continue;
|
|
632
|
+
routes.add(route);
|
|
633
|
+
}
|
|
634
|
+
return [...routes].sort();
|
|
635
|
+
}
|
|
636
|
+
var segmentsOf = (route) => route.split("/").filter(Boolean);
|
|
637
|
+
var rank = (seg) => seg.startsWith("[[...") ? 3 : seg.startsWith("[...") ? 2 : seg.startsWith("[") ? 1 : 0;
|
|
638
|
+
var cleanRoute = (route) => {
|
|
639
|
+
const path = route.replace(/[?#].*$/, "").replace(/\/+$/, "");
|
|
640
|
+
return path === "" ? "/" : path;
|
|
641
|
+
};
|
|
642
|
+
function routeMatches(pattern, route) {
|
|
643
|
+
if (pattern === route) return true;
|
|
644
|
+
const want = segmentsOf(pattern);
|
|
645
|
+
const have = segmentsOf(route);
|
|
646
|
+
for (let i = 0; i < want.length; i++) {
|
|
647
|
+
const seg = want[i];
|
|
648
|
+
if (seg.startsWith("[[...")) return true;
|
|
649
|
+
if (seg.startsWith("[...")) return have.length > i;
|
|
650
|
+
if (have[i] === void 0) return false;
|
|
651
|
+
if (!seg.startsWith("[") && seg !== have[i]) return false;
|
|
652
|
+
}
|
|
653
|
+
return want.length === have.length;
|
|
654
|
+
}
|
|
655
|
+
var moreSpecific = (a, b) => {
|
|
656
|
+
const x = segmentsOf(a).map(rank);
|
|
657
|
+
const y = segmentsOf(b).map(rank);
|
|
658
|
+
for (let i = 0; i < Math.min(x.length, y.length); i++) if (x[i] !== y[i]) return x[i] < y[i];
|
|
659
|
+
return x.length > y.length;
|
|
660
|
+
};
|
|
661
|
+
var excludes = (entry, page) => entry.endsWith("/*") ? page === entry.slice(0, -2) || page.startsWith(entry.slice(0, -1)) : entry === page;
|
|
662
|
+
function judgeRoutes(pages, measuredRoutes, excluded = []) {
|
|
663
|
+
const problems = [];
|
|
664
|
+
excluded.forEach((e, i) => {
|
|
665
|
+
const at = `excludeRoutes[${i}]`;
|
|
666
|
+
const x = e;
|
|
667
|
+
if (typeof x?.route !== "string" || !x.route.startsWith("/")) problems.push(`${at}: names no route (start it with /)`);
|
|
668
|
+
else if (typeof x.reason !== "string" || !x.reason.trim()) problems.push(`${at} (${x.route}): no reason. Say why the gate cannot measure this page, or remove the entry.`);
|
|
669
|
+
else if (!pages.some((p) => excludes(x.route, p))) problems.push(`${at}: ${x.route} is not a page route of the app. Remove the entry.`);
|
|
670
|
+
});
|
|
671
|
+
const named = excluded.filter((e) => typeof e?.route === "string" && typeof e.reason === "string" && e.reason.trim());
|
|
672
|
+
const covered = /* @__PURE__ */ new Set();
|
|
673
|
+
for (const route of measuredRoutes.map(cleanRoute)) {
|
|
674
|
+
const hit = pages.filter((p) => routeMatches(p, route)).sort((a, b) => moreSpecific(a, b) ? -1 : moreSpecific(b, a) ? 1 : 0)[0];
|
|
675
|
+
if (hit) covered.add(hit);
|
|
676
|
+
}
|
|
677
|
+
for (const page of pages) if (named.some((e) => excludes(e.route, page))) covered.add(page);
|
|
678
|
+
return { missing: pages.filter((p) => !covered.has(p)), problems, covered: covered.size };
|
|
679
|
+
}
|
|
563
680
|
|
|
564
681
|
// src/phone/viewports.ts
|
|
565
682
|
var BANDS = [
|
|
@@ -603,16 +720,16 @@ var DEFAULT_THRESHOLDS = {
|
|
|
603
720
|
var mainActionFor = (config, route) => typeof config === "string" ? config : config ? config[route] ?? config["*"] : void 0;
|
|
604
721
|
function formatWidths(failing, tested) {
|
|
605
722
|
const plain = tested.filter((n) => /^\d+$/.test(n)).sort((a, b) => Number(a) - Number(b));
|
|
606
|
-
const
|
|
723
|
+
const rank2 = new Map(plain.map((name, i) => [name, i]));
|
|
607
724
|
const names = [...new Set(failing)];
|
|
608
725
|
const runs = [];
|
|
609
|
-
for (const name of names.filter((n) =>
|
|
726
|
+
for (const name of names.filter((n) => rank2.has(n)).sort((a, b) => rank2.get(a) - rank2.get(b))) {
|
|
610
727
|
const last = runs.at(-1);
|
|
611
|
-
if (last &&
|
|
728
|
+
if (last && rank2.get(name) === rank2.get(last.at(-1)) + 1) last.push(name);
|
|
612
729
|
else runs.push([name]);
|
|
613
730
|
}
|
|
614
731
|
const out = runs.map((r) => r.length > 1 ? `${r[0]}-${r.at(-1)}` : r[0]);
|
|
615
|
-
return [...out, ...names.filter((n) => !
|
|
732
|
+
return [...out, ...names.filter((n) => !rank2.has(n))].join(", ");
|
|
616
733
|
}
|
|
617
734
|
var keyOf = (f) => `${f.check}\0${f.element.replace(/("[^]*)$/, (t) => t.replace(/\d+/g, "#"))}`;
|
|
618
735
|
function mergeViewportFindings(perViewport, tested) {
|
|
@@ -777,7 +894,7 @@ async function measureSite(browser, options) {
|
|
|
777
894
|
async function measurePhone(page, options) {
|
|
778
895
|
if (!options.route.startsWith("/")) throw new Error(`measurePhone: route "${options.route}" should start with /`);
|
|
779
896
|
await page.evaluate(() => document.fonts?.ready.then(() => void 0), void 0);
|
|
780
|
-
const findings = await page.evaluate(measurePhoneInPage, PHONE_FLOORS);
|
|
897
|
+
const findings = await page.evaluate(measurePhoneInPage, { ...PHONE_FLOORS, ...options.floors ?? {} });
|
|
781
898
|
const viewport = page.viewportSize?.() ?? void 0;
|
|
782
899
|
const result = { route: options.route, ...viewport ? { viewport } : {}, findings };
|
|
783
900
|
const dir = options.out ?? DEFAULT_MEASURED_DIR;
|
|
@@ -801,8 +918,13 @@ async function measurePhone(page, options) {
|
|
|
801
918
|
WIDE_WIDTHS,
|
|
802
919
|
bandOf,
|
|
803
920
|
checkExceptions,
|
|
921
|
+
cleanRoute,
|
|
804
922
|
formatWidths,
|
|
923
|
+
hasReason,
|
|
924
|
+
hasUnexcusedEntries,
|
|
925
|
+
judgeGrowth,
|
|
805
926
|
judgeMeasured,
|
|
927
|
+
judgeRoutes,
|
|
806
928
|
judgeStatic,
|
|
807
929
|
mainActionFor,
|
|
808
930
|
measurePhone,
|
|
@@ -813,8 +935,12 @@ async function measurePhone(page, options) {
|
|
|
813
935
|
measureViewports,
|
|
814
936
|
mergeViewportFindings,
|
|
815
937
|
normaliseElement,
|
|
938
|
+
parseBaseline,
|
|
816
939
|
reasonOf,
|
|
817
940
|
routeFile,
|
|
941
|
+
routeMatches,
|
|
942
|
+
routesFromManifest,
|
|
943
|
+
routesFromPages,
|
|
818
944
|
scanPhoneFirst,
|
|
819
945
|
sweepWidths,
|
|
820
946
|
writeBaseline
|
package/dist/phone.d.cts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
interface SourceFile {
|
|
2
|
-
/** Repo-relative path. The extension decides how the file is read. */
|
|
3
|
-
path: string;
|
|
4
|
-
text: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* The in-page half of the phone-first gate.
|
|
9
3
|
*
|
|
@@ -23,6 +17,12 @@ interface PhoneFloors {
|
|
|
23
17
|
targetPx: number;
|
|
24
18
|
fieldFontPx: number;
|
|
25
19
|
textPx: number;
|
|
20
|
+
/**
|
|
21
|
+
* The height of a text field, select or textarea (portal standard rule 5:
|
|
22
|
+
* 48px inputs). Left out, 48. Below `targetPx` the field also fails the
|
|
23
|
+
* target check; this floor is what catches 44 to 47px.
|
|
24
|
+
*/
|
|
25
|
+
fieldHeightPx?: number;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* What a measure can find. The first five are the 375px floors (DOM-775); the
|
|
@@ -44,6 +44,12 @@ declare function measurePhoneInPage(floors: PhoneFloors & {
|
|
|
44
44
|
only?: PhoneCheck[];
|
|
45
45
|
}): RawPhoneFinding[];
|
|
46
46
|
|
|
47
|
+
interface SourceFile {
|
|
48
|
+
/** Repo-relative path. The extension decides how the file is read. */
|
|
49
|
+
path: string;
|
|
50
|
+
text: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* The judging half of the phone-first gate: pure text work, tested without a
|
|
49
55
|
* browser or a disk.
|
|
@@ -62,6 +68,11 @@ declare function measurePhoneInPage(floors: PhoneFloors & {
|
|
|
62
68
|
* the day it goes in while the existing ones stay listed in the open. The
|
|
63
69
|
* baseline only shrinks: a count higher than what is found fails as well
|
|
64
70
|
* ("lower the baseline"), so a fix cannot leave room for the next breach.
|
|
71
|
+
*
|
|
72
|
+
* Shrinking is also enforced against the base branch (DOM-1053): a baseline
|
|
73
|
+
* entry, or a higher count, that main's copy does not have fails, unless the
|
|
74
|
+
* entry carries a `reason` (a named exception: third-party UI, a
|
|
75
|
+
* destructive-only form).
|
|
65
76
|
*/
|
|
66
77
|
|
|
67
78
|
interface StaticFinding {
|
|
@@ -86,18 +97,30 @@ interface MeasuredRoute {
|
|
|
86
97
|
interface Baseline {
|
|
87
98
|
/** Why the baseline exists and which issue burns it down. Free text, for a person. */
|
|
88
99
|
note?: string;
|
|
100
|
+
/**
|
|
101
|
+
* `reason` makes an entry a named exception: it may be added, or raised,
|
|
102
|
+
* after the baseline went in. Absent on the faults that were there first.
|
|
103
|
+
*/
|
|
89
104
|
static: {
|
|
90
105
|
file: string;
|
|
91
106
|
count: number;
|
|
92
107
|
found?: string[];
|
|
108
|
+
reason?: string;
|
|
93
109
|
}[];
|
|
94
110
|
measured: {
|
|
95
111
|
route: string;
|
|
96
112
|
check: PhoneCheck;
|
|
97
113
|
element: string;
|
|
98
114
|
count: number;
|
|
115
|
+
reason?: string;
|
|
99
116
|
}[];
|
|
100
117
|
}
|
|
118
|
+
/** An entry is a named exception when its `reason` says something. */
|
|
119
|
+
declare const hasReason: (entry: {
|
|
120
|
+
reason?: unknown;
|
|
121
|
+
}) => boolean;
|
|
122
|
+
/** A baseline file, read. Old files (no `reason`, no `note`) read as before; a `reason` that is not text is an error. */
|
|
123
|
+
declare function parseBaseline(raw: unknown, where: string): Baseline;
|
|
101
124
|
declare const EMPTY_BASELINE: Baseline;
|
|
102
125
|
/** The reason in a `mobile-first-ok: <reason>` comment, "" for the marker with no reason, null for none. */
|
|
103
126
|
declare function reasonOf(line: string | undefined): string | null;
|
|
@@ -106,7 +129,10 @@ declare function reasonOf(line: string | undefined): string | null;
|
|
|
106
129
|
* `mobile-first-ok: <reason>` on the line or the line above, or the whole file
|
|
107
130
|
* in `exceptions` with a reason. A marker with no reason is itself a finding.
|
|
108
131
|
*/
|
|
109
|
-
declare function scanPhoneFirst(files: SourceFile[], exceptions?: FileException[]
|
|
132
|
+
declare function scanPhoneFirst(files: SourceFile[], exceptions?: FileException[], options?: {
|
|
133
|
+
/** True for a file in an app whose tailwindcss is v3: it is also scanned for `/NN` opacity on a `var()` colour. */
|
|
134
|
+
tailwind3?: (path: string) => boolean;
|
|
135
|
+
}): {
|
|
110
136
|
findings: StaticFinding[];
|
|
111
137
|
excused: number;
|
|
112
138
|
};
|
|
@@ -128,7 +154,48 @@ interface Judgement {
|
|
|
128
154
|
declare function judgeStatic(findings: StaticFinding[], baseline: Baseline): Judgement;
|
|
129
155
|
declare function judgeMeasured(routes: MeasuredRoute[], baseline: Baseline): Judgement;
|
|
130
156
|
/** The baseline that makes this run pass: what is there now, counted. */
|
|
131
|
-
declare function writeBaseline(findings: StaticFinding[], routes: MeasuredRoute[], note?: string): Baseline;
|
|
157
|
+
declare function writeBaseline(findings: StaticFinding[], routes: MeasuredRoute[], note?: string, previous?: Baseline): Baseline;
|
|
158
|
+
/**
|
|
159
|
+
* Entries the baseline holds that the base branch's copy does not, or holds
|
|
160
|
+
* at a lower count, and that name no reason. The baseline lists the faults
|
|
161
|
+
* that were there when the gate arrived; a new breach is fixed where it is.
|
|
162
|
+
* An entry with a `reason` is a named exception and may be added or raised.
|
|
163
|
+
*/
|
|
164
|
+
declare function judgeGrowth(current: Baseline, base: Baseline, baseName?: string): string[];
|
|
165
|
+
/** Whether the baseline holds anything a reason does not name: only then is the base branch's copy needed. */
|
|
166
|
+
declare const hasUnexcusedEntries: (b: Baseline) => boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Page routes from the page files of a Next app directory, as paths relative
|
|
169
|
+
* to it (`portal/(shell)/invoices/[id]/page.tsx`). Route groups `(x)`, parallel
|
|
170
|
+
* slots `@x` and private folders `_x` are not part of the URL; an intercepting
|
|
171
|
+
* route `(.)x` is a second way into a page, not a page of its own.
|
|
172
|
+
*/
|
|
173
|
+
declare function routesFromPages(files: string[]): string[];
|
|
174
|
+
/** Page routes from Next's `app-path-routes-manifest.json` (`{ "/portal/page": "/portal" }`). Route handlers and internal `_` routes are not pages. */
|
|
175
|
+
declare function routesFromManifest(manifest: unknown): string[];
|
|
176
|
+
interface ExcludedRoute {
|
|
177
|
+
route: string;
|
|
178
|
+
reason: string;
|
|
179
|
+
}
|
|
180
|
+
/** A route as the gate names it: no query, no hash, no trailing slash. */
|
|
181
|
+
declare const cleanRoute: (route: string) => string;
|
|
182
|
+
/** Whether a measured route (`/portal/projects/p1`, or the pattern itself) is a page route (`/portal/projects/[id]`). */
|
|
183
|
+
declare function routeMatches(pattern: string, route: string): boolean;
|
|
184
|
+
interface RouteJudgement {
|
|
185
|
+
/** Page routes nothing measured and no exclusion covers: the gate fails on these. */
|
|
186
|
+
missing: string[];
|
|
187
|
+
/** Problems with `excludeRoutes` itself: no reason, or names no page. */
|
|
188
|
+
problems: string[];
|
|
189
|
+
/** Pages measured or excluded with a reason. */
|
|
190
|
+
covered: number;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Every page route of the app is in the gate's route list. A measured route
|
|
194
|
+
* counts for the most specific page it matches, so `/portal/projects/new` does
|
|
195
|
+
* not cover `/portal/projects/[id]`. A page that only redirects measures
|
|
196
|
+
* nothing: it is excluded with that reason.
|
|
197
|
+
*/
|
|
198
|
+
declare function judgeRoutes(pages: string[], measuredRoutes: string[], excluded?: ExcludedRoute[]): RouteJudgement;
|
|
132
199
|
|
|
133
200
|
/**
|
|
134
201
|
* What "every viewport" means (STANDARD.md section 10, DOM-787): the ladder
|
|
@@ -263,8 +330,13 @@ declare const PHONE: {
|
|
|
263
330
|
readonly isMobile: true;
|
|
264
331
|
readonly hasTouch: true;
|
|
265
332
|
};
|
|
266
|
-
/**
|
|
267
|
-
|
|
333
|
+
/**
|
|
334
|
+
* The house floors at phone width. A site may raise `textPx`, or lower
|
|
335
|
+
* `fieldHeightPx` with a reason; they are not per-repo taste. The field height
|
|
336
|
+
* is portal standard rule 5 (48px inputs); until DOM-1053 the gate held fields
|
|
337
|
+
* to the 44px target floor only.
|
|
338
|
+
*/
|
|
339
|
+
declare const PHONE_FLOORS: Required<PhoneFloors>;
|
|
268
340
|
/** Where `measurePhone` writes and `craft phone-first --measured` reads, unless told otherwise. */
|
|
269
341
|
declare const DEFAULT_MEASURED_DIR = "phone-first/measured";
|
|
270
342
|
/** A route as a file name: `/portal/invoices` is `portal-invoices.json`, `/` is `home.json`. */
|
|
@@ -309,7 +381,7 @@ interface MeasureViewportsOptions {
|
|
|
309
381
|
scope?: "all" | "phone" | "wide";
|
|
310
382
|
/** Override house thresholds. */
|
|
311
383
|
thresholds?: Partial<Thresholds>;
|
|
312
|
-
/** Override the 12 / 16 / 44px floors. The defaults are the house standard; a site may set `textPx` higher. */
|
|
384
|
+
/** Override the 12 / 16 / 44px floors and the 48px field height (`fieldHeightPx`). The defaults are the house standard; a site may set `textPx` higher. */
|
|
313
385
|
floors?: Partial<PhoneFloors>;
|
|
314
386
|
/** The main action's selector: one for all routes, or per route with `*` as the fallback. Absent: not checked. */
|
|
315
387
|
mainAction?: MainAction;
|
|
@@ -440,6 +512,8 @@ interface MeasurePhoneOptions {
|
|
|
440
512
|
route: string;
|
|
441
513
|
/** The folder to write `<route>.json` into. Default `phone-first/measured`, from the working directory. */
|
|
442
514
|
out?: string;
|
|
515
|
+
/** Override the 12 / 16 / 44 / 48px floors (text, field text, target, field height). The defaults are the house standard. */
|
|
516
|
+
floors?: Partial<PhoneFloors>;
|
|
443
517
|
}
|
|
444
518
|
/**
|
|
445
519
|
* Measure the page as it is now and write the result for `craft phone-first`.
|
|
@@ -448,4 +522,4 @@ interface MeasurePhoneOptions {
|
|
|
448
522
|
*/
|
|
449
523
|
declare function measurePhone(page: MinimalPage, options: MeasurePhoneOptions): Promise<MeasuredRoute>;
|
|
450
524
|
|
|
451
|
-
export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, DESKTOP, EMPTY_BASELINE, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, type OpenedPage, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, formatWidths, judgeMeasured, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureRoute, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, reasonOf, routeFile, scanPhoneFirst, sweepWidths, writeBaseline };
|
|
525
|
+
export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, DESKTOP, EMPTY_BASELINE, type ExcludedRoute, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, type OpenedPage, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, type RouteJudgement, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, cleanRoute, formatWidths, hasReason, hasUnexcusedEntries, judgeGrowth, judgeMeasured, judgeRoutes, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureRoute, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, parseBaseline, reasonOf, routeFile, routeMatches, routesFromManifest, routesFromPages, scanPhoneFirst, sweepWidths, writeBaseline };
|
package/dist/phone.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
interface SourceFile {
|
|
2
|
-
/** Repo-relative path. The extension decides how the file is read. */
|
|
3
|
-
path: string;
|
|
4
|
-
text: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* The in-page half of the phone-first gate.
|
|
9
3
|
*
|
|
@@ -23,6 +17,12 @@ interface PhoneFloors {
|
|
|
23
17
|
targetPx: number;
|
|
24
18
|
fieldFontPx: number;
|
|
25
19
|
textPx: number;
|
|
20
|
+
/**
|
|
21
|
+
* The height of a text field, select or textarea (portal standard rule 5:
|
|
22
|
+
* 48px inputs). Left out, 48. Below `targetPx` the field also fails the
|
|
23
|
+
* target check; this floor is what catches 44 to 47px.
|
|
24
|
+
*/
|
|
25
|
+
fieldHeightPx?: number;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* What a measure can find. The first five are the 375px floors (DOM-775); the
|
|
@@ -44,6 +44,12 @@ declare function measurePhoneInPage(floors: PhoneFloors & {
|
|
|
44
44
|
only?: PhoneCheck[];
|
|
45
45
|
}): RawPhoneFinding[];
|
|
46
46
|
|
|
47
|
+
interface SourceFile {
|
|
48
|
+
/** Repo-relative path. The extension decides how the file is read. */
|
|
49
|
+
path: string;
|
|
50
|
+
text: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* The judging half of the phone-first gate: pure text work, tested without a
|
|
49
55
|
* browser or a disk.
|
|
@@ -62,6 +68,11 @@ declare function measurePhoneInPage(floors: PhoneFloors & {
|
|
|
62
68
|
* the day it goes in while the existing ones stay listed in the open. The
|
|
63
69
|
* baseline only shrinks: a count higher than what is found fails as well
|
|
64
70
|
* ("lower the baseline"), so a fix cannot leave room for the next breach.
|
|
71
|
+
*
|
|
72
|
+
* Shrinking is also enforced against the base branch (DOM-1053): a baseline
|
|
73
|
+
* entry, or a higher count, that main's copy does not have fails, unless the
|
|
74
|
+
* entry carries a `reason` (a named exception: third-party UI, a
|
|
75
|
+
* destructive-only form).
|
|
65
76
|
*/
|
|
66
77
|
|
|
67
78
|
interface StaticFinding {
|
|
@@ -86,18 +97,30 @@ interface MeasuredRoute {
|
|
|
86
97
|
interface Baseline {
|
|
87
98
|
/** Why the baseline exists and which issue burns it down. Free text, for a person. */
|
|
88
99
|
note?: string;
|
|
100
|
+
/**
|
|
101
|
+
* `reason` makes an entry a named exception: it may be added, or raised,
|
|
102
|
+
* after the baseline went in. Absent on the faults that were there first.
|
|
103
|
+
*/
|
|
89
104
|
static: {
|
|
90
105
|
file: string;
|
|
91
106
|
count: number;
|
|
92
107
|
found?: string[];
|
|
108
|
+
reason?: string;
|
|
93
109
|
}[];
|
|
94
110
|
measured: {
|
|
95
111
|
route: string;
|
|
96
112
|
check: PhoneCheck;
|
|
97
113
|
element: string;
|
|
98
114
|
count: number;
|
|
115
|
+
reason?: string;
|
|
99
116
|
}[];
|
|
100
117
|
}
|
|
118
|
+
/** An entry is a named exception when its `reason` says something. */
|
|
119
|
+
declare const hasReason: (entry: {
|
|
120
|
+
reason?: unknown;
|
|
121
|
+
}) => boolean;
|
|
122
|
+
/** A baseline file, read. Old files (no `reason`, no `note`) read as before; a `reason` that is not text is an error. */
|
|
123
|
+
declare function parseBaseline(raw: unknown, where: string): Baseline;
|
|
101
124
|
declare const EMPTY_BASELINE: Baseline;
|
|
102
125
|
/** The reason in a `mobile-first-ok: <reason>` comment, "" for the marker with no reason, null for none. */
|
|
103
126
|
declare function reasonOf(line: string | undefined): string | null;
|
|
@@ -106,7 +129,10 @@ declare function reasonOf(line: string | undefined): string | null;
|
|
|
106
129
|
* `mobile-first-ok: <reason>` on the line or the line above, or the whole file
|
|
107
130
|
* in `exceptions` with a reason. A marker with no reason is itself a finding.
|
|
108
131
|
*/
|
|
109
|
-
declare function scanPhoneFirst(files: SourceFile[], exceptions?: FileException[]
|
|
132
|
+
declare function scanPhoneFirst(files: SourceFile[], exceptions?: FileException[], options?: {
|
|
133
|
+
/** True for a file in an app whose tailwindcss is v3: it is also scanned for `/NN` opacity on a `var()` colour. */
|
|
134
|
+
tailwind3?: (path: string) => boolean;
|
|
135
|
+
}): {
|
|
110
136
|
findings: StaticFinding[];
|
|
111
137
|
excused: number;
|
|
112
138
|
};
|
|
@@ -128,7 +154,48 @@ interface Judgement {
|
|
|
128
154
|
declare function judgeStatic(findings: StaticFinding[], baseline: Baseline): Judgement;
|
|
129
155
|
declare function judgeMeasured(routes: MeasuredRoute[], baseline: Baseline): Judgement;
|
|
130
156
|
/** The baseline that makes this run pass: what is there now, counted. */
|
|
131
|
-
declare function writeBaseline(findings: StaticFinding[], routes: MeasuredRoute[], note?: string): Baseline;
|
|
157
|
+
declare function writeBaseline(findings: StaticFinding[], routes: MeasuredRoute[], note?: string, previous?: Baseline): Baseline;
|
|
158
|
+
/**
|
|
159
|
+
* Entries the baseline holds that the base branch's copy does not, or holds
|
|
160
|
+
* at a lower count, and that name no reason. The baseline lists the faults
|
|
161
|
+
* that were there when the gate arrived; a new breach is fixed where it is.
|
|
162
|
+
* An entry with a `reason` is a named exception and may be added or raised.
|
|
163
|
+
*/
|
|
164
|
+
declare function judgeGrowth(current: Baseline, base: Baseline, baseName?: string): string[];
|
|
165
|
+
/** Whether the baseline holds anything a reason does not name: only then is the base branch's copy needed. */
|
|
166
|
+
declare const hasUnexcusedEntries: (b: Baseline) => boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Page routes from the page files of a Next app directory, as paths relative
|
|
169
|
+
* to it (`portal/(shell)/invoices/[id]/page.tsx`). Route groups `(x)`, parallel
|
|
170
|
+
* slots `@x` and private folders `_x` are not part of the URL; an intercepting
|
|
171
|
+
* route `(.)x` is a second way into a page, not a page of its own.
|
|
172
|
+
*/
|
|
173
|
+
declare function routesFromPages(files: string[]): string[];
|
|
174
|
+
/** Page routes from Next's `app-path-routes-manifest.json` (`{ "/portal/page": "/portal" }`). Route handlers and internal `_` routes are not pages. */
|
|
175
|
+
declare function routesFromManifest(manifest: unknown): string[];
|
|
176
|
+
interface ExcludedRoute {
|
|
177
|
+
route: string;
|
|
178
|
+
reason: string;
|
|
179
|
+
}
|
|
180
|
+
/** A route as the gate names it: no query, no hash, no trailing slash. */
|
|
181
|
+
declare const cleanRoute: (route: string) => string;
|
|
182
|
+
/** Whether a measured route (`/portal/projects/p1`, or the pattern itself) is a page route (`/portal/projects/[id]`). */
|
|
183
|
+
declare function routeMatches(pattern: string, route: string): boolean;
|
|
184
|
+
interface RouteJudgement {
|
|
185
|
+
/** Page routes nothing measured and no exclusion covers: the gate fails on these. */
|
|
186
|
+
missing: string[];
|
|
187
|
+
/** Problems with `excludeRoutes` itself: no reason, or names no page. */
|
|
188
|
+
problems: string[];
|
|
189
|
+
/** Pages measured or excluded with a reason. */
|
|
190
|
+
covered: number;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Every page route of the app is in the gate's route list. A measured route
|
|
194
|
+
* counts for the most specific page it matches, so `/portal/projects/new` does
|
|
195
|
+
* not cover `/portal/projects/[id]`. A page that only redirects measures
|
|
196
|
+
* nothing: it is excluded with that reason.
|
|
197
|
+
*/
|
|
198
|
+
declare function judgeRoutes(pages: string[], measuredRoutes: string[], excluded?: ExcludedRoute[]): RouteJudgement;
|
|
132
199
|
|
|
133
200
|
/**
|
|
134
201
|
* What "every viewport" means (STANDARD.md section 10, DOM-787): the ladder
|
|
@@ -263,8 +330,13 @@ declare const PHONE: {
|
|
|
263
330
|
readonly isMobile: true;
|
|
264
331
|
readonly hasTouch: true;
|
|
265
332
|
};
|
|
266
|
-
/**
|
|
267
|
-
|
|
333
|
+
/**
|
|
334
|
+
* The house floors at phone width. A site may raise `textPx`, or lower
|
|
335
|
+
* `fieldHeightPx` with a reason; they are not per-repo taste. The field height
|
|
336
|
+
* is portal standard rule 5 (48px inputs); until DOM-1053 the gate held fields
|
|
337
|
+
* to the 44px target floor only.
|
|
338
|
+
*/
|
|
339
|
+
declare const PHONE_FLOORS: Required<PhoneFloors>;
|
|
268
340
|
/** Where `measurePhone` writes and `craft phone-first --measured` reads, unless told otherwise. */
|
|
269
341
|
declare const DEFAULT_MEASURED_DIR = "phone-first/measured";
|
|
270
342
|
/** A route as a file name: `/portal/invoices` is `portal-invoices.json`, `/` is `home.json`. */
|
|
@@ -309,7 +381,7 @@ interface MeasureViewportsOptions {
|
|
|
309
381
|
scope?: "all" | "phone" | "wide";
|
|
310
382
|
/** Override house thresholds. */
|
|
311
383
|
thresholds?: Partial<Thresholds>;
|
|
312
|
-
/** Override the 12 / 16 / 44px floors. The defaults are the house standard; a site may set `textPx` higher. */
|
|
384
|
+
/** Override the 12 / 16 / 44px floors and the 48px field height (`fieldHeightPx`). The defaults are the house standard; a site may set `textPx` higher. */
|
|
313
385
|
floors?: Partial<PhoneFloors>;
|
|
314
386
|
/** The main action's selector: one for all routes, or per route with `*` as the fallback. Absent: not checked. */
|
|
315
387
|
mainAction?: MainAction;
|
|
@@ -440,6 +512,8 @@ interface MeasurePhoneOptions {
|
|
|
440
512
|
route: string;
|
|
441
513
|
/** The folder to write `<route>.json` into. Default `phone-first/measured`, from the working directory. */
|
|
442
514
|
out?: string;
|
|
515
|
+
/** Override the 12 / 16 / 44 / 48px floors (text, field text, target, field height). The defaults are the house standard. */
|
|
516
|
+
floors?: Partial<PhoneFloors>;
|
|
443
517
|
}
|
|
444
518
|
/**
|
|
445
519
|
* Measure the page as it is now and write the result for `craft phone-first`.
|
|
@@ -448,4 +522,4 @@ interface MeasurePhoneOptions {
|
|
|
448
522
|
*/
|
|
449
523
|
declare function measurePhone(page: MinimalPage, options: MeasurePhoneOptions): Promise<MeasuredRoute>;
|
|
450
524
|
|
|
451
|
-
export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, DESKTOP, EMPTY_BASELINE, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, type OpenedPage, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, formatWidths, judgeMeasured, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureRoute, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, reasonOf, routeFile, scanPhoneFirst, sweepWidths, writeBaseline };
|
|
525
|
+
export { BANDS, type Band, type Baseline, DEFAULT_MEASURED_DIR, DEFAULT_SWEEP, DEFAULT_THRESHOLDS, DESKTOP, EMPTY_BASELINE, type ExcludedRoute, type FileException, type InPageGroup, type Judgement, LADDER, type MainAction, type MeasurePhoneOptions, type MeasureSiteOptions, type MeasureViewportsOptions, type MeasuredRoute, type OpenedPage, PHONE, PHONE_FLOORS, type PhoneCheck, type PhoneFloors, type RawPhoneFinding, type RouteJudgement, SHORT_PHONE, type SiteBrowser, type SitePage, type SiteResult, type StaticFinding, type Sweep, type Thresholds, type Viewport, type ViewportArg, type ViewportPage, type ViewportsResult, WIDE_WIDTHS, bandOf, checkExceptions, cleanRoute, formatWidths, hasReason, hasUnexcusedEntries, judgeGrowth, judgeMeasured, judgeRoutes, judgeStatic, mainActionFor, measurePhone, measurePhoneInPage, measureRoute, measureSite, measureViewportInPage, measureViewports, mergeViewportFindings, normaliseElement, parseBaseline, reasonOf, routeFile, routeMatches, routesFromManifest, routesFromPages, scanPhoneFirst, sweepWidths, writeBaseline };
|