@godxjp/ui 33.12.6 → 33.12.8

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` 33.12.6.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 33.12.8.** 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.
@@ -245,7 +245,7 @@
245
245
  "type": "boolean | { clearIcon?: ReactNode; label?: string }"
246
246
  },
247
247
  {
248
- "description": "Accessible NAME of the calendar button. The default (「カレンダーを開く」 / 'Open calendar') is right for one picker on a page and useless for three: a screen-reader user hears the same sentence three times with nothing to say which field each button belongs to (WCAG 2.2 SC 2.4.6). Name it after the FIELD — `開始日のカレンダーを開く`. Same axis and same reason as Select's `clearLabel`.",
248
+ "description": "Accessible NAME of the calendar button. The default (「カレンダーを開く」 / 'Open calendar') is right for one picker on a page and useless for three: a screen-reader user hears the same sentence three times with nothing to say which field each button belongs to (WCAG 2.2 SC 2.4.6). Name it after the FIELD — `開始日のカレンダーを開く`. Same axis and same reason as Select's `clearLabel`. The calendar DIALOG is named after the field too: the FormField label (or your `aria-labelledby` / `aria-label`) first, then `triggerLabel`, then the default.",
249
249
  "name": "triggerLabel",
250
250
  "type": "string"
251
251
  }
@@ -81,7 +81,7 @@
81
81
  "type": "React.ReactNode"
82
82
  },
83
83
  {
84
- "description": "Placeholder shown in the trigger when no value is selected.",
84
+ "description": "Placeholder shown in the trigger when no value is selected. Default: the catalogue's 「選択…」 / 'Chọn…' / 'Select…' — the same string with or without `showSearch`, so an unselected field never shows an empty trigger. Only a placeholder YOU pass can name an unlabelled trigger; the default never becomes the accessible name.",
85
85
  "name": "placeholder",
86
86
  "type": "string"
87
87
  },
@@ -6726,7 +6726,7 @@
6726
6726
  "type": "React.ReactNode"
6727
6727
  },
6728
6728
  {
6729
- "description": "Placeholder shown in the trigger when no value is selected.",
6729
+ "description": "Placeholder shown in the trigger when no value is selected. Default: the catalogue's 「選択…」 / 'Chọn…' / 'Select…' — the same string with or without `showSearch`, so an unselected field never shows an empty trigger. Only a placeholder YOU pass can name an unlabelled trigger; the default never becomes the accessible name.",
6730
6730
  "name": "placeholder",
6731
6731
  "type": "string"
6732
6732
  },
@@ -7992,7 +7992,7 @@
7992
7992
  "type": "boolean | { clearIcon?: ReactNode; label?: string }"
7993
7993
  },
7994
7994
  {
7995
- "description": "Accessible NAME of the calendar button. The default (「カレンダーを開く」 / 'Open calendar') is right for one picker on a page and useless for three: a screen-reader user hears the same sentence three times with nothing to say which field each button belongs to (WCAG 2.2 SC 2.4.6). Name it after the FIELD — `開始日のカレンダーを開く`. Same axis and same reason as Select's `clearLabel`.",
7995
+ "description": "Accessible NAME of the calendar button. The default (「カレンダーを開く」 / 'Open calendar') is right for one picker on a page and useless for three: a screen-reader user hears the same sentence three times with nothing to say which field each button belongs to (WCAG 2.2 SC 2.4.6). Name it after the FIELD — `開始日のカレンダーを開く`. Same axis and same reason as Select's `clearLabel`. The calendar DIALOG is named after the field too: the FormField label (or your `aria-labelledby` / `aria-label`) first, then `triggerLabel`, then the default.",
7996
7996
  "name": "triggerLabel",
7997
7997
  "type": "string"
7998
7998
  }
package/agent/index.json CHANGED
@@ -54,7 +54,7 @@
54
54
  "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.",
55
55
  "read": {
56
56
  "live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
57
- "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.12.6/agent/index.json"
57
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.12.8/agent/index.json"
58
58
  },
59
59
  "source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
60
60
  "start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
@@ -68,5 +68,5 @@
68
68
  "foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
69
69
  "semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
70
70
  },
71
- "version": "33.12.6"
71
+ "version": "33.12.8"
72
72
  }
package/agent/llms.txt CHANGED
@@ -1,10 +1,10 @@
1
1
  # @godxjp/ui
2
2
 
3
3
  > A Japanese-enterprise React design system: 169 components, 2241 design tokens,
4
- > 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.12.6.
4
+ > 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.12.8.
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@33.12.6`). It is searchable and version-locked. These files exist for agents
7
+ (`npx @godxjp/ui-mcp@33.12.8`). It is searchable and version-locked. These files exist for agents
8
8
  that can only fetch URLs.
