@godxjp/ui 33.12.8 → 33.13.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/README.md +4 -0
- package/agent/START-HERE.md +1 -1
- package/agent/components/BranchScopePicker.json +21 -1
- package/agent/components/Breadcrumb.json +8 -2
- package/agent/components/DataTable.json +1 -1
- package/agent/components/MobileShell.json +1 -0
- package/agent/components/PageContainer.json +6 -0
- package/agent/components/Sidebar.json +1 -0
- package/agent/components/Table.json +1 -1
- package/agent/components.json +39 -5
- package/agent/index.json +3 -3
- package/agent/llms.txt +3 -3
- package/agent/tokens.json +2 -2
- package/agent/vocabulary.json +13 -0
- package/dist/components/data-entry/branch-scope-picker.d.ts +3 -0
- package/dist/components/data-entry/branch-scope-picker.js +65 -11
- package/dist/components/layout/breadcrumb-ellipsis.js +33 -1
- package/dist/components/layout/breadcrumb.d.ts +4 -2
- package/dist/components/layout/breadcrumb.js +13 -3
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +2 -1
- package/dist/i18n/messages/ja.json +13 -12
- package/dist/i18n/messages/vi.json +2 -1
- package/dist/props/components/data-entry.prop.d.ts +6 -0
- package/dist/props/components/layout.prop.d.ts +5 -1
- package/dist/props/registry.d.ts +19 -2
- package/dist/props/registry.js +21 -0
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/navigation.prop.d.ts +2 -0
- package/dist/styles/control.css +29 -3
- package/dist/styles/layers.json +3 -2
- package/dist/styles/table-layout.css +16 -4
- package/dist/styles.css +1 -1
- package/dist/tokens/components/table.css +1 -1
- package/docs/TOKENS.md +11 -0
- package/package.json +2 -2
- package/scripts/cli.mjs +8 -2
- package/scripts/visual-audit.mjs +119 -27
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
|
|
85
85
|
:root {
|
|
86
86
|
--table-stacked-collection-card-padding-y: var(--space-stack-sm);
|
|
87
|
-
--table-stacked-collection-card-padding-x:
|
|
87
|
+
--table-stacked-collection-card-padding-x: initial;
|
|
88
88
|
--table-stacked-collection-card-gap: var(--space-stack-sm);
|
|
89
89
|
--table-stacked-collection-cell-padding-y: var(--space-stack-xs);
|
|
90
90
|
|
package/docs/TOKENS.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Every visual dimension has **one canonical owner**. Apps never patch spacing, density, typography, or color ad hoc.
|
|
4
4
|
|
|
5
|
+
## Stacked records and calendar sizing
|
|
6
|
+
|
|
7
|
+
`--table-stacked-collection-card-padding-x` defaults to `initial`. At each stacked row it
|
|
8
|
+
resolves to `calc(var(--card-space-inset) - var(--stroke-hairline))`: the row border plus
|
|
9
|
+
padding lands on the CardTitle keyline. Scoped Card density and theme overrides therefore
|
|
10
|
+
remain live. Set the stacked token explicitly to choose an independent row padding.
|
|
11
|
+
|
|
12
|
+
Calendar columns retain the control-height tier at their natural width. In a narrow container,
|
|
13
|
+
the grid shares the available width between seven dates (the optional week-number label keeps its intrinsic measure),
|
|
14
|
+
keeping each date target at least `--touch-target-min`. `width="full"` retains its embedded sizing.
|
|
15
|
+
|
|
5
16
|
## Architecture
|
|
6
17
|
|
|
7
18
|
```
|
package/package.json
CHANGED
package/scripts/cli.mjs
CHANGED
|
@@ -106,7 +106,7 @@ const HELP = {
|
|
|
106
106
|
--dry-run list every change without writing
|
|
107
107
|
What it cannot decide (a component move that changes props, an AppProvider that relied on the
|
|
108
108
|
old vi default) is printed as a "note" for you to finish.`,
|
|
109
|
-
"visual-audit": `godxjp-ui visual-audit [--format json] [--strict] [--widths WxH,…] [--storage-state FILE] [--text-spacing] [--text-zoom 200] [--screenshots DIR] <baseUrl> [route …]
|
|
109
|
+
"visual-audit": `godxjp-ui visual-audit [--format json] [--strict] [--widths WxH,…] [--storage-state FILE] [--text-spacing] [--text-zoom 200] [--screenshots DIR] [--playwright-module PATH] [--executable-path CHROME] <baseUrl> [route …]
|
|
110
110
|
|
|
111
111
|
Runtime audit (Playwright) against an app you are ALREADY running locally, at six widths.
|
|
112
112
|
baseUrl the running app, e.g. http://localhost:5173
|
|
@@ -121,6 +121,11 @@ const HELP = {
|
|
|
121
121
|
Each reports the geometry delta against the unmodified render; a delta of
|
|
122
122
|
zero is an error ("override not applied"), never a pass
|
|
123
123
|
--screenshots a directory for the base + override render of each evidence mode
|
|
124
|
+
--playwright-module PATH
|
|
125
|
+
a playwright or playwright-core package dir (or its entry file) to use, e.g.
|
|
126
|
+
one in the npx cache. Without it: the playwright peer, then playwright-core
|
|
127
|
+
--executable-path CHROME
|
|
128
|
+
the Chromium/Chrome binary to launch (else PLAYWRIGHT_CHROMIUM_EXECUTABLE)
|
|
124
129
|
--strict exit non-zero on any finding, not only errors
|
|
125
130
|
--format json machine-readable: findings (viewport, element, threshold + origin), unmapped
|
|
126
131
|
items (reviewer required), per-width rule status + reviewer checklist
|
|
@@ -128,7 +133,8 @@ const HELP = {
|
|
|
128
133
|
Responsive probes C01–C12 are advisory; thresholds are repo-chosen unless marked WCAG. A clean
|
|
129
134
|
run ends "probes passed; independent acceptance pending" — the checklist still needs a reviewer.
|
|
130
135
|
Map your own components with data-audit-role (search, search-trigger, account-name, editor,
|
|
131
|
-
task-actions, rail-toggle, content-column, section-label, metadata). Needs the playwright peer
|
|
136
|
+
task-actions, rail-toggle, content-column, section-label, metadata). Needs the playwright peer
|
|
137
|
+
or playwright-core (--playwright-module).`,
|
|
132
138
|
};
|
|
133
139
|
|
|
134
140
|
const USAGE = `usage: godxjp-ui <command> [args]
|
package/scripts/visual-audit.mjs
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync, mkdirSync, realpathSync } from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { createRequire } from "node:module";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import {
|
|
10
11
|
VISUAL_RULES,
|
|
@@ -431,7 +432,7 @@ export const PROBE_RULES = [
|
|
|
431
432
|
category: "layout",
|
|
432
433
|
standard: `WCAG 2.2 SC 1.4.10 / 1.4.4 / 1.4.12; 1.5px tolerance ${RC}`,
|
|
433
434
|
kind: "probe",
|
|
434
|
-
fix: "Nothing may be cut off: no horizontal scroll on the document or the app's main region, and no text/icon partly hidden by an overflow:hidden/clip ancestor. Let the container shrink its content (min-width:0 + wrap), or truncate with a recoverable full value (title / aria-label).",
|
|
435
|
+
fix: "Nothing may be cut off: no horizontal scroll on the document or the app's main region, and no text/icon partly hidden by an overflow:hidden/clip ancestor. Let the container shrink its content (min-width:0 + wrap), or truncate with a recoverable full value (title / aria-label). Kit Breadcrumb ellipsis requires the complete label in both title and aria-label on its clipping element; a tooltip alone or a partial label is insufficient.",
|
|
435
436
|
},
|
|
436
437
|
{
|
|
437
438
|
id: "c02-search-usable",
|
|
@@ -1056,11 +1057,21 @@ export function collectProbes(opts) {
|
|
|
1056
1057
|
if (it.kind === "text" && truncating) {
|
|
1057
1058
|
const full = snippet(it.owner.textContent).slice(0, 20);
|
|
1058
1059
|
const carrier = it.owner.closest("[title], [aria-label], [data-audit-recoverable]");
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1060
|
+
const crumb = it.owner.closest(".ui-breadcrumb-ellipsis");
|
|
1061
|
+
const crumbText = crumb?.cloneNode(true);
|
|
1062
|
+
crumbText
|
|
1063
|
+
?.querySelectorAll('[aria-hidden="true"], [hidden]')
|
|
1064
|
+
.forEach((child) => child.remove());
|
|
1065
|
+
const crumbLabel = crumbText?.textContent?.replace(/\s+/g, " ").trim();
|
|
1066
|
+
const kitCrumb = crumb?.closest(".ui-breadcrumb-list > .ui-breadcrumb-item");
|
|
1067
|
+
recoverable = kitCrumb
|
|
1068
|
+
? !!crumbLabel &&
|
|
1069
|
+
crumb.getAttribute("title")?.replace(/\s+/g, " ").trim() === crumbLabel &&
|
|
1070
|
+
crumb.getAttribute("aria-label")?.replace(/\s+/g, " ").trim() === crumbLabel
|
|
1071
|
+
: !!carrier &&
|
|
1072
|
+
(carrier.hasAttribute("data-audit-recoverable") ||
|
|
1073
|
+
snippet(carrier.getAttribute("title")).includes(full) ||
|
|
1074
|
+
snippet(carrier.getAttribute("aria-label")).includes(full));
|
|
1064
1075
|
}
|
|
1065
1076
|
worst = { px, axis: dx >= dy ? "x" : "y", clipper: desc(a), recoverable };
|
|
1066
1077
|
}
|
|
@@ -1838,20 +1849,74 @@ async function runProbes(page, url, viewport) {
|
|
|
1838
1849
|
}
|
|
1839
1850
|
/* c8 ignore stop */
|
|
1840
1851
|
|
|
1841
|
-
/**
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1852
|
+
/**
|
|
1853
|
+
* Optional-peer loader — throws a tagged bootstrap error instead of a raw stack (gh#1390).
|
|
1854
|
+
*
|
|
1855
|
+
* Resolution order: an explicit `--playwright-module` path (a directory or an entry file that
|
|
1856
|
+
* exports `chromium`) → the `playwright` peer → `playwright-core`. The two package names are
|
|
1857
|
+
* looked up from this script AND from the consumer's cwd: under pnpm's strict layout a
|
|
1858
|
+
* consumer-root `playwright-core` is not reachable from the installed script. An explicit path that
|
|
1859
|
+
* fails is an error, never a silent fall-through to another engine.
|
|
1860
|
+
*/
|
|
1861
|
+
export async function loadDeps({ playwrightModule, bases } = {}) {
|
|
1862
|
+
const tried = [];
|
|
1863
|
+
// `require`, not `import()`: the path comes from require.resolve (playwright and playwright-core
|
|
1864
|
+
// are CJS), and a computed import() makes vite's test transform prepend a helper above the shebang.
|
|
1865
|
+
const load = (resolved, label) => {
|
|
1866
|
+
const mod = createRequire(import.meta.url)(resolved);
|
|
1867
|
+
const chromium = mod.chromium ?? mod.default?.chromium;
|
|
1868
|
+
if (!chromium?.launch) throw new Error(`${label} does not export chromium`);
|
|
1869
|
+
return chromium;
|
|
1870
|
+
};
|
|
1871
|
+
if (playwrightModule) {
|
|
1872
|
+
const abs = path.resolve(playwrightModule);
|
|
1873
|
+
const label = `${abs} (--playwright-module)`;
|
|
1874
|
+
try {
|
|
1875
|
+
const resolved = createRequire(path.join(process.cwd(), "noop.js")).resolve(abs);
|
|
1876
|
+
return { chromium: load(resolved, label), source: abs };
|
|
1877
|
+
} catch (cause) {
|
|
1878
|
+
const err = new Error(
|
|
1879
|
+
`visual-audit could not load --playwright-module: tried ${label}: ${cause.message}`,
|
|
1880
|
+
);
|
|
1881
|
+
err.bootstrap = true;
|
|
1882
|
+
err.hint = "pass the playwright or playwright-core package directory (or its index.js).";
|
|
1883
|
+
err.cause = cause;
|
|
1884
|
+
throw err;
|
|
1885
|
+
}
|
|
1854
1886
|
}
|
|
1887
|
+
const from = bases ?? [import.meta.url, path.join(process.cwd(), "package.json")];
|
|
1888
|
+
for (const name of ["playwright", "playwright-core"]) {
|
|
1889
|
+
for (const base of from) {
|
|
1890
|
+
const where = base.startsWith("file:") ? fileURLToPath(base) : base;
|
|
1891
|
+
const label = `${name} (from ${path.dirname(where)})`;
|
|
1892
|
+
let resolved;
|
|
1893
|
+
try {
|
|
1894
|
+
resolved = createRequire(base).resolve(name);
|
|
1895
|
+
} catch {
|
|
1896
|
+
tried.push(label);
|
|
1897
|
+
continue;
|
|
1898
|
+
}
|
|
1899
|
+
try {
|
|
1900
|
+
return { chromium: load(resolved, label), source: resolved };
|
|
1901
|
+
} catch (cause) {
|
|
1902
|
+
tried.push(`${label}: ${cause.message}`);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
const err = new Error(
|
|
1907
|
+
`visual-audit needs the optional peer \`playwright\` (or \`playwright-core\`); tried: ${tried.join("; ")}`,
|
|
1908
|
+
);
|
|
1909
|
+
err.bootstrap = true;
|
|
1910
|
+
err.hint =
|
|
1911
|
+
"pnpm add -D playwright && pnpm exec playwright install chromium, or point at an existing " +
|
|
1912
|
+
"install: --playwright-module /abs/path/playwright-core --executable-path /path/to/chrome " +
|
|
1913
|
+
"(or set PLAYWRIGHT_CHROMIUM_EXECUTABLE).";
|
|
1914
|
+
throw err;
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
/** Options for `chromium.launch` — `--executable-path` wins over PLAYWRIGHT_CHROMIUM_EXECUTABLE. */
|
|
1918
|
+
export function launchOptions({ executablePath, env = process.env } = {}) {
|
|
1919
|
+
return { executablePath: executablePath || env.PLAYWRIGHT_CHROMIUM_EXECUTABLE || undefined };
|
|
1855
1920
|
}
|
|
1856
1921
|
|
|
1857
1922
|
/**
|
|
@@ -1863,7 +1928,7 @@ async function audit(
|
|
|
1863
1928
|
targets,
|
|
1864
1929
|
{ chromium },
|
|
1865
1930
|
viewports = DEFAULT_VIEWPORTS,
|
|
1866
|
-
{ storageState, modes = [], zoom = 200, screenshots } = {},
|
|
1931
|
+
{ storageState, modes = [], zoom = 200, screenshots, executablePath } = {},
|
|
1867
1932
|
) {
|
|
1868
1933
|
const findings = [];
|
|
1869
1934
|
const errors = [];
|
|
@@ -1875,15 +1940,13 @@ async function audit(
|
|
|
1875
1940
|
let context;
|
|
1876
1941
|
try {
|
|
1877
1942
|
try {
|
|
1878
|
-
browser = await chromium.launch({
|
|
1879
|
-
executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE || undefined,
|
|
1880
|
-
});
|
|
1943
|
+
browser = await chromium.launch(launchOptions({ executablePath }));
|
|
1881
1944
|
} catch (cause) {
|
|
1882
1945
|
const err = new Error(`could not launch Chromium: ${cause.message}`);
|
|
1883
1946
|
err.bootstrap = true;
|
|
1884
1947
|
err.hint =
|
|
1885
1948
|
"install a browser: pnpm exec playwright install chromium " +
|
|
1886
|
-
"(or set PLAYWRIGHT_CHROMIUM_EXECUTABLE to a system Chromium).";
|
|
1949
|
+
"(or pass --executable-path / set PLAYWRIGHT_CHROMIUM_EXECUTABLE to a system Chromium).";
|
|
1887
1950
|
throw err;
|
|
1888
1951
|
}
|
|
1889
1952
|
context = await browser.newContext({ viewport: viewports[0], storageState });
|
|
@@ -2197,11 +2260,39 @@ async function main() {
|
|
|
2197
2260
|
}
|
|
2198
2261
|
}
|
|
2199
2262
|
|
|
2200
|
-
|
|
2263
|
+
// `--playwright-module <path>` / `--executable-path <chrome>` (gh#1390): reuse a playwright-core +
|
|
2264
|
+
// Chrome the app already has instead of installing the `playwright` peer.
|
|
2265
|
+
const pmIdx = args.indexOf("--playwright-module");
|
|
2266
|
+
const playwrightModule = pmIdx === -1 ? undefined : args[pmIdx + 1];
|
|
2267
|
+
const epIdx = args.indexOf("--executable-path");
|
|
2268
|
+
const executablePath = epIdx === -1 ? undefined : args[epIdx + 1];
|
|
2269
|
+
for (const [flag, idx, value] of [
|
|
2270
|
+
["--playwright-module", pmIdx, playwrightModule],
|
|
2271
|
+
["--executable-path", epIdx, executablePath],
|
|
2272
|
+
]) {
|
|
2273
|
+
if (idx !== -1 && (!value || value.startsWith("--") || !existsSync(value))) {
|
|
2274
|
+
finish(buildBootstrapError(`${flag}: "${value ?? ""}" does not exist`), {
|
|
2275
|
+
asJson,
|
|
2276
|
+
strict,
|
|
2277
|
+
pages: 0,
|
|
2278
|
+
});
|
|
2279
|
+
return;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
const VALUED = [
|
|
2284
|
+
"--format",
|
|
2285
|
+
"--widths",
|
|
2286
|
+
"--storage-state",
|
|
2287
|
+
"--text-zoom",
|
|
2288
|
+
"--screenshots",
|
|
2289
|
+
"--playwright-module",
|
|
2290
|
+
"--executable-path",
|
|
2291
|
+
];
|
|
2201
2292
|
const urls = args.filter((a, i) => !a.startsWith("--") && !VALUED.includes(args[i - 1]));
|
|
2202
2293
|
if (urls.length === 0) {
|
|
2203
2294
|
const msg =
|
|
2204
|
-
"no baseUrl given — usage: visual-audit.mjs [--format json] [--strict] [--widths 390x844,1280x900] [--storage-state state.json] [--text-spacing] [--text-zoom 200] [--screenshots DIR] <baseUrl> [route …] " +
|
|
2295
|
+
"no baseUrl given — usage: visual-audit.mjs [--format json] [--strict] [--widths 390x844,1280x900] [--storage-state state.json] [--text-spacing] [--text-zoom 200] [--screenshots DIR] [--playwright-module PATH] [--executable-path CHROME] <baseUrl> [route …] " +
|
|
2205
2296
|
"(baseUrl is the running app; extra args are routes appended to it)";
|
|
2206
2297
|
finish(buildBootstrapError(msg), { asJson, strict, pages: 0 });
|
|
2207
2298
|
return;
|
|
@@ -2215,7 +2306,7 @@ async function main() {
|
|
|
2215
2306
|
|
|
2216
2307
|
let deps;
|
|
2217
2308
|
try {
|
|
2218
|
-
deps = await loadDeps();
|
|
2309
|
+
deps = await loadDeps({ playwrightModule });
|
|
2219
2310
|
} catch (e) {
|
|
2220
2311
|
finish(buildBootstrapError(e.message, e.hint), { asJson, strict, pages: targets.length });
|
|
2221
2312
|
return;
|
|
@@ -2227,6 +2318,7 @@ async function main() {
|
|
|
2227
2318
|
modes,
|
|
2228
2319
|
zoom,
|
|
2229
2320
|
screenshots: screenshots && path.resolve(screenshots),
|
|
2321
|
+
executablePath,
|
|
2230
2322
|
});
|
|
2231
2323
|
finish(result, { asJson, strict, pages: targets.length });
|
|
2232
2324
|
} catch (e) {
|