@godxjp/ui 31.0.2 → 31.0.4
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/i18n/translate.d.ts +2 -0
- package/dist/i18n/translate.js +7 -0
- package/dist/i18n/use-translation.d.ts +5 -4
- package/dist/i18n/use-translation.js +28 -7
- package/dist/styles/layers.json +1 -1
- package/dist/styles/shell-layout.css +2 -0
- package/docs/CONSUMER-RULES.md +1 -1
- package/package.json +2 -2
- package/scripts/consumer-rule.md +8 -0
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` 31.0.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 31.0.4.** 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/v31.0.
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.0.4/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.0.
|
|
65
|
+
"version": "31.0.4"
|
|
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: 175 components, 2074 design tokens,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.0.
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.0.4.
|
|
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.0.
|
|
7
|
+
(`npx @godxjp/ui-mcp@31.0.4`). 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.0.
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v31.0.4/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": "31.0.
|
|
3
|
+
"version": "31.0.4",
|
|
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/i18n/translate.d.ts
CHANGED
|
@@ -28,6 +28,8 @@ export declare function translate(locale: AppLocale, fallbackLocale: AppLocale,
|
|
|
28
28
|
/** Non-React translate using module-synced locale (see `syncI18nLocale`). */
|
|
29
29
|
export declare function translateCurrent(key: MessageKey, params?: TranslateParams): string;
|
|
30
30
|
export declare function syncI18nLocale(locale: AppLocale, fallbackLocale: AppLocale): void;
|
|
31
|
+
/** Whether anything has ever called `syncI18nLocale` — the resting "vi" was never CHOSEN. */
|
|
32
|
+
export declare function isI18nLocaleSynced(): boolean;
|
|
31
33
|
export declare function getSyncedLocale(): AppLocale;
|
|
32
34
|
export declare function getSyncedFallbackLocale(): AppLocale;
|
|
33
35
|
/** Reset for tests. */
|
package/dist/i18n/translate.js
CHANGED
|
@@ -81,9 +81,14 @@ function translateCurrent(key, params) {
|
|
|
81
81
|
}
|
|
82
82
|
let syncedLocale = "vi";
|
|
83
83
|
let syncedFallbackLocale = "en";
|
|
84
|
+
let syncedByCaller = false;
|
|
84
85
|
function syncI18nLocale(locale, fallbackLocale) {
|
|
85
86
|
syncedLocale = locale;
|
|
86
87
|
syncedFallbackLocale = fallbackLocale;
|
|
88
|
+
syncedByCaller = true;
|
|
89
|
+
}
|
|
90
|
+
function isI18nLocaleSynced() {
|
|
91
|
+
return syncedByCaller;
|
|
87
92
|
}
|
|
88
93
|
function getSyncedLocale() {
|
|
89
94
|
return syncedLocale;
|
|
@@ -94,11 +99,13 @@ function getSyncedFallbackLocale() {
|
|
|
94
99
|
function resetI18nLocale() {
|
|
95
100
|
syncedLocale = "vi";
|
|
96
101
|
syncedFallbackLocale = "en";
|
|
102
|
+
syncedByCaller = false;
|
|
97
103
|
}
|
|
98
104
|
export {
|
|
99
105
|
MESSAGE_CATALOG,
|
|
100
106
|
getSyncedFallbackLocale,
|
|
101
107
|
getSyncedLocale,
|
|
108
|
+
isI18nLocaleSynced,
|
|
102
109
|
registerMessages,
|
|
103
110
|
resetI18nLocale,
|
|
104
111
|
syncI18nLocale,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import type { DayPickerProps } from "react-day-picker";
|
|
2
|
-
import type { AppLocale } from "../app/types.js";
|
|
3
2
|
import { type MessageKey, type TranslateParams } from "./translate.js";
|
|
3
|
+
/** Test seam: the once-only warning is module state. */
|
|
4
|
+
export declare function resetOutsideProviderWarningForTests(): void;
|
|
4
5
|
type DayPickerLocale = NonNullable<DayPickerProps["locale"]>;
|
|
5
6
|
export declare function useTranslation(): {
|
|
6
|
-
locale: AppLocale;
|
|
7
|
-
fallbackLocale: AppLocale;
|
|
7
|
+
locale: import("../app/index.js").AppLocale;
|
|
8
|
+
fallbackLocale: import("../app/index.js").AppLocale;
|
|
8
9
|
t: (key: MessageKey, params?: TranslateParams) => string;
|
|
9
10
|
};
|
|
10
11
|
/** date-fns + react-day-picker locales + datetime prefs from AppProvider. */
|
|
11
12
|
export declare function usePickerLocales(dayPickerOverride?: DayPickerLocale): {
|
|
12
|
-
locale: AppLocale;
|
|
13
|
+
locale: import("../app/index.js").AppLocale;
|
|
13
14
|
timezone: string;
|
|
14
15
|
timeFormat: import("../app/index.js").AppTimeFormat;
|
|
15
16
|
dateFormat: import("../app/index.js").AppDateFormat;
|
|
@@ -2,13 +2,30 @@
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { useOptionalAppContext } from "../app/app-provider.js";
|
|
4
4
|
import { getDateFnsLocale, getDayPickerLocale } from "../app/locales.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { resolveHydrationSafeTimezone } from "../app/timezones.js";
|
|
6
|
+
import { isDevelopment } from "../lib/dev.js";
|
|
7
|
+
import {
|
|
8
|
+
getSyncedFallbackLocale,
|
|
9
|
+
getSyncedLocale,
|
|
10
|
+
isI18nLocaleSynced,
|
|
11
|
+
translate
|
|
12
|
+
} from "./translate.js";
|
|
13
|
+
let warnedOutsideProvider = false;
|
|
14
|
+
function warnOutsideProvider(locale) {
|
|
15
|
+
if (warnedOutsideProvider || !isDevelopment() || isI18nLocaleSynced()) return;
|
|
16
|
+
warnedOutsideProvider = true;
|
|
17
|
+
console.warn(
|
|
18
|
+
`[@godxjp/ui] A kit component rendered outside <AppProvider>, so its built-in strings (close/cancel/delete labels, counters, pickers) use the resting locale "${locale}" \u2014 nothing chose it. Wrap the app in <AppProvider defaultLocale="\u2026"> (docs/CONSUMER-RULES.md), or call syncI18nLocale(locale, fallback) at startup if you truly cannot. Shown once.`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function resetOutsideProviderWarningForTests() {
|
|
22
|
+
warnedOutsideProvider = false;
|
|
23
|
+
}
|
|
8
24
|
function useTranslation() {
|
|
9
25
|
const ctx = useOptionalAppContext();
|
|
10
|
-
const locale = ctx?.locale ??
|
|
11
|
-
const fallbackLocale = ctx?.fallbackLocale ??
|
|
26
|
+
const locale = ctx?.locale ?? getSyncedLocale();
|
|
27
|
+
const fallbackLocale = ctx?.fallbackLocale ?? getSyncedFallbackLocale();
|
|
28
|
+
if (!ctx) warnOutsideProvider(locale);
|
|
12
29
|
return useMemo(
|
|
13
30
|
() => ({
|
|
14
31
|
locale,
|
|
@@ -20,11 +37,14 @@ function useTranslation() {
|
|
|
20
37
|
}
|
|
21
38
|
function usePickerLocales(dayPickerOverride) {
|
|
22
39
|
const ctx = useOptionalAppContext();
|
|
23
|
-
const locale = ctx?.locale ??
|
|
40
|
+
const locale = ctx?.locale ?? getSyncedLocale();
|
|
41
|
+
if (!ctx) warnOutsideProvider(locale);
|
|
24
42
|
return useMemo(
|
|
25
43
|
() => ({
|
|
26
44
|
locale,
|
|
27
|
-
|
|
45
|
+
// AppProvider's own unconfigured answer (gh#968) — a zone that looks right when it is wrong
|
|
46
|
+
// (Asia/Ho_Chi_Minh) is worse than one that is visibly not local.
|
|
47
|
+
timezone: ctx?.timezone ?? resolveHydrationSafeTimezone("browser"),
|
|
28
48
|
timeFormat: ctx?.timeFormat ?? "24h",
|
|
29
49
|
dateFormat: ctx?.dateFormat ?? "dmy",
|
|
30
50
|
dateFnsLocale: ctx?.dateFnsLocale ?? getDateFnsLocale(locale),
|
|
@@ -42,6 +62,7 @@ function usePickerLocales(dayPickerOverride) {
|
|
|
42
62
|
);
|
|
43
63
|
}
|
|
44
64
|
export {
|
|
65
|
+
resetOutsideProviderWarningForTests,
|
|
45
66
|
usePickerLocales,
|
|
46
67
|
useTranslation
|
|
47
68
|
};
|
package/dist/styles/layers.json
CHANGED
package/docs/CONSUMER-RULES.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Read this once; the audit enforces it. Everything else in `docs/` is for contributors.
|
|
4
4
|
|
|
5
5
|
1. Load styles with `@import "@godxjp/ui/styles"` (fonts bundled, 729 sliced woff2 faces, ~11.7 MB), `@import "@godxjp/ui/styles/core"` (no `@font-face` at all), `@import "@godxjp/ui/styles/core-with-fallbacks"` (`core` + six `local()`-only metric-matched faces, still zero network bytes — for when you supply Noto Sans JP yourself) or `@import "@godxjp/ui/styles/core-with-jis-level1"` (`core-with-fallbacks` + Noto Sans JP merged to JIS X 0208 level 1: **3 requests, ~1.53 MB, once** instead of ~8 font requests on every navigation — for a Japanese app that wants the bundled face). Never cherry-pick `*-layout.css`.
|
|
6
|
-
2. Every page is `<PageContainer title subtitle extra footer>`; its sections are spaced by the page. Group items inside a section with `<Flex direction="col" gap>` or `<ResponsiveGrid>`.
|
|
6
|
+
2. **Mount `<AppProvider defaultLocale="…">` once, at the root.** Without it the kit's OWN strings (dialog close/cancel/delete, counters, picker labels) fall to the resting locale `vi` and pickers to UTC — measured in a Japanese app as Vietnamese buttons, silently (gh#1005). A development build now warns once when a kit component renders outside it; `syncI18nLocale(locale, fallback)` is the escape for an app that truly cannot mount the provider. Every page is `<PageContainer title subtitle extra footer>`; its sections are spaced by the page. Group items inside a section with `<Flex direction="col" gap>` or `<ResponsiveGrid>`.
|
|
7
7
|
3. No Tailwind layout on your own elements: no `flex`, `grid`, `gap-*`, `p-*`, `m-*`, `space-*`. Rows are `<Flex>` (default row), stacks are `<Flex direction="col">`, grids are `<ResponsiveGrid>`.
|
|
8
8
|
4. No hand-rolled surfaces: no `rounded-* border bg-*` divs. A box is `Card`, a pill is `Badge`, a person is `Avatar`, a row is `ListRow`, a label/value pair is `Descriptions`, an empty area is `EmptyState`, a read-only sample of a colour the USER chose is `Swatch`. A LIST of those rows is `<Flex as="ul" marker="none" direction="col" gap="none">` with `<ListRow as="li">` children — `marker="none"` keeps the `<ul>`, the `<li>` semantics and the gap token while dropping the bullet and the indent. Never a raw `<ul>`/`<ol>` (it carries no gap token), never `<div role="list">` + `<div role="listitem">`, and never a wrapper around each row: the divider is `:not(:last-child)` among siblings, so a row alone in its own wrapper is always the last one and EVERY divider disappears silently. A bulleted prose list is the same `<Flex as="ul">` without `marker`.
|
|
9
9
|
5. Real controls only: `Button`, `Input`, `Select`, `Textarea`, `Checkbox`… never raw `<button>`/`<input>`; a labelled control lives in `<FormField label>`. A Select outside a form takes `width="auto"`. **A disabled control's reason is visible text, never a tooltip** — see below. **Fields live in a `<Form layout="horizontal" labelWidth controlWidth>`** — never a group of `FormField`s without one, never a hand-rolled `<Flex>` row of fields (a row that belongs together is `<SpaceCompact>` or `<Form columns>`); size each control for its content with `controlWidth` (GOV.UK text-input width: a port ~7rem, a short enum ~10rem); three or more fields is a page, not a Dialog. The audit rules are `formfield-needs-form`, `dialog-form-too-big` and `select-width-hint`. **A case the kit cannot express is an issue, not a hand-roll:** open it on godx-jp/godxjp-ui, use the nearest valid composition, and mark it `// TODO(godxjp-ui#<n>)` (gh#998).
|
package/package.json
CHANGED
package/scripts/consumer-rule.md
CHANGED
|
@@ -120,6 +120,14 @@ ngày: năm thứ cần đều ĐÃ CÓ và vẫn bị dựng lại bằng thứ
|
|
|
120
120
|
Lỗi không phải "đoán sai tên prop" mà là **cho rằng nó không tồn tại nên không
|
|
121
121
|
hỏi**.
|
|
122
122
|
|
|
123
|
+
## `AppProvider` là bắt buộc — thiếu nó, chuỗi của kit nói tiếng Việt
|
|
124
|
+
|
|
125
|
+
Mount `<AppProvider defaultLocale="ja">` MỘT lần ở gốc app. Thiếu nó, chuỗi của chính kit (nút
|
|
126
|
+
đóng/hủy/xóa của dialog, upload, badge đếm, nhãn picker) rơi về locale nghỉ `vi` và picker rơi về
|
|
127
|
+
UTC — godx-mailer đo được nút tiếng Việt giữa UI tiếng Nhật, không một cảnh báo (gh#1005). Bản dev
|
|
128
|
+
giờ cảnh báo MỘT lần khi component của kit render ngoài provider. Không mount được provider thì gọi
|
|
129
|
+
`syncI18nLocale(locale, fallback)` lúc khởi động.
|
|
130
|
+
|
|
123
131
|
## Form: `Form` bọc `FormField`, bề rộng theo nội dung, form dài là PAGE
|
|
124
132
|
|
|
125
133
|
godx-mailer dính bốn lỗi form trong một ngày, cả bốn đều là kit ĐÃ CÓ đồ đúng
|