9
9
 
10
10
  ## Start
@@ -27,7 +27,7 @@ that can only fetch URLs.
27
27
  ## Pinning
28
28
 
29
29
  Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
30
- the tag: `.../godx-jp/godxjp-ui/v33.12.6/agent/...`. A catalog that does not match the installed
30
+ the tag: `.../godx-jp/godxjp-ui/v33.12.8/agent/...`. A catalog that does not match the installed
31
31
  package describes props that are absent, or hides props that are present, and says nothing either way.
32
32
 
33
33
  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.
@@ -511,7 +511,8 @@ function DatePicker(props) {
511
511
  {
512
512
  id: dialogId,
513
513
  role: "dialog",
514
- "aria-label": (isPeriod ? t("dataEntry.monthPicker.openGrid") : t("dataEntry.datePicker.openCalendar")) ?? "Calendar",
514
+ "aria-labelledby": fieldA11y["aria-labelledby"],
515
+ "aria-label": fieldA11y["aria-labelledby"] !== void 0 ? void 0 : ariaProps["aria-label"] ?? triggerLabel ?? (isPeriod ? t("dataEntry.monthPicker.openGrid") : t("dataEntry.datePicker.openCalendar")) ?? "Calendar",
515
516
  className: isPeriod ? "ui-month-picker-panel" : "ui-control-panel-flush",
516
517
  side: placement.startsWith("top") ? "top" : "bottom",
517
518
  align: placement.endsWith("end") ? "end" : "start",
@@ -771,7 +771,7 @@ function DataSelect(props) {
771
771
  ...ariaProps,
772
772
  children: [
773
773
  prefix === void 0 || prefix === null ? null : /* @__PURE__ */ jsx("span", { "data-slot": "select-prefix", className: "ui-select-prefix", children: prefix }),
774
- /* @__PURE__ */ jsx(SelectValue, { placeholder, children: labelRender ? /* @__PURE__ */ jsx(DataSelectLabel, { labelRender, options }) : void 0 }),
774
+ /* @__PURE__ */ jsx(SelectValue, { placeholder: placeholder ?? t("dataEntry.searchSelect.placeholder"), children: labelRender ? /* @__PURE__ */ jsx(DataSelectLabel, { labelRender, options }) : void 0 }),
775
775
  suffixIcon === void 0 || suffixIcon === null || showClear || loading ? null : /* @__PURE__ */ jsx("span", { "data-slot": "select-suffix", className: "ui-select-suffix", "aria-hidden": "true", children: suffixIcon })
776
776
  ]
777
777
  }
@@ -116,7 +116,7 @@ function DialogShell({
116
116
  "data-slot": "dialog-overlay",
117
117
  "data-state": dataState,
118
118
  className: cn(OVERLAY_CLASS, overlayClassName),
119
- children: /* @__PURE__ */ jsx(Modal, { className: "contents", children: dialog })
119
+ children: /* @__PURE__ */ jsx(Modal, { className: "ui-overlay-modal contents", children: dialog })
120
120
  }
121
121
  );
122
122
  }
@@ -201,7 +201,7 @@ function SheetContent({
201
201
  "data-slot": "sheet-overlay",
202
202
  "data-state": dataState,
203
203
  className: cn(SHEET_OVERLAY_CLASS, overlayClassName),
204
- children: /* @__PURE__ */ jsx(Modal, { className: "contents", children: dialog })
204
+ children: /* @__PURE__ */ jsx(Modal, { className: "ui-overlay-modal contents", children: dialog })
205
205
  }
206
206
  );
207
207
  }
