@godxjp/ui 30.2.0 → 30.3.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.
@@ -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` 30.2.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 30.3.0.** 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.
@@ -167,6 +167,7 @@
167
167
  "usage": [
168
168
  "DO name the tree — pass `aria-label` (through your own `t()`) or `aria-labelledby`. A tree with no name is an unlabelled landmark for every screen reader user.",
169
169
  "DO keep SELECTION and CHECKS apart: `value`/`onValueChange` is which node is open in the detail pane; `checkedValues`/`onCheckedValuesChange` is which nodes are ticked. They are two axes, exactly as in antd — never drive one from the other.",
170
+ "DO keep SELECTION and EXPANSION apart too — this is the THIRD axis and the one gh#910 tripped on. `onValueChange` says which node a detail pane should show; `onExpandedValuesChange` says which branches are unfolded. A sibling pane listens to the first and ignores the second, so unfolding a branch cannot reload it. If your pane reloads when a branch opens, it is being driven from the wrong event — not from a missing feature.",
170
171
  "DO let the keyboard work: the tree ships the full APG contract (Up/Down through visible nodes, Right expands then descends, Left collapses then climbs, Home/End, Enter/Space, `*` to expand the current level, type-ahead). Do not add your own key handling on top.",
171
172
  "DON'T nest a Button, Checkbox, Link or any focusable control inside a node label. A tree item owns exactly ONE tab stop; the disclosure triangle and the tick box are decorative glyphs for that reason. Put row actions in a sibling column outside the tree, or open a detail pane on selection.",
172
173
  "DON'T hand-roll an indented `<ul>` (or a NavList / ListRow stack with a per-depth margin) for a hierarchy. A flat indented list only LOOKS like a tree: no expand/collapse, no `role=\"tree\"`, no keyboard model, no selection contract. `TreeList` was exactly that list and was REMOVED in 21.0.0 — Tree is what replaced it, and it is the one to reach for whenever nodes expand, collapse or are keyboard-navigated.",
@@ -10877,6 +10877,7 @@
10877
10877
  "usage": [
10878
10878
  "DO name the tree — pass `aria-label` (through your own `t()`) or `aria-labelledby`. A tree with no name is an unlabelled landmark for every screen reader user.",
10879
10879
  "DO keep SELECTION and CHECKS apart: `value`/`onValueChange` is which node is open in the detail pane; `checkedValues`/`onCheckedValuesChange` is which nodes are ticked. They are two axes, exactly as in antd — never drive one from the other.",
10880
+ "DO keep SELECTION and EXPANSION apart too — this is the THIRD axis and the one gh#910 tripped on. `onValueChange` says which node a detail pane should show; `onExpandedValuesChange` says which branches are unfolded. A sibling pane listens to the first and ignores the second, so unfolding a branch cannot reload it. If your pane reloads when a branch opens, it is being driven from the wrong event — not from a missing feature.",
10880
10881
  "DO let the keyboard work: the tree ships the full APG contract (Up/Down through visible nodes, Right expands then descends, Left collapses then climbs, Home/End, Enter/Space, `*` to expand the current level, type-ahead). Do not add your own key handling on top.",
10881
10882
  "DON'T nest a Button, Checkbox, Link or any focusable control inside a node label. A tree item owns exactly ONE tab stop; the disclosure triangle and the tick box are decorative glyphs for that reason. Put row actions in a sibling column outside the tree, or open a detail pane on selection.",
10882
10883
  "DON'T hand-roll an indented `<ul>` (or a NavList / ListRow stack with a per-depth margin) for a hierarchy. A flat indented list only LOOKS like a tree: no expand/collapse, no `role=\"tree\"`, no keyboard model, no selection contract. `TreeList` was exactly that list and was REMOVED in 21.0.0 — Tree is what replaced it, and it is the one to reach for whenever nodes expand, collapse or are keyboard-navigated.",
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/v30.2.0/agent/index.json"
51
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v30.3.0/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": "30.2.0"
65
+ "version": "30.3.0"
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: 171 components, 2071 design tokens,
4
- > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 30.2.0.
4
+ > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 30.3.0.
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@30.2.0`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@30.3.0`). 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/v30.2.0/agent/...`. A catalog that does not match the installed
29
+ the tag: `.../godx-jp/godxjp-ui/v30.3.0/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.
@@ -87,7 +87,11 @@ function TreeRoot({
87
87
  });
88
88
  const isExpandedControlled = expandedValues !== void 0;
89
89
  const expanded = isExpandedControlled ? [...expandedValues] : internalExpanded;
90
- const expandedSet = new Set(expanded);
90
+ const expandedKey = expanded.join("\0");
91
+ const expandedSet = React.useMemo(
92
+ () => new Set(expandedKey ? expandedKey.split("\0") : []),
93
+ [expandedKey]
94
+ );
91
95
  const commitExpanded = (next) => {
92
96
  if (!isExpandedControlled) setInternalExpanded(next);
93
97
  onExpandedValuesChange?.(next);
@@ -126,6 +130,29 @@ function TreeRoot({
126
130
  });
127
131
  });
128
132
  };
133
+ const requestLoadRef = React.useRef(requestLoad);
134
+ requestLoadRef.current = requestLoad;
135
+ const nodesByValue = React.useMemo(() => {
136
+ const map = /* @__PURE__ */ new Map();
137
+ const walk = (list) => {
138
+ for (const node of list) {
139
+ map.set(node.value, node);
140
+ if (node.children?.length) walk(node.children);
141
+ }
142
+ };
143
+ walk(options);
144
+ return map;
145
+ }, [options]);
146
+ const loadedFor = React.useRef(/* @__PURE__ */ new Set());
147
+ React.useEffect(() => {
148
+ if (!loadData) return;
149
+ for (const value2 of expandedSet) {
150
+ if (loadedFor.current.has(value2)) continue;
151
+ loadedFor.current.add(value2);
152
+ const node = nodesByValue.get(value2);
153
+ if (node) requestLoadRef.current(node);
154
+ }
155
+ }, [expandedSet, loadData, nodesByValue, requestLoadRef]);
129
156
  const visible = flattenVisibleTree(options, expandedSet);
130
157
  const visibleIndex = new Map(visible.map((entry, index) => [entry.node.value, index]));
131
158
  const [activeValue, setActiveValue] = React.useState(null);
@@ -327,6 +354,7 @@ function TreeRoot({
327
354
  if (nodeDisabled) return;
328
355
  select(node);
329
356
  },
357
+ "data-value": node.value,
330
358
  "data-selected": isSelected ? "true" : void 0,
331
359
  "data-disabled": nodeDisabled ? "" : void 0,
332
360
  className: "ui-tree-node ui-focus-ring",
@@ -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": "30.1.1",
3
+ "version": "30.2.0",
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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "30.2.0",
4
- "godxUiMcp": "30.2.0",
3
+ "version": "30.3.0",
4
+ "godxUiMcp": "30.3.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",