@godxjp/ui 31.10.0 → 31.10.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.
@@ -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` 31.10.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 31.10.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.
@@ -59,7 +59,7 @@
59
59
  "type": "boolean"
60
60
  },
61
61
  {
62
- "description": "Ant Design `tabBarExtraContent`, renamed to the library's `extra` slot and made logical: antd's `left`/`right` keys are `start`/`end` here. A bare node goes to `end` (antd's own default). Renders a bar row beside the strip; without it — and without an add button — no extra wrapper is emitted at all. Under `bodied` the bar row aligns its contents to the JOINED edge instead of centring them, so the add button and the extra sit on the rail rather than hanging across it.",
62
+ "description": "Ant Design `tabBarExtraContent`, renamed to the library's `extra` slot and made logical: antd's `left`/`right` keys are `start`/`end` here. A bare node goes to `end` (antd's own default). Renders a bar row beside the strip; without it — and without an add button — no extra wrapper is emitted at all. Centred on the tab faces (antd `.ant-tabs-nav { align-items: center }`). Under `bodied` the tabs stretch to the bar's height (antd's stretched nav list), so they stay joined to the body while the extra stays centred and off the body's border; only the add button sits on the rail (gh#1073).",
63
63
  "name": "extra",
64
64
  "type": "React.ReactNode | { start?: React.ReactNode; end?: React.ReactNode }"
65
65
  },
@@ -7982,7 +7982,7 @@
7982
7982
  "type": "boolean"
7983
7983
  },
7984
7984
  {
7985
- "description": "Ant Design `tabBarExtraContent`, renamed to the library's `extra` slot and made logical: antd's `left`/`right` keys are `start`/`end` here. A bare node goes to `end` (antd's own default). Renders a bar row beside the strip; without it — and without an add button — no extra wrapper is emitted at all. Under `bodied` the bar row aligns its contents to the JOINED edge instead of centring them, so the add button and the extra sit on the rail rather than hanging across it.",
7985
+ "description": "Ant Design `tabBarExtraContent`, renamed to the library's `extra` slot and made logical: antd's `left`/`right` keys are `start`/`end` here. A bare node goes to `end` (antd's own default). Renders a bar row beside the strip; without it — and without an add button — no extra wrapper is emitted at all. Centred on the tab faces (antd `.ant-tabs-nav { align-items: center }`). Under `bodied` the tabs stretch to the bar's height (antd's stretched nav list), so they stay joined to the body while the extra stays centred and off the body's border; only the add button sits on the rail (gh#1073).",
7986
7986
  "name": "extra",
7987
7987
  "type": "React.ReactNode | { start?: React.ReactNode; end?: React.ReactNode }"
7988
7988
  },
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/v31.10.0/agent/index.json"
51
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.10.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": "31.10.0"
65
+ "version": "31.10.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: 177 components, 2104 design tokens,
4
- > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.10.0.
4
+ > 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.10.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@31.10.0`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@31.10.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/v31.10.0/agent/...`. A catalog that does not match the installed
29
+ the tag: `.../godx-jp/godxjp-ui/v31.10.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.
@@ -13,6 +13,8 @@ function useActionsColumnFit(ref, enabled) {
13
13
  React.useLayoutEffect(() => {
14
14
  const box = ref.current;
15
15
  if (!enabled || !box || typeof ResizeObserver === "undefined") return void 0;
16
+ const measuredWidths = /* @__PURE__ */ new WeakMap();
17
+ const observedContents = /* @__PURE__ */ new Set();
16
18
  const measure = () => {
17
19
  box.style.removeProperty(ACTIONS_CONTENT_WIDTH);
18
20
  let needed = 0;
@@ -22,29 +24,73 @@ function useActionsColumnFit(ref, enabled) {
22
24
  const style = getComputedStyle(cell);
23
25
  const inset = parseFloat(style.paddingInlineStart) + parseFloat(style.paddingInlineEnd);
24
26
  const width = content.getBoundingClientRect().width;
27
+ measuredWidths.set(content, width);
25
28
  if (width <= cell.clientWidth + 0.5) return;
26
29
  const edges = style.boxSizing === "border-box" ? inset + parseFloat(style.borderInlineStartWidth) + parseFloat(style.borderInlineEndWidth) : 0;
27
30
  needed = Math.max(needed, Math.ceil(width + edges));
28
31
  });
29
32
  if (needed > 0) box.style.setProperty(ACTIONS_CONTENT_WIDTH, `${needed}px`);
30
33
  };
31
- const resize = new ResizeObserver(measure);
32
- const observeAll = () => {
33
- resize.disconnect();
34
- resize.observe(box);
35
- box.querySelectorAll(".ui-table-actions-content").forEach((content) => resize.observe(content));
36
- measure();
34
+ let frame = 0;
35
+ let rowsChanged = false;
36
+ const schedule = () => {
37
+ if (frame !== 0) return;
38
+ frame = requestAnimationFrame(() => {
39
+ frame = 0;
40
+ if (rowsChanged) {
41
+ rowsChanged = false;
42
+ observeStructure();
43
+ observeContents();
44
+ }
45
+ measure();
46
+ });
47
+ };
48
+ const resize = new ResizeObserver((entries) => {
49
+ if (entries.some((entry) => measuredWidths.get(entry.target) !== entry.contentRect.width)) {
50
+ schedule();
51
+ }
52
+ });
53
+ const observeContents = () => {
54
+ observedContents.forEach((content) => {
55
+ if (content.isConnected) return;
56
+ resize.unobserve(content);
57
+ observedContents.delete(content);
58
+ });
59
+ box.querySelectorAll(".ui-table-actions-content").forEach((content) => {
60
+ if (observedContents.has(content)) return;
61
+ observedContents.add(content);
62
+ resize.observe(content);
63
+ });
37
64
  };
38
- const mutations = new MutationObserver(observeAll);
39
- mutations.observe(box, { childList: true, subtree: true });
40
- observeAll();
65
+ const mutations = new MutationObserver(() => {
66
+ rowsChanged = true;
67
+ schedule();
68
+ });
69
+ const observeStructure = () => {
70
+ mutations.disconnect();
71
+ const table = box.querySelector(":scope > table");
72
+ if (!table) return;
73
+ mutations.observe(table, { childList: true });
74
+ for (const section of Array.from(table.children)) {
75
+ mutations.observe(section, { childList: true });
76
+ for (const row of Array.from(section.children)) {
77
+ mutations.observe(row, { childList: true });
78
+ }
79
+ }
80
+ };
81
+ resize.observe(box);
82
+ observeStructure();
83
+ observeContents();
84
+ measure();
41
85
  return () => {
86
+ if (frame !== 0) cancelAnimationFrame(frame);
42
87
  resize.disconnect();
43
88
  mutations.disconnect();
44
89
  box.style.removeProperty(ACTIONS_CONTENT_WIDTH);
45
90
  };
46
91
  }, [ref, enabled]);
47
92
  }