@@ -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": "33.12.6",
3
+ "version": "33.12.8",
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,6 +1,15 @@
1
1
  import * as React from "react";
2
2
  import type { TimelineGridProp } from "../props/components/data-display.prop.js";
3
3
  export type { TimelineGridColumnProp, TimelineGridEventProp, TimelineGridProp, TimelineGridProp as TimelineGridProps, } from "../props/components/data-display.prop.js";
4
+ export type TimelineGridEventLayout = {
5
+ mode: "compact" | "single";
6
+ } | {
7
+ mode: "stacked";
8
+ titleLines: number;
9
+ showDescription: boolean;
10
+ };
11
+ /** Layout of one block from its drawn length in minutes (already floored at the display minimum). */
12
+ export declare function eventTextLayout(drawnMinutes: number, hasDescription: boolean): TimelineGridEventLayout;
4
13
  /**
5
14
  * TimelineGrid — the time-axis half of the Timeline family: a vertical hour axis, one column per
6
15
  * day (or room, or machine) and event blocks placed by start time and duration.
@@ -26,6 +26,22 @@ function resolveEvent(event) {
26
26
  return { event, startMin, endMin: endMin > startMin ? endMin : endMin + MINUTES_PER_DAY };
27
27
  }
28
28
  const EVENT_MIN_MINUTES = 36;
29
+ const HOUR_HEIGHT_REM = 2.5;
30
+ const EVENT_GAP_REM = 0.25;
31
+ const EVENT_INSET_BLOCK_REM = 0.25;
32
+ const EVENT_LINE_REM = 1.1905;
33
+ function eventTextLayout(drawnMinutes, hasDescription) {
34
+ const bodyRem = drawnMinutes / 60 * HOUR_HEIGHT_REM - EVENT_GAP_REM;
35
+ const lines = Math.floor((bodyRem - 2 * EVENT_INSET_BLOCK_REM) / EVENT_LINE_REM);
36
+ if (lines < 1) return { mode: "compact" };
37
+ if (lines < 2) return { mode: "single" };
38
+ const showDescription = hasDescription && lines >= 3;
39
+ return { mode: "stacked", titleLines: lines - 1 - (showDescription ? 1 : 0), showDescription };
40
+ }
41
+ function plainText(node) {
42
+ if (typeof node === "string" || typeof node === "number") return String(node);
43
+ return null;
44
+ }
29
45
  function placeColumn(events) {
30
46
  const drawnEnd = (e) => Math.max(e.endMin, e.startMin + EVENT_MIN_MINUTES);
31
47
  const sorted = [...events].sort((a, b) => a.startMin - b.startMin || a.endMin - b.endMin);
@@ -188,22 +204,39 @@ function renderEvent(entry, axis, onEventSelect) {
188
204
  const clippedEnd = entry.endMin > axis.endMin;
189
205
  const clipped = clippedStart && clippedEnd ? "both" : clippedStart ? "start" : "end";
190
206
  const range = `${toClock(entry.startMin)}\u2013${toClock(entry.endMin)}`;
191
- const body = /* @__PURE__ */ jsxs(Fragment, { children: [
207
+ const layout = eventTextLayout(
208
+ Math.max(to - from, EVENT_MIN_MINUTES),
209
+ event.description !== void 0
210
+ );
211
+ const stacked = layout.mode === "stacked";
212
+ const titleText = plainText(event.title);
213
+ const descriptionText = plainText(event.description);
214
+ const fullName = titleText === null ? void 0 : [titleText, range, descriptionText].filter((part) => part !== null && part !== "").join(", ");
215
+ const title = /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-title", children: event.title });
216
+ const body = stacked ? /* @__PURE__ */ jsxs(Fragment, { children: [
217
+ title,
192
218
  /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-time", children: range }),
193
- /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-title", children: event.title }),
194
- event.description === void 0 ? null : /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-description", children: event.description })
219
+ layout.showDescription ? /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-description", children: event.description }) : null
220
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
221
+ title,
222
+ /* @__PURE__ */ jsxs("span", { className: "ui-timeline-grid-event-time", children: [
223
+ toClock(entry.startMin),
224
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `\u2013${toClock(entry.endMin)}` })
225
+ ] })
195
226
  ] });
196
227
  return /* @__PURE__ */ jsx(
197
228
  "li",
198
229
  {
199
230
  "data-event-id": event.id,
200
231
  "data-clipped": clippedStart || clippedEnd ? clipped : void 0,
232
+ "data-layout": layout.mode,
201
233
  className: "ui-timeline-grid-event",
202
234
  style: {
203
235
  "--timeline-grid-event-offset": (from - axis.startMin) / 60,
204
236
  "--timeline-grid-event-span": (to - from) / 60,
205
237
  "--timeline-grid-event-lane": entry.lane,
206
238
  "--timeline-grid-event-lanes": entry.lanes,
239
+ ...stacked ? { "--timeline-grid-event-title-lines": layout.titleLines } : null,
207
240
  ...event.color === void 0 || event.color === "" ? null : { "--timeline-grid-event-color": event.color }
208
241
  },
209
242
  children: onEventSelect ? /* @__PURE__ */ jsx(
@@ -211,14 +244,17 @@ function renderEvent(entry, axis, onEventSelect) {
211
244
  {
212
245
  type: "button",
213
246
  className: "ui-timeline-grid-event-body ui-focus-ring",
247
+ title: fullName,
248
+ "aria-label": fullName,
214
249
  onClick: () => onEventSelect(event),
215
250
  children: body
216
251
  }
217
- ) : /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-body", children: body })
252
+ ) : /* @__PURE__ */ jsx("span", { className: "ui-timeline-grid-event-body", title: fullName, children: body })
218
253
  },
219
254
  event.id
220
255
  );
221
256
  }
