@godxjp/ui 33.12.8 → 33.14.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.
Files changed (51) hide show
  1. package/README.md +8 -4
  2. package/agent/START-HERE.md +5 -5
  3. package/agent/components/BranchScopePicker.json +21 -1
  4. package/agent/components/Breadcrumb.json +8 -2
  5. package/agent/components/DataTable.json +2 -1
  6. package/agent/components/MobileShell.json +1 -0
  7. package/agent/components/PageContainer.json +6 -0
  8. package/agent/components/Persona.json +66 -0
  9. package/agent/components/Sidebar.json +1 -0
  10. package/agent/components/Table.json +1 -1
  11. package/agent/components-index.json +5 -0
  12. package/agent/components.json +106 -5
  13. package/agent/index.json +7 -7
  14. package/agent/llms.txt +6 -6
  15. package/agent/tokens.json +62 -2
  16. package/agent/vocabulary.json +13 -0
  17. package/dist/components/data-display/data-table.js +51 -10
  18. package/dist/components/data-display/index.d.ts +2 -0
  19. package/dist/components/data-display/index.js +2 -0
  20. package/dist/components/data-display/persona.d.ts +11 -0
  21. package/dist/components/data-display/persona.js +34 -0
  22. package/dist/components/data-entry/branch-scope-picker.d.ts +3 -0
  23. package/dist/components/data-entry/branch-scope-picker.js +65 -11
  24. package/dist/components/layout/breadcrumb-ellipsis.js +33 -1
  25. package/dist/components/layout/breadcrumb.d.ts +4 -2
  26. package/dist/components/layout/breadcrumb.js +13 -3
  27. package/dist/components/layout/page-container.d.ts +1 -1
  28. package/dist/components/layout/page-container.js +5 -3
  29. package/dist/contracts/measurement.json +1 -1
  30. package/dist/i18n/messages/en.json +2 -1
  31. package/dist/i18n/messages/ja.json +13 -12
  32. package/dist/i18n/messages/vi.json +2 -1
  33. package/dist/props/components/data-display.prop.d.ts +10 -0
  34. package/dist/props/components/data-entry.prop.d.ts +6 -0
  35. package/dist/props/components/layout.prop.d.ts +5 -1
  36. package/dist/props/registry.d.ts +24 -2
  37. package/dist/props/registry.js +26 -0
  38. package/dist/props/vocabulary/index.d.ts +1 -1
  39. package/dist/props/vocabulary/navigation.prop.d.ts +2 -0
  40. package/dist/styles/control.css +29 -3
  41. package/dist/styles/data-display-layout.css +58 -0
  42. package/dist/styles/layers.json +8 -2
  43. package/dist/styles/table-layout.css +32 -12
  44. package/dist/styles.css +1 -1
  45. package/dist/tokens/base.css +2 -0
  46. package/dist/tokens/components/persona.css +13 -0
  47. package/dist/tokens/components/table.css +1 -1
  48. package/docs/TOKENS.md +11 -0
  49. package/package.json +2 -2
  50. package/scripts/cli.mjs +8 -2
  51. package/scripts/visual-audit.mjs +119 -27
@@ -53,3 +53,5 @@
53
53
  @import "./components/anchor.css";
54
54
 
55
55
  @import "./components/resizable.css";
56
+
57
+ @import "./components/persona.css";
@@ -0,0 +1,13 @@
1
+
2
+ :root {
3
+ --persona-avatar-gap: initial;
4
+ --persona-label-gap: initial;
5
+ --persona-trailing-gap: initial;
6
+ --persona-label-line-height: 1.5;
7
+ --persona-name-font-size: initial;
8
+ --persona-name-font-size-sm: initial;
9
+ --persona-name-font-weight: initial;
10
+ --persona-description-font-size: initial;
11
+ --persona-name-color: initial;
12
+ --persona-description-color: initial;
13
+ }
@@ -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: var(--space-inline-md);
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "33.12.8",
4
- "godxUiMcp": "33.12.8",
3
+ "version": "33.14.0",
4
+ "godxUiMcp": "33.14.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
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]
@@ -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
- recoverable =
1060
- !!carrier &&
1061
- (carrier.hasAttribute("data-audit-recoverable") ||
1062
- snippet(carrier.getAttribute("title")).includes(full) ||
1063
- snippet(carrier.getAttribute("aria-label")).includes(full));
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
- /** Optional-peer loader — throws a tagged bootstrap error instead of a raw stack. */
1842
- async function loadDeps() {
1843
- try {
1844
- const { chromium } = await import("playwright");
1845
- return { chromium };
1846
- } catch (cause) {
1847
- const err = new Error("visual-audit needs the optional peer `playwright`");
1848
- err.bootstrap = true;
1849
- err.hint =
1850
- "pnpm add -D playwright && pnpm exec playwright install chromium " +
1851
- "(or set PLAYWRIGHT_CHROMIUM_EXECUTABLE to a system Chromium).";
1852
- err.cause = cause;
1853
- throw err;
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
- const VALUED = ["--format", "--widths", "--storage-state", "--text-zoom", "--screenshots"];
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) {