93
+ const TablePresetContext = React.createContext("default");
48
94
  const Table = React.forwardRef(
49
95
  ({
50
96
  className,
@@ -91,7 +137,7 @@ const Table = React.forwardRef(
91
137
  "--table-action-collection-min-inline-size-compact": columnWidths.minInlineSizeCompact
92
138
  } : void 0,
93
139
  ...scrolls ? { role: "group", "aria-label": scrollRegionLabel(label, t), tabIndex: 0 } : {},
94
- children: /* @__PURE__ */ jsx(
140
+ children: /* @__PURE__ */ jsx(TablePresetContext.Provider, { value: preset, children: /* @__PURE__ */ jsx(
95
141
  "table",
96
142
  {
97
143
  ref,
@@ -100,7 +146,7 @@ const Table = React.forwardRef(
100
146
  className: cn("w-full caption-bottom", bordered && "ui-table-bordered", className),
101
147
  ...props
102
148
  }
103
- )
149
+ ) })
104
150
  }
105
151
  )
106
152
  );
@@ -180,30 +226,33 @@ const TableCell = React.forwardRef(
180
226
  children,
181
227
  style,
182
228
  ...props
183
- }, ref) => /* @__PURE__ */ jsxs(
184
- "td",
185
- {
186
- ref,
187
- "data-slot": "table-cell",
188
- "data-priority": priority,
189
- "data-flush": flush ? "" : void 0,
190
- "data-indent": indent === void 0 ? void 0 : indent,
191
- "data-align": align,
192
- "data-numeric": numeric ? "" : void 0,
193
- "data-wrap": wrap ? "" : void 0,
194
- className: cn(className),
195
- style: indent === void 0 && width === void 0 ? style : {
196
- ...style,
197
- ...indent === void 0 ? null : { "--table-cell-indent-level": indent },
198
- ...width === void 0 ? null : { inlineSize: cellWidth(width) }
199
- },
200
- ...props,
201
- children: [
202
- label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
203
- priority === "actions" ? /* @__PURE__ */ jsx("span", { className: "ui-table-actions-content", children }) : children
204
- ]
205
- }
206
- )
229
+ }, ref) => {
230
+ const preset = React.useContext(TablePresetContext);
231
+ return /* @__PURE__ */ jsxs(
232
+ "td",
233
+ {
234
+ ref,
235
+ "data-slot": "table-cell",
236
+ "data-priority": priority,
237
+ "data-flush": flush ? "" : void 0,
238
+ "data-indent": indent === void 0 ? void 0 : indent,
239
+ "data-align": align,
240
+ "data-numeric": numeric ? "" : void 0,
241
+ "data-wrap": wrap ? "" : void 0,
242
+ className: cn(className),
243
+ style: indent === void 0 && width === void 0 ? style : {
244
+ ...style,
245
+ ...indent === void 0 ? null : { "--table-cell-indent-level": indent },
246
+ ...width === void 0 ? null : { inlineSize: cellWidth(width) }
247
+ },
248
+ ...props,
249
+ children: [
250
+ label !== void 0 ? /* @__PURE__ */ jsx("span", { className: "ui-table-stacked-collection-label", "aria-hidden": "true", children: label }) : null,
251
+ priority === "actions" && preset === "action-collection" ? /* @__PURE__ */ jsx("span", { className: "ui-table-actions-content", children }) : children
252
+ ]
253
+ }
254
+ );
255
+ }
207
256
  );