222
257
  export {
223
- TimelineGrid
258
+ TimelineGrid,
259
+ eventTextLayout
224
260
  };
@@ -2007,6 +2007,38 @@
2007
2007
  white-space: nowrap;
2008
2008
  }
2009
2009
 
2010
+ .ui-timeline-grid-event:is([data-layout="single"], [data-layout="compact"])
2011
+ .ui-timeline-grid-event-body {
2012
+ flex-direction: row;
2013
+ align-items: baseline;
2014
+ gap: var(--space-1);
2015
+ }
2016
+
2017
+ .ui-timeline-grid-event[data-layout="compact"] .ui-timeline-grid-event-body {
2018
+ align-items: center;
2019
+ padding-block: 0;
2020
+ }
2021
+
2022
+ .ui-timeline-grid-event:is([data-layout="single"], [data-layout="compact"])
2023
+ .ui-timeline-grid-event-title {
2024
+ min-inline-size: 0;
2025
+ }
2026
+
2027
+ .ui-timeline-grid-event:is([data-layout="single"], [data-layout="compact"])
2028
+ .ui-timeline-grid-event-time {
2029
+ flex: none;
2030
+ }
2031
+
2032
+ .ui-timeline-grid-event[data-layout="stacked"] .ui-timeline-grid-event-title {
2033
+ display: -webkit-box;
2034
+ flex: none;
2035
+ -webkit-box-orient: vertical;
2036
+ -webkit-line-clamp: var(--timeline-grid-event-title-lines, 1);
2037
+ line-clamp: var(--timeline-grid-event-title-lines, 1);
2038
+ overflow-wrap: anywhere;
2039
+ white-space: normal;
2040
+ }
2041
+
2010
2042
  .ui-timeline-grid-event-description {
2011
2043
  overflow: hidden;
2012
2044
  color: var(--timeline-grid-event-muted-color);
@@ -188,6 +188,10 @@
188
188
  opacity: 1;
189
189
  }
190
190
 
191
+ .ui-overlay-modal:has(> section > :is(.ui-dialog-close, .ui-sheet-close)) > :not(section) {
192
+ display: none;
193
+ }
194
+
191
195
  [data-slot="dialog-title"] {
192
196
  font-size: var(
193
197
  --font-size-lg,
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "33.12.6",
2
+ "version": "33.12.8",
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",