@godxjp/ui 32.1.1 → 32.1.2
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/agent/START-HERE.md +1 -1
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/dist/contracts/measurement.json +1 -1
- package/dist/styles/layers.json +1 -1
- package/package.json +2 -2
- package/scripts/ui-audit.mjs +79 -3
package/agent/START-HERE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
You are about to write code against a design system you did not author. This file is the whole
|
|
4
4
|
contract. Read it before you write JSX.
|
|
5
5
|
|
|
6
|
-
**This catalog describes `@godxjp/ui` 32.1.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 32.1.2.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
package/agent/index.json
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
|
|
49
49
|
"read": {
|
|
50
50
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
51
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.1.
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.1.2/agent/index.json"
|
|
52
52
|
},
|
|
53
53
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
54
54
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
63
63
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
64
64
|
},
|
|
65
|
-
"version": "32.1.
|
|
65
|
+
"version": "32.1.2"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
3
|
> A Japanese-enterprise React design system: 161 components, 2193 design tokens,
|
|
4
|
-
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.1.
|
|
4
|
+
> 43 cardinal rules. This file is the entry point for AI agents. Catalog version 32.1.2.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@32.1.
|
|
7
|
+
(`npx @godxjp/ui-mcp@32.1.2`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -26,7 +26,7 @@ that can only fetch URLs.
|
|
|
26
26
|
## Pinning
|
|
27
27
|
|
|
28
28
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
29
|
-
the tag: `.../godx-jp/godxjp-ui/v32.1.
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v32.1.2/agent/...`. A catalog that does not match the installed
|
|
30
30
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
31
31
|
|
|
32
32
|
Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "32.1.
|
|
3
|
+
"version": "32.1.2",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
package/dist/styles/layers.json
CHANGED
package/package.json
CHANGED
package/scripts/ui-audit.mjs
CHANGED
|
@@ -1829,6 +1829,8 @@ function staleOwnedRules() {
|
|
|
1829
1829
|
const FORM_TAGS = new Set(["Form", "FormRoot"]);
|
|
1830
1830
|
const formOpenTag = new RegExp(`<(${[...FORM_TAGS].join("|")})(?=[\\s>])([^>]*)>`, "g");
|
|
1831
1831
|
function formTagWalk(scanContent) {
|
|
1832
|
+
const formSpans = [];
|
|
1833
|
+
const formOpens = [];
|
|
1832
1834
|
const stack = [];
|
|
1833
1835
|
const bareByParent = new Map();
|
|
1834
1836
|
const underForm = new Set();
|
|
@@ -1846,11 +1848,18 @@ function formTagWalk(scanContent) {
|
|
|
1846
1848
|
break;
|
|
1847
1849
|
}
|
|
1848
1850
|
}
|
|
1849
|
-
if (FORM_TAGS.has(tag))
|
|
1851
|
+
if (FORM_TAGS.has(tag)) {
|
|
1852
|
+
formDepth = Math.max(0, formDepth - 1);
|
|
1853
|
+
const open = formOpens.pop();
|
|
1854
|
+
if (open !== undefined) formSpans.push([open, m.index]);
|
|
1855
|
+
}
|
|
1850
1856
|
continue;
|
|
1851
1857
|
}
|
|
1852
1858
|
if (tag === "FormField" && formDepth === 0) {
|
|
1853
|
-
|
|
1859
|
+
// A field at the TOP of a return has no parent tag; key it by its component, or two
|
|
1860
|
+
// one-field components in one file (`Field`, `Choice`) read as "Field renders 2 FormFields"
|
|
1861
|
+
// (gh#1260). A lone field is not flagged, so each is now judged on its own.
|
|
1862
|
+
const parent = stack.at(-1)?.index ?? `top:${enclosingComponent(scanContent, m.index)}`;
|
|
1854
1863
|
(bareByParent.get(parent) ?? bareByParent.set(parent, []).get(parent)).push(m.index);
|
|
1855
1864
|
}
|
|
1856
1865
|
if (/^[A-Z]/.test(tag)) {
|
|
@@ -1859,11 +1868,78 @@ function formTagWalk(scanContent) {
|
|
|
1859
1868
|
}
|
|
1860
1869
|
if (selfClose) continue;
|
|
1861
1870
|
stack.push({ tag, index: m.index });
|
|
1862
|
-
if (FORM_TAGS.has(tag))
|
|
1871
|
+
if (FORM_TAGS.has(tag)) {
|
|
1872
|
+
formDepth += 1;
|
|
1873
|
+
formOpens.push(m.index);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
// gh#1260: JSX inside a RENDER HELPER (`const legFields = (leg) => (…)`) has no Form above it in
|
|
1877
|
+
// the source, but it renders wherever the helper is CALLED. When every call of that helper is
|
|
1878
|
+
// under a Form — directly, or inside another such helper — the JSX is under that Form too.
|
|
1879
|
+
const covered = renderHelperCoverage(scanContent, formSpans);
|
|
1880
|
+
if (covered) {
|
|
1881
|
+
for (const [parent, indexes] of bareByParent) {
|
|
1882
|
+
const kept = indexes.filter((i) => !covered(i));
|
|
1883
|
+
if (kept.length) bareByParent.set(parent, kept);
|
|
1884
|
+
else bareByParent.delete(parent);
|
|
1885
|
+
}
|
|
1886
|
+
for (const [tag, indexes] of outsideForm) {
|
|
1887
|
+
const kept = indexes.filter((i) => !covered(i));
|
|
1888
|
+
if (kept.length < indexes.length) underForm.add(tag);
|
|
1889
|
+
if (kept.length) outsideForm.set(tag, kept);
|
|
1890
|
+
else outsideForm.delete(tag);
|
|
1891
|
+
}
|
|
1863
1892
|
}
|
|
1864
1893
|
return { bareByParent, underForm, outsideForm };
|
|
1865
1894
|
}
|
|
1866
1895
|
|
|
1896
|
+
/**
|
|
1897
|
+
* `index → true` when `index` sits in a same-file render helper whose every call is under a Form
|
|
1898
|
+
* (gh#1260). Helpers are lowercase `function name(` / `const name = (…) =>` declarations; their
|
|
1899
|
+
* body is found by bracket matching, and a helper never called is NOT covered (it might be
|
|
1900
|
+
* exported or passed as a render prop). Returns null when the file declares no helper.
|
|
1901
|
+
*/
|
|
1902
|
+
function renderHelperCoverage(scanContent, formSpans) {
|
|
1903
|
+
const helpers = [];
|
|
1904
|
+
for (const m of scanContent.matchAll(
|
|
1905
|
+
/(?<![\w$.])(?:function\s+([a-z]\w*)\s*(?:<[^>]*>)?\s*\(|(?:const|let)\s+([a-z]\w*)\s*(?::[^=]+)?=\s*(?:async\s*)?(?:\([^()]*(?:\([^()]*\)[^()]*)*\)|[a-z]\w*)\s*(?::[^=]+?)?=>\s*)/g,
|
|
1906
|
+
)) {
|
|
1907
|
+
const name = m[1] ?? m[2];
|
|
1908
|
+
let open;
|
|
1909
|
+
if (m[1]) {
|
|
1910
|
+
const params = matchBracket(scanContent, m.index + m[0].length - 1);
|
|
1911
|
+
if (params < 0) continue;
|
|
1912
|
+
open = scanContent.indexOf("{", params);
|
|
1913
|
+
} else {
|
|
1914
|
+
open = m.index + m[0].length;
|
|
1915
|
+
if (scanContent[open] !== "{" && scanContent[open] !== "(") continue;
|
|
1916
|
+
}
|
|
1917
|
+
const close = open < 0 ? -1 : matchBracket(scanContent, open);
|
|
1918
|
+
if (close < 0) continue;
|
|
1919
|
+
helpers.push({ name, from: open, to: close, decl: m.index });
|
|
1920
|
+
}
|
|
1921
|
+
if (!helpers.length) return null;
|
|
1922
|
+
const inForm = (i) => formSpans.some(([a, b]) => i > a && i < b);
|
|
1923
|
+
/** The innermost helper whose body holds `i`. */
|
|
1924
|
+
const helperAt = (i) =>
|
|
1925
|
+
helpers
|
|
1926
|
+
.filter((h) => i > h.from && i < h.to)
|
|
1927
|
+
.reduce((inner, h) => (!inner || h.from > inner.from ? h : inner), null);
|
|
1928
|
+
const callsOf = (name) =>
|
|
1929
|
+
[...scanContent.matchAll(new RegExp(`(?<![\\w$.])${name}\\s*\\(`, "g"))]
|
|
1930
|
+
.map((c) => c.index)
|
|
1931
|
+
.filter((i) => !helpers.some((h) => h.name === name && i >= h.decl && i < h.from));
|
|
1932
|
+
const covered = (i, depth = 0) => {
|
|
1933
|
+
if (inForm(i)) return true;
|
|
1934
|
+
if (depth > 4) return false;
|
|
1935
|
+
const helper = helperAt(i);
|
|
1936
|
+
if (!helper) return false;
|
|
1937
|
+
const calls = callsOf(helper.name);
|
|
1938
|
+
return calls.length > 0 && calls.every((c) => covered(c, depth + 1));
|
|
1939
|
+
};
|
|
1940
|
+
return (i) => covered(i);
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1867
1943
|
/** The PascalCase component declared last before `index` — the one a FormField group sits in. */
|
|
1868
1944
|
function enclosingComponent(scanContent, index) {
|
|
1869
1945
|
let name = null;
|