208
257
  TableCell.displayName = "TableCell";
209
258
  export {
@@ -161,7 +161,7 @@ function SearchSelect(props) {
161
161
  const isSelected = (optionValue) => multiple ? values.includes(optionValue) : value === optionValue;
162
162
  const hasSelection = multiple ? values.length > 0 : Boolean(value);
163
163
  const reqId = React.useRef(0);
164
- const resetActiveRef = React.useRef(false);
164
+ const [freshPage, setFreshPage] = React.useState(0);
165
165
  const matchesQuery = React.useCallback(
166
166
  (option, needle) => {
167
167
  if (filterOption) return filterOption(option, needle);
@@ -195,7 +195,7 @@ function SearchSelect(props) {
195
195
  const result = await resolvedLoad({ query: search, page: nextPage });
196
196
  if (ticket !== reqId.current) return;
197
197
  setLoaded((prev) => append ? [...prev, ...result.options] : result.options);
198
- if (!append) resetActiveRef.current = true;
198
+ if (!append) setFreshPage((tick) => tick + 1);
199
199
  setHasMore(Boolean(result.hasMore));
200
200
  setPage(nextPage);
201
201
  } catch {
@@ -271,14 +271,16 @@ function SearchSelect(props) {
271
271
  [grouped]
272
272
  );
273
273
  const lastTypedRef = React.useRef(typedText);
274
+ const lastFreshPageRef = React.useRef(freshPage);
274
275
  React.useEffect(() => {
275
276
  const typedChanged = lastTypedRef.current !== typedText;
277
+ const pageChanged = lastFreshPageRef.current !== freshPage;
276
278
  lastTypedRef.current = typedText;
277
- if (!typedChanged && !resetActiveRef.current) return;
278
- resetActiveRef.current = false;
279
+ lastFreshPageRef.current = freshPage;
280
+ if (!typedChanged && !pageChanged) return;
279
281
  const firstEnabled = flatOrdered.findIndex((option) => !option.disabled);
280
282
  setActiveIndex(firstEnabled >= 0 ? firstEnabled : 0);
281
- }, [flatOrdered, typedText]);
283
+ }, [flatOrdered, typedText, freshPage]);
282
284
  const resolvedPlaceholder = placeholder ?? t("dataEntry.searchSelect.placeholder");
283
285
  const optionFor = (optionValue) => pickedOptions[optionValue] ?? (staticOptions ?? []).find((option) => option.value === optionValue) ?? loaded.find((option) => option.value === optionValue) ?? null;
284
286
  const selectedOption = value ? optionFor(value) : null;
@@ -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": "31.10.0",
3
+ "version": "31.10.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,
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "31.10.0",
2
+ "version": "31.10.2",
3
3
  "generatedBy": "scripts/gen-style-layers.mjs — do not edit by hand; run `pnpm gen:style-layers`",
4
4
  "base": "base.css",
5
5
  "fonts": "fonts.css",
@@ -292,12 +292,26 @@
292
292
  box-shadow: none;
293
293
  }
294
294
 
295
- [data-slot="tabs"][data-bodied="true"][data-placement="top"] .ui-tabs-bar {
296
- align-items: flex-end;
295
+ [data-slot="tabs"][data-bodied="true"]:is([data-placement="top"], [data-placement="bottom"])
296
+ .ui-tabs-bar
297
+ > [data-slot="tabs-list"],
298
+ [data-slot="tabs"][data-bodied="true"]:is([data-placement="top"], [data-placement="bottom"])
299
+ .ui-tabs-bar
300
+ [data-slot="tabs-trigger"] {
301
+ align-self: stretch;
297
302
  }
298
303
 
299
- [data-slot="tabs"][data-bodied="true"][data-placement="bottom"] .ui-tabs-bar {
300
- align-items: flex-start;
304
+ [data-slot="tabs"][data-bodied="true"]:is([data-placement="top"], [data-placement="bottom"])
305
+ .ui-tabs-extra {
306
+ margin-block: var(--tabs-panel-border-width);
307
+ }
308
+
309
+ [data-slot="tabs"][data-bodied="true"][data-placement="top"] .ui-tabs-add {
310
+ align-self: flex-end;
311
+ }
312
+
313
+ [data-slot="tabs"][data-bodied="true"][data-placement="bottom"] .ui-tabs-add {
314
+ align-self: flex-start;
301
315
  }
302
316
 
303
317
  [data-slot="tabs"][data-bodied="true"][data-placement="top"] .ui-tabs-extra[data-side="end"],
@@ -652,10 +652,6 @@
652
652
  text-align: end;
653
653
  }
654
654
 
655
- .ui-table-actions-content {
656
- display: contents;
657
- }
658
-
659
655
  .ui-table-collection .ui-table-actions-content {
660
656
  display: inline-block;
661
657
  white-space: nowrap;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@godxjp/ui",
3
- "version": "31.10.0",
4
- "godxUiMcp": "31.10.0",
3
+ "version": "31.10.2",
4
+ "godxUiMcp": "31.10.2",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",