@godxjp/ui 33.4.2 → 33.6.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.
- package/agent/START-HERE.md +1 -1
- package/agent/components/AppProvider.json +6 -0
- package/agent/components/Logo.json +1 -1
- package/agent/components/TranslatableInput.json +3 -2
- package/agent/components/TranslatableTextarea.json +2 -2
- package/agent/components.json +12 -5
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/agent/tokens.json +4 -4
- package/dist/app/app-provider.d.ts +1 -1
- package/dist/app/app-provider.js +9 -0
- package/dist/brand/godx-artwork.generated.js +4 -4
- package/dist/brand/godx-mark.d.ts +2 -2
- package/dist/components/data-entry/translatable-input.d.ts +2 -2
- package/dist/components/data-entry/translatable-input.js +6 -3
- package/dist/contracts/measurement.json +1 -1
- package/dist/email/tokens.generated.d.ts +6 -6
- package/dist/email/tokens.generated.js +6 -6
- package/dist/props/components/app.prop.d.ts +11 -0
- package/dist/props/components/data-entry.prop.d.ts +7 -3
- package/dist/styles/layers.json +1 -1
- package/dist/themes/godx-tokens.css +22 -18
- package/dist/themes/godx.d.ts +1 -1
- package/dist/themes/godx.js +4 -1
- package/docs/CUSTOMER-THEMING.md +6 -5
- package/docs/DESIGN-AUTHORITY.md +6 -1
- package/package.json +2 -2
- package/scripts/brand-accent.generated.mjs +5 -30
- package/scripts/visual-audit-rules.mjs +6 -2
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` 33.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 33.6.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.
|
|
@@ -68,6 +68,11 @@
|
|
|
68
68
|
"name": "persist",
|
|
69
69
|
"type": "boolean | readonly AppPreferenceAxis[]"
|
|
70
70
|
},
|
|
71
|
+
{
|
|
72
|
+
"description": "The languages the app stores USER CONTENT in, in order, source language first — e.g. `[\"ja\", \"en\", \"vi\"]` for a Japanese-first catalogue (gh#1347). A different fact from the UI locale (`defaultLocale`) and from the registered UI catalogs: a Japanese UI can edit content in three languages, and content may be stored in a language the UI has no catalog for. Every `TranslatableInput` / `TranslatableTextarea` without its own `locales` takes its tabs from this list and opens on its first entry; a field's `locales` / `defaultLocale` still override. Omit (or `[]`) to keep the field default (`getRegisteredLocales()`, first tab = the UI locale). App configuration: not persisted, no setter. Read it from `useAppContext().contentLocales` (`undefined` when unset).",
|
|
73
|
+
"name": "contentLocales",
|
|
74
|
+
"type": "readonly string[]"
|
|
75
|
+
},
|
|
71
76
|
{
|
|
72
77
|
"defaultValue": "false",
|
|
73
78
|
"description": "OFF by default and deliberately opt-in: `name` decides what a native <form> submit sends, so switching it on for every consumer of a shared package would make apps start posting new keys to their backend on a library upgrade. Turn it on for apps that need native form posts or a screen-automation (RPA) contract on their controls. The inert `data-field` companion attribute is emitted regardless; a `name` written on the control itself always wins. NOT persisted to localStorage: it is the app's configuration, not a user choice.",
|
|
@@ -100,6 +105,7 @@
|
|
|
100
105
|
"DO set `defaultTimezone='system'` together with `systemTimezone={serverTimezone}` when your backend knows the legal entity's canonical timezone (e.g. 'Asia/Ho_Chi_Minh'). Use `defaultTimezone='browser'` (the default) only when you want the user's browser clock. Do NOT pass a raw IANA string to `defaultTimezone` if the user may be in a different zone — use the named aliases.",
|
|
101
106
|
"DO wire `onLocaleChange`, `onTimezoneChange`, `onTimeFormatChange`, `onDateFormatChange` to persist changes server-side (e.g. patch user profile via Inertia router) in addition to the automatic localStorage write. These callbacks fire after state is set, so the new value is already reflected in context.",
|
|
102
107
|
"DO set `emitFieldNames` on AppProvider when the app is driven by screen automation (RPA) or posts native forms — every control under a FormField then carries a real `name` taken from the field key, and legacy automation that addressed controls by `name` keeps working after a rewrite. Leave it off (the default) otherwise: it changes what a native submit sends. The `data-field` attribute is emitted either way, so e2e selectors do not depend on this flag.",
|
|
108
|
+
"DO pass `contentLocales` when the app edits translatable content (`TranslatableInput` / `TranslatableTextarea`) — `contentLocales={[\"ja\", \"en\", \"vi\"]}` — so the tab order and the source-language first tab are stated once, not repeated as `locales` on every field. It is NOT the UI language list: leave `defaultLocale` / `registerLocale` to the UI.",
|
|
103
109
|
"DO restrict the timezone dropdown by passing `timezoneOptions={APP_TIMEZONE_PRESET}` (an exported constant) to AppProvider — every `AppSettingPicker kind=\"timezone\"` inherits this restricted list from context. Without it the picker offers the full IANA list (~600 entries)."
|
|
104
110
|
],
|
|
105
111
|
"useCases": [
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"DO use `<Logo mark=\"godx-lockup\" productSuffix=\"ID\" />` for a product surface branded \"GoDX | ID\" — the divider, the gaps, the `size` scale and the light/dark master are the package's. DON'T inline the kit's flattened \"GoDX | ID\" SVG in the app: it is a second master in its own coordinate system, with global `id=\"title\"`/`id=\"desc\"` that collide across instances, a hardcoded `#0B0F3B` ink with no dark variant, and a hardcoded `#C5C8D6` rule (gh#649).",
|
|
71
71
|
"DON'T typeset the suffix yourself as `<Logo mark=\"godx-lockup\" /><Text>ID</Text>` — that has no divider and the spacing is not the lockup's token.",
|
|
72
72
|
"DON'T re-tint via `className=\"bg-*\"` — the fill reads the `--primary` role token; retune it through a service theme (`--primary`, `--logo-radius`, `--logo-size-*`), not utilities.",
|
|
73
|
-
"GoDX LOOK = THE PRESET (v32): the package defaults are neutral (ink `--primary`, no product mark). A GoDX surface gets the
|
|
73
|
+
"GoDX LOOK = THE PRESET (v32): the package defaults are neutral (ink `--primary`, no product mark). A GoDX surface gets the emerald-teal identity (#008066, gh#1345), the fonts and the GoDX mark in AuthIdentity from `import \"@godxjp/ui/themes/godx.css\"` (after the base stylesheet) plus `import { godxPreset } from \"@godxjp/ui/themes/godx\"` and `<AppProvider preset={godxPreset}>`. `mark=\"godx\"` / `\"godx-lockup\"` still render the GoDX artwork wherever you place them explicitly.",
|
|
74
74
|
"DO use `mark=\"godx\"` for the canonical GoDX identity mark on hosted-identity screens — it is ALREADY in the package as real inline vector artwork. DON'T pass a hand-drawn brand SVG as `glyph`, and don't ship a brand asset in the app, to reproduce it.",
|
|
75
75
|
"DO make the brand a link with `asChild`, not with a wrapper: `<Logo asChild mark=\"godx\" wordmark=\"GoDX\"><Link href=\"/\" /></Logo>`. Writing `<a className=\"flex\"><Logo …/></a>` instead is the exact shape ui-audit rejects (no-utility-layout), and dropping the `flex` misaligns the mark."
|
|
76
76
|
],
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"type": "(value: TranslatableValue) => void"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"description": "The BCP-47 tags the field edits, in tab order. Default: every locale registered with the app (`getRegisteredLocales()` — built-in `vi`/`en`/`ja` plus `registerLocale`). Tabs are named by `Intl.DisplayNames` in the reader's UI language; the tags stay the keys.",
|
|
23
|
+
"description": "The BCP-47 tags the field edits, in tab order. Default: AppProvider `contentLocales` when set (gh#1347 — state the content languages once at the root instead of on every field), else every locale registered with the app (`getRegisteredLocales()` — built-in `vi`/`en`/`ja` plus `registerLocale`). Tabs are named by `Intl.DisplayNames` in the reader's UI language; the tags stay the keys.",
|
|
24
24
|
"name": "locales",
|
|
25
25
|
"type": "readonly string[]"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"description": "The locale tab selected first. Default: the AppProvider's active locale when it is in `locales`, else the fallback locale.",
|
|
28
|
+
"description": "The locale tab selected first. Default: the first of AppProvider `contentLocales` (the source language) when set and in `locales`, else the AppProvider's active locale when it is in `locales`, else the fallback locale.",
|
|
29
29
|
"name": "defaultLocale",
|
|
30
30
|
"type": "string"
|
|
31
31
|
},
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"storyPath": "data-entry/translatable-input.tsx",
|
|
78
78
|
"tagline": "ONE text field holding a value per locale (`{ ja, en, vi }`), switched by locale tabs above it (gh#1336). For user content stored per locale — a product name, a category label, a menu description (Astrotomic / Spatie `*_translations`). Locales, first tab and fallback come from AppProvider; an empty locale shows the fallback locale's text as its placeholder; a locale with an error is marked on its tab. Every other `Input` prop applies to the one control.",
|
|
79
79
|
"usage": [
|
|
80
|
+
"DO set the app's content languages ONCE on the root provider — `<AppProvider contentLocales={[\"ja\", \"en\", \"vi\"]}>` — when every translatable field edits the same list; each field then needs no `locales` and opens on the source language (the first). Pass `locales` on a field only where it differs.",
|
|
80
81
|
"DO wrap it in FormField: the label names the control together with the active locale («商品名 English») and names the tab strip («商品名 Language»), `required`/`helper` reach the control, and the active locale's error renders in FormField's error line.",
|
|
81
82
|
"DO pass the per-locale error map from your validator as `errors` (e.g. Laravel `name.ja` → `errors.ja`). Don't pass the same message to FormField `error` as well: FormField's own `error` wins over the reported one, and it would mark the field invalid on every locale.",
|
|
82
83
|
"DO set `fallbackLocale` to the content's SOURCE language (often `ja`) when it differs from the AppProvider's UI fallback — the placeholder of an untranslated locale then shows the source text to translate from.",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"type": "(value: TranslatableValue) => void"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"description": "The BCP-47 tags the field edits, in tab order. Default: the app's registered locales.",
|
|
23
|
+
"description": "The BCP-47 tags the field edits, in tab order. Default: AppProvider `contentLocales` when set, else the app's registered locales.",
|
|
24
24
|
"name": "locales",
|
|
25
25
|
"type": "readonly string[]"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"description": "The locale tab selected first. Default: the AppProvider's active locale.",
|
|
28
|
+
"description": "The locale tab selected first. Default: the first of AppProvider `contentLocales` when set and in `locales`, else the AppProvider's active locale.",
|
|
29
29
|
"name": "defaultLocale",
|
|
30
30
|
"type": "string"
|
|
31
31
|
},
|
package/agent/components.json
CHANGED
|
@@ -3146,7 +3146,7 @@
|
|
|
3146
3146
|
"DO use `<Logo mark=\"godx-lockup\" productSuffix=\"ID\" />` for a product surface branded \"GoDX | ID\" — the divider, the gaps, the `size` scale and the light/dark master are the package's. DON'T inline the kit's flattened \"GoDX | ID\" SVG in the app: it is a second master in its own coordinate system, with global `id=\"title\"`/`id=\"desc\"` that collide across instances, a hardcoded `#0B0F3B` ink with no dark variant, and a hardcoded `#C5C8D6` rule (gh#649).",
|
|
3147
3147
|
"DON'T typeset the suffix yourself as `<Logo mark=\"godx-lockup\" /><Text>ID</Text>` — that has no divider and the spacing is not the lockup's token.",
|
|
3148
3148
|
"DON'T re-tint via `className=\"bg-*\"` — the fill reads the `--primary` role token; retune it through a service theme (`--primary`, `--logo-radius`, `--logo-size-*`), not utilities.",
|
|
3149
|
-
"GoDX LOOK = THE PRESET (v32): the package defaults are neutral (ink `--primary`, no product mark). A GoDX surface gets the
|
|
3149
|
+
"GoDX LOOK = THE PRESET (v32): the package defaults are neutral (ink `--primary`, no product mark). A GoDX surface gets the emerald-teal identity (#008066, gh#1345), the fonts and the GoDX mark in AuthIdentity from `import \"@godxjp/ui/themes/godx.css\"` (after the base stylesheet) plus `import { godxPreset } from \"@godxjp/ui/themes/godx\"` and `<AppProvider preset={godxPreset}>`. `mark=\"godx\"` / `\"godx-lockup\"` still render the GoDX artwork wherever you place them explicitly.",
|
|
3150
3150
|
"DO use `mark=\"godx\"` for the canonical GoDX identity mark on hosted-identity screens — it is ALREADY in the package as real inline vector artwork. DON'T pass a hand-drawn brand SVG as `glyph`, and don't ship a brand asset in the app, to reproduce it.",
|
|
3151
3151
|
"DO make the brand a link with `asChild`, not with a wrapper: `<Logo asChild mark=\"godx\" wordmark=\"GoDX\"><Link href=\"/\" /></Logo>`. Writing `<a className=\"flex\"><Logo …/></a>` instead is the exact shape ui-audit rejects (no-utility-layout), and dropping the `flex` misaligns the mark."
|
|
3152
3152
|
],
|
|
@@ -7148,12 +7148,12 @@
|
|
|
7148
7148
|
"type": "(value: TranslatableValue) => void"
|
|
7149
7149
|
},
|
|
7150
7150
|
{
|
|
7151
|
-
"description": "The BCP-47 tags the field edits, in tab order. Default: every locale registered with the app (`getRegisteredLocales()` — built-in `vi`/`en`/`ja` plus `registerLocale`). Tabs are named by `Intl.DisplayNames` in the reader's UI language; the tags stay the keys.",
|
|
7151
|
+
"description": "The BCP-47 tags the field edits, in tab order. Default: AppProvider `contentLocales` when set (gh#1347 — state the content languages once at the root instead of on every field), else every locale registered with the app (`getRegisteredLocales()` — built-in `vi`/`en`/`ja` plus `registerLocale`). Tabs are named by `Intl.DisplayNames` in the reader's UI language; the tags stay the keys.",
|
|
7152
7152
|
"name": "locales",
|
|
7153
7153
|
"type": "readonly string[]"
|
|
7154
7154
|
},
|
|
7155
7155
|
{
|
|
7156
|
-
"description": "The locale tab selected first. Default: the AppProvider's active locale when it is in `locales`, else the fallback locale.",
|
|
7156
|
+
"description": "The locale tab selected first. Default: the first of AppProvider `contentLocales` (the source language) when set and in `locales`, else the AppProvider's active locale when it is in `locales`, else the fallback locale.",
|
|
7157
7157
|
"name": "defaultLocale",
|
|
7158
7158
|
"type": "string"
|
|
7159
7159
|
},
|
|
@@ -7205,6 +7205,7 @@
|
|
|
7205
7205
|
"storyPath": "data-entry/translatable-input.tsx",
|
|
7206
7206
|
"tagline": "ONE text field holding a value per locale (`{ ja, en, vi }`), switched by locale tabs above it (gh#1336). For user content stored per locale — a product name, a category label, a menu description (Astrotomic / Spatie `*_translations`). Locales, first tab and fallback come from AppProvider; an empty locale shows the fallback locale's text as its placeholder; a locale with an error is marked on its tab. Every other `Input` prop applies to the one control.",
|
|
7207
7207
|
"usage": [
|
|
7208
|
+
"DO set the app's content languages ONCE on the root provider — `<AppProvider contentLocales={[\"ja\", \"en\", \"vi\"]}>` — when every translatable field edits the same list; each field then needs no `locales` and opens on the source language (the first). Pass `locales` on a field only where it differs.",
|
|
7208
7209
|
"DO wrap it in FormField: the label names the control together with the active locale («商品名 English») and names the tab strip («商品名 Language»), `required`/`helper` reach the control, and the active locale's error renders in FormField's error line.",
|
|
7209
7210
|
"DO pass the per-locale error map from your validator as `errors` (e.g. Laravel `name.ja` → `errors.ja`). Don't pass the same message to FormField `error` as well: FormField's own `error` wins over the reported one, and it would mark the field invalid on every locale.",
|
|
7210
7211
|
"DO set `fallbackLocale` to the content's SOURCE language (often `ja`) when it differs from the AppProvider's UI fallback — the placeholder of an untranslated locale then shows the source text to translate from.",
|
|
@@ -7240,12 +7241,12 @@
|
|
|
7240
7241
|
"type": "(value: TranslatableValue) => void"
|
|
7241
7242
|
},
|
|
7242
7243
|
{
|
|
7243
|
-
"description": "The BCP-47 tags the field edits, in tab order. Default: the app's registered locales.",
|
|
7244
|
+
"description": "The BCP-47 tags the field edits, in tab order. Default: AppProvider `contentLocales` when set, else the app's registered locales.",
|
|
7244
7245
|
"name": "locales",
|
|
7245
7246
|
"type": "readonly string[]"
|
|
7246
7247
|
},
|
|
7247
7248
|
{
|
|
7248
|
-
"description": "The locale tab selected first. Default: the AppProvider's active locale.",
|
|
7249
|
+
"description": "The locale tab selected first. Default: the first of AppProvider `contentLocales` when set and in `locales`, else the AppProvider's active locale.",
|
|
7249
7250
|
"name": "defaultLocale",
|
|
7250
7251
|
"type": "string"
|
|
7251
7252
|
},
|
|
@@ -9059,6 +9060,11 @@
|
|
|
9059
9060
|
"name": "persist",
|
|
9060
9061
|
"type": "boolean | readonly AppPreferenceAxis[]"
|
|
9061
9062
|
},
|
|
9063
|
+
{
|
|
9064
|
+
"description": "The languages the app stores USER CONTENT in, in order, source language first — e.g. `[\"ja\", \"en\", \"vi\"]` for a Japanese-first catalogue (gh#1347). A different fact from the UI locale (`defaultLocale`) and from the registered UI catalogs: a Japanese UI can edit content in three languages, and content may be stored in a language the UI has no catalog for. Every `TranslatableInput` / `TranslatableTextarea` without its own `locales` takes its tabs from this list and opens on its first entry; a field's `locales` / `defaultLocale` still override. Omit (or `[]`) to keep the field default (`getRegisteredLocales()`, first tab = the UI locale). App configuration: not persisted, no setter. Read it from `useAppContext().contentLocales` (`undefined` when unset).",
|
|
9065
|
+
"name": "contentLocales",
|
|
9066
|
+
"type": "readonly string[]"
|
|
9067
|
+
},
|
|
9062
9068
|
{
|
|
9063
9069
|
"defaultValue": "false",
|
|
9064
9070
|
"description": "OFF by default and deliberately opt-in: `name` decides what a native <form> submit sends, so switching it on for every consumer of a shared package would make apps start posting new keys to their backend on a library upgrade. Turn it on for apps that need native form posts or a screen-automation (RPA) contract on their controls. The inert `data-field` companion attribute is emitted regardless; a `name` written on the control itself always wins. NOT persisted to localStorage: it is the app's configuration, not a user choice.",
|
|
@@ -9091,6 +9097,7 @@
|
|
|
9091
9097
|
"DO set `defaultTimezone='system'` together with `systemTimezone={serverTimezone}` when your backend knows the legal entity's canonical timezone (e.g. 'Asia/Ho_Chi_Minh'). Use `defaultTimezone='browser'` (the default) only when you want the user's browser clock. Do NOT pass a raw IANA string to `defaultTimezone` if the user may be in a different zone — use the named aliases.",
|
|
9092
9098
|
"DO wire `onLocaleChange`, `onTimezoneChange`, `onTimeFormatChange`, `onDateFormatChange` to persist changes server-side (e.g. patch user profile via Inertia router) in addition to the automatic localStorage write. These callbacks fire after state is set, so the new value is already reflected in context.",
|
|
9093
9099
|
"DO set `emitFieldNames` on AppProvider when the app is driven by screen automation (RPA) or posts native forms — every control under a FormField then carries a real `name` taken from the field key, and legacy automation that addressed controls by `name` keeps working after a rewrite. Leave it off (the default) otherwise: it changes what a native submit sends. The `data-field` attribute is emitted either way, so e2e selectors do not depend on this flag.",
|
|
9100
|
+
"DO pass `contentLocales` when the app edits translatable content (`TranslatableInput` / `TranslatableTextarea`) — `contentLocales={[\"ja\", \"en\", \"vi\"]}` — so the tab order and the source-language first tab are stated once, not repeated as `locales` on every field. It is NOT the UI language list: leave `defaultLocale` / `registerLocale` to the UI.",
|
|
9094
9101
|
"DO restrict the timezone dropdown by passing `timezoneOptions={APP_TIMEZONE_PRESET}` (an exported constant) to AppProvider — every `AppSettingPicker kind=\"timezone\"` inherits this restricted list from context. Without it the picker offers the full IANA list (~600 entries)."
|
|
9095
9102
|
],
|
|
9096
9103
|
"useCases": [
|
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.
|
|
57
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v33.6.0/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.
|
|
71
|
+
"version": "33.6.0"
|
|
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: 166 components, 2232 design tokens,
|
|
4
|
-
> 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.
|
|
4
|
+
> 44 cardinal rules. This file is the entry point for AI agents. Catalog version 33.6.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@33.
|
|
7
|
+
(`npx @godxjp/ui-mcp@33.6.0`). 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.
|
|
30
|
+
the tag: `.../godx-jp/godxjp-ui/v33.6.0/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.
|
package/agent/tokens.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
|
-
"description": "Color system (HSL components) — the reference design: warm hue-60 neutral spine, a NEUTRAL INK primary (v32, gh#1220), 和色/wa-iro semantics. The neutral spine still carries SmartHR's values and says so per line. The GoDX
|
|
3
|
+
"description": "Color system (HSL components) — the reference design: warm hue-60 neutral spine, a NEUTRAL INK primary (v32, gh#1220), 和色/wa-iro semantics. The neutral spine still carries SmartHR's values and says so per line. The GoDX identity colour is a preset now, not a default: `@godxjp/ui/themes/godx.css` (emerald-teal #008066 since gh#1345). #fdfdfb warm off-white",
|
|
4
4
|
"name": "--background",
|
|
5
5
|
"tier": "foundation",
|
|
6
6
|
"value": "60 33% 99%"
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"value": "30 7% 53%"
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
|
-
"description": "STATUS FILLS AND THE INK THAT RIDES ON THEM. The FILLS are the palette and they do not move: 若竹, 山吹, 群青, 朱 are named colours, every solid success/attention surface in every consumer is one of them, and a chip that changes hue on upgrade is a different design. What moved is the INK, and only where it failed to be readable (gh#643). Measured from these very tokens (src/tokens/__tests__/status-fill-contrast.test.ts, and confirmed in Chromium by `check:frame-axe` on /isolate/foundation-colors at 320/375/1440): role fill WAS near-white ink dark ink (48 8% 13%) success #68be8d 2.19:1 ✗ 7.08:1 ✓ attention #eb6101 3.32:1 ✗ 4.68:1 ✓ warning #f8b500 1.74:1 ✗ 8.91:1 ✓ (already dark — the precedent) primary #18181b 17.45:1 ✓ (the GoDX preset
|
|
141
|
+
"description": "STATUS FILLS AND THE INK THAT RIDES ON THEM. The FILLS are the palette and they do not move: 若竹, 山吹, 群青, 朱 are named colours, every solid success/attention surface in every consumer is one of them, and a chip that changes hue on upgrade is a different design. What moved is the INK, and only where it failed to be readable (gh#643). Measured from these very tokens (src/tokens/__tests__/status-fill-contrast.test.ts, and confirmed in Chromium by `check:frame-axe` on /isolate/foundation-colors at 320/375/1440): role fill WAS near-white ink dark ink (48 8% 13%) success #68be8d 2.19:1 ✗ 7.08:1 ✓ attention #eb6101 3.32:1 ✗ 4.68:1 ✓ warning #f8b500 1.74:1 ✗ 8.91:1 ✓ (already dark — the precedent) primary #18181b 17.45:1 ✓ (the GoDX preset #008066: 4.86:1) destructive … 6.10:1 ✓ info #4c6cb3 5.00:1 ✓ Two of the eight light-theme fills carried an ink their own lightness cannot support, and the package already knew the answer twice over: --warning-foreground has always been this same near-black on the equally pale 山吹, and the DARK theme flips --success-foreground / --attention-foreground to 48 9% 9% for exactly this reason. The light block was the outlier. REJECTED — darkening 若竹 and 朱 so the near-white ink clears 4.5:1. A fill needs luminance ≤ 0.183 for that; 若竹 sits at 0.422, so \"keep the white text\" means a different green, not a darker one. That is the palette change this deliberately is not. 若竹 #68be8d",
|
|
142
142
|
"name": "--success",
|
|
143
143
|
"tier": "foundation",
|
|
144
144
|
"value": "146 40% 58%"
|
|
@@ -8382,7 +8382,7 @@
|
|
|
8382
8382
|
"value": "initial"
|
|
8383
8383
|
},
|
|
8384
8384
|
{
|
|
8385
|
-
"description": "Identity-fill INK — the ink `mark=\"glyph\"` sets its (caller-supplied) TEXT in when it sits on the --brand identity fill. This is deliberately NOT --brand-foreground. --brand-foreground is the identity artwork's KNOCKOUT colour, not an ink: it tracks --background in both themes (light 60 33% 99% = --background; dark 48 9% 9% = --background) because `<Logo mark=\"godx\">` punches its inner bar as an evenodd HOLE and the email mark has to paint that hole as a solid fill to match. Negative space only has to clear WCAG 2.2 SC 1.4.11 (3:1, non-text) — and at 3.67:1 on the emerald it does. The boxed glyph is a different thing: it renders real TEXT, so SC 1.4.3 applies at 4.5:1 (14px bold is NOT \"large text\" — that needs 18.66px bold / 24px). THIS INK USED TO BE THEME-INVARIANT, AND THE VIOLET IDENTITY ENDED THAT. While --brand was 翠 emerald the fill was light in BOTH themes, so one near-black ink cleared AA on both. Brand identity v2.3 makes the fill #7A00FF in light and #DCBCFF in dark — dark and light respectively — so a single ink cannot serve both: measured, near-black on the light-theme violet is 2.77:1, a real AA failure, while the same ink on the dark-theme violet is 10.72:1. So the ink now FLIPS with the theme, and each side is measured: light ink 60 33% 99% (#fdfdfb) on #
|
|
8385
|
+
"description": "Identity-fill INK — the ink `mark=\"glyph\"` sets its (caller-supplied) TEXT in when it sits on the --brand identity fill. This is deliberately NOT --brand-foreground. --brand-foreground is the identity artwork's KNOCKOUT colour, not an ink: it tracks --background in both themes (light 60 33% 99% = --background; dark 48 9% 9% = --background) because `<Logo mark=\"godx\">` punches its inner bar as an evenodd HOLE and the email mark has to paint that hole as a solid fill to match. Negative space only has to clear WCAG 2.2 SC 1.4.11 (3:1, non-text) — and at 3.67:1 on the emerald it does. The boxed glyph is a different thing: it renders real TEXT, so SC 1.4.3 applies at 4.5:1 (14px bold is NOT \"large text\" — that needs 18.66px bold / 24px). THIS INK USED TO BE THEME-INVARIANT, AND THE VIOLET IDENTITY ENDED THAT. While --brand was 翠 emerald the fill was light in BOTH themes, so one near-black ink cleared AA on both. Brand identity v2.3 makes the fill #7A00FF in light and #DCBCFF in dark — dark and light respectively — so a single ink cannot serve both: measured, near-black on the light-theme violet is 2.77:1, a real AA failure, while the same ink on the dark-theme violet is 10.72:1. The GoDX emerald-teal of gh#1345 keeps the same polarity (#008066 light, #5CD6BE dark). So the ink now FLIPS with the theme, and each side is measured on the GoDX preset: light ink 60 33% 99% (#fdfdfb) on #008066 = 4.86:1 dark ink 48 9% 9% (#191815) on #5CD6BE = 9.99:1 The dark override lives HERE and not in foundation.css on purpose: `:root` and `.dark` have equal specificity, and tokens/base.css imports this file AFTER foundation.css — so a `.dark` rule there would lose to the `:root` rule here. Same file, later block, no ambiguity. A service that re-themes --brand to a fill of the opposite lightness overrides --logo-success-foreground (the public knob) to re-invert the ink. NOT a role-mirror knob: its default is a real value, not a role token, so there is no role to freeze at :root and the `initial` + call-site rule (docs/TOKENS.md) does not apply to it.",
|
|
8386
8386
|
"name": "--logo-identity-foreground",
|
|
8387
8387
|
"tier": "component",
|
|
8388
8388
|
"value": "60 33% 99%"
|
|
@@ -8580,7 +8580,7 @@
|
|
|
8580
8580
|
"value": "initial"
|
|
8581
8581
|
},
|
|
8582
8582
|
{
|
|
8583
|
-
"description": "The other half of the ink flip above — see --logo-identity-foreground. The dark fill is the LIGHT
|
|
8583
|
+
"description": "The other half of the ink flip above — see --logo-identity-foreground. The dark fill is the LIGHT green #5CD6BE in the GoDX preset, so the glyph goes back to the near-black spine (9.99:1).",
|
|
8584
8584
|
"name": "--logo-identity-foreground",
|
|
8585
8585
|
"tier": "component",
|
|
8586
8586
|
"value": "48 9% 9%"
|
|
@@ -4,7 +4,7 @@ import type { AppContextValue, AppProviderProp } from "../props/components/app.p
|
|
|
4
4
|
export type { AppProviderProp, AppContextValue } from "../props/components/app.prop.js";
|
|
5
5
|
/** `AppProvider`'s props (`preset` included since v32, gh#1219 / gh#1220). */
|
|
6
6
|
export type AppProviderProps = AppProviderProp;
|
|
7
|
-
export declare function AppProvider({ children, preset, defaultLocale: defaultLocaleProp, fallbackLocale, defaultTimezone: defaultTimezoneProp, systemTimezone, defaultTimeFormat, defaultDateFormat, timezoneOptions, storageKey, persist, theme: initialTheme, brand: initialBrand, density: initialDensity, fontSize: initialFontSize, scaling: initialScaling, emitFieldNames, onLocaleChange, onTimezoneChange, onTimeFormatChange, onDateFormatChange, onThemeChange, onBrandChange, onDensityChange, onFontSizeChange, onScalingChange, }: AppProviderProps): React.JSX.Element;
|
|
7
|
+
export declare function AppProvider({ children, preset, defaultLocale: defaultLocaleProp, fallbackLocale, defaultTimezone: defaultTimezoneProp, systemTimezone, defaultTimeFormat, defaultDateFormat, timezoneOptions, contentLocales: contentLocalesProp, storageKey, persist, theme: initialTheme, brand: initialBrand, density: initialDensity, fontSize: initialFontSize, scaling: initialScaling, emitFieldNames, onLocaleChange, onTimezoneChange, onTimeFormatChange, onDateFormatChange, onThemeChange, onBrandChange, onDensityChange, onFontSizeChange, onScalingChange, }: AppProviderProps): React.JSX.Element;
|
|
8
8
|
export declare function useAppContext(): AppContextValue;
|
|
9
9
|
/** Returns null outside AppProvider — used by pickers for optional context. */
|
|
10
10
|
export declare function useOptionalAppContext(): AppContextValue | null;
|
package/dist/app/app-provider.js
CHANGED
|
@@ -80,6 +80,7 @@ function AppProvider({
|
|
|
80
80
|
defaultTimeFormat = "locale",
|
|
81
81
|
defaultDateFormat = "locale",
|
|
82
82
|
timezoneOptions,
|
|
83
|
+
contentLocales: contentLocalesProp,
|
|
83
84
|
storageKey = DEFAULT_STORAGE_KEY,
|
|
84
85
|
persist = true,
|
|
85
86
|
theme: initialTheme = "light",
|
|
@@ -133,6 +134,12 @@ function AppProvider({
|
|
|
133
134
|
scaling
|
|
134
135
|
});
|
|
135
136
|
const persistKey = Array.isArray(persist) ? [...persist].sort().join(",") : String(persist);
|
|
137
|
+
const contentLocalesKey = contentLocalesProp?.join(",");
|
|
138
|
+
const contentLocales = React.useMemo(
|
|
139
|
+
() => contentLocalesProp,
|
|
140
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
141
|
+
[contentLocalesKey]
|
|
142
|
+
);
|
|
136
143
|
const persistedAxes = React.useMemo(
|
|
137
144
|
() => resolvePersistedAxes(persist),
|
|
138
145
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -400,6 +407,7 @@ function AppProvider({
|
|
|
400
407
|
dayPickerLocale: getDayPickerLocale(locale),
|
|
401
408
|
requestHeaders,
|
|
402
409
|
timezoneOptions,
|
|
410
|
+
contentLocales,
|
|
403
411
|
theme,
|
|
404
412
|
brand,
|
|
405
413
|
density,
|
|
@@ -425,6 +433,7 @@ function AppProvider({
|
|
|
425
433
|
dateFnsLocale,
|
|
426
434
|
requestHeaders,
|
|
427
435
|
timezoneOptions,
|
|
436
|
+
contentLocales,
|
|
428
437
|
theme,
|
|
429
438
|
brand,
|
|
430
439
|
density,
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
const GODX_ARTWORK_ID_TOKEN = "__GXID__";
|
|
2
2
|
const GODX_LOCKUP_LIGHT = Object.freeze({
|
|
3
3
|
viewBox: "30 30 871.285714 182.000000",
|
|
4
|
-
markup: '<defs>\n <radialGradient id="__GXID__-gx-lockup-l-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#
|
|
4
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-lockup-l-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#008066"/><stop offset="0.46" stop-color="#00513F"/><stop offset="1" stop-color="#03241D"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-lockup-l-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#008066"/><stop offset="1" stop-color="#00A383"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#006E57"/><stop offset="0.40" stop-color="#00A383"/><stop offset="1" stop-color="#5CE6C4"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.28" stop-color="#024034"/><stop offset="0.62" stop-color="#00A383"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.70" stop-color="#023328"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#008066"/><stop offset="0.55" stop-color="#023328"/><stop offset="1" stop-color="#03241D"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#008066"/><stop offset="0.6" stop-color="#2FBF9C"/><stop offset="1" stop-color="#B8EBDD"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#D9F5EE"/><stop offset="0.46" stop-color="#4FD1AE"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-lockup-l-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-lockup-l-godx-logo" transform="translate(5 7)">\n<path id="__GXID__-gx-lockup-l-icon-body" fill="url(#__GXID__-gx-lockup-l-iconBodyGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-lockup-l-icon-arrow" fill="url(#__GXID__-gx-lockup-l-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-lockup-l-arrow-fold" clip-path="url(#__GXID__-gx-lockup-l-arrowClip)" fill="url(#__GXID__-gx-lockup-l-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n<path id="__GXID__-gx-lockup-l-letter-g" fill="#0B0F3B" fill-rule="evenodd" d="M428 76 L399 98 C391 86 378 79 365 79 C342 79 325 98 325 121 C325 144 343 163 365 163 C382 163 395 153 402 137 H362 V107 H442 V121 C442 165 409 198 365 198 C322 198 287 164 287 121 C287 78 322 44 365 44 C390 44 413 57 428 76 Z"/>\n<path id="__GXID__-gx-lockup-l-letter-o" fill="#0B0F3B" fill-rule="evenodd" d="M566 142.5 C566 173.704 539.585 199 507 199 C474.415 199 448 173.704 448 142.5 C448 111.296 474.415 86 507 86 C539.585 86 566 111.296 566 142.5 Z M533.5 142.5 C533.5 156.583 521.636 168 507 168 C492.364 168 480.5 156.583 480.5 142.5 C480.5 128.417 492.364 117 507 117 C521.636 117 533.5 128.417 533.5 142.5 Z"/>\n<path id="__GXID__-gx-lockup-l-letter-d" fill="#0B0F3B" fill-rule="evenodd" d="M574 44 H650 C698 44 732 75 732 121 C732 162 698 198 650 198 H574 Z M616.5 78 H649 C673 78 690 96 690 121 C690 146 673 164 649 164 H616.5 Z"/>\n<path id="__GXID__-gx-lockup-l-x-upper" fill="url(#__GXID__-gx-lockup-l-xUpperGradient)" fill-rule="evenodd" d="M715 44 H762 Q764 44 765 46 L801 86 L774 117 L713 47 Q711 44 715 44 Z"/>\n<path id="__GXID__-gx-lockup-l-x-diagonal" fill="url(#__GXID__-gx-lockup-l-xMainGradient)" fill-rule="evenodd" d="M844 42 H895 Q897 42 895 44 L761 196 Q759 198 757 198 H711 Q708 198 710 196 L841 44 Q843 42 844 42 Z"/>\n<path id="__GXID__-gx-lockup-l-x-lower" fill="url(#__GXID__-gx-lockup-l-xLowerGradient)" fill-rule="evenodd" d="M831 121 L895 196 Q898 199 894 199 H847 Q844 199 842 197 L805 153 Q803 151 805 149 Z"/>\n</g>'
|
|
5
5
|
});
|
|
6
6
|
const GODX_LOCKUP_DARK = Object.freeze({
|
|
7
7
|
viewBox: "30 30 871.285714 182.000000",
|
|
8
|
-
markup: '<defs>\n <radialGradient id="__GXID__-gx-lockup-d-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#
|
|
8
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-lockup-d-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#008066"/><stop offset="0.46" stop-color="#00513F"/><stop offset="1" stop-color="#03241D"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-lockup-d-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#008066"/><stop offset="1" stop-color="#00A383"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#006E57"/><stop offset="0.40" stop-color="#00A383"/><stop offset="1" stop-color="#5CE6C4"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.28" stop-color="#024034"/><stop offset="0.62" stop-color="#00A383"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.70" stop-color="#023328"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#008066"/><stop offset="0.55" stop-color="#023328"/><stop offset="1" stop-color="#03241D"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#008066"/><stop offset="0.6" stop-color="#2FBF9C"/><stop offset="1" stop-color="#B8EBDD"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#D9F5EE"/><stop offset="0.46" stop-color="#4FD1AE"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-lockup-d-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-lockup-d-godx-logo" transform="translate(5 7)">\n<path id="__GXID__-gx-lockup-d-icon-body" fill="url(#__GXID__-gx-lockup-d-reverseIconGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-lockup-d-icon-arrow" fill="url(#__GXID__-gx-lockup-d-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-lockup-d-arrow-fold" clip-path="url(#__GXID__-gx-lockup-d-arrowClip)" fill="url(#__GXID__-gx-lockup-d-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n<path id="__GXID__-gx-lockup-d-letter-g" fill="#FFFFFF" fill-rule="evenodd" d="M428 76 L399 98 C391 86 378 79 365 79 C342 79 325 98 325 121 C325 144 343 163 365 163 C382 163 395 153 402 137 H362 V107 H442 V121 C442 165 409 198 365 198 C322 198 287 164 287 121 C287 78 322 44 365 44 C390 44 413 57 428 76 Z"/>\n<path id="__GXID__-gx-lockup-d-letter-o" fill="#FFFFFF" fill-rule="evenodd" d="M566 142.5 C566 173.704 539.585 199 507 199 C474.415 199 448 173.704 448 142.5 C448 111.296 474.415 86 507 86 C539.585 86 566 111.296 566 142.5 Z M533.5 142.5 C533.5 156.583 521.636 168 507 168 C492.364 168 480.5 156.583 480.5 142.5 C480.5 128.417 492.364 117 507 117 C521.636 117 533.5 128.417 533.5 142.5 Z"/>\n<path id="__GXID__-gx-lockup-d-letter-d" fill="#FFFFFF" fill-rule="evenodd" d="M574 44 H650 C698 44 732 75 732 121 C732 162 698 198 650 198 H574 Z M616.5 78 H649 C673 78 690 96 690 121 C690 146 673 164 649 164 H616.5 Z"/>\n<path id="__GXID__-gx-lockup-d-x-upper" fill="#FFFFFF" fill-rule="evenodd" d="M715 44 H762 Q764 44 765 46 L801 86 L774 117 L713 47 Q711 44 715 44 Z"/>\n<path id="__GXID__-gx-lockup-d-x-diagonal" fill="url(#__GXID__-gx-lockup-d-reverseXMainGradient)" fill-rule="evenodd" d="M844 42 H895 Q897 42 895 44 L761 196 Q759 198 757 198 H711 Q708 198 710 196 L841 44 Q843 42 844 42 Z"/>\n<path id="__GXID__-gx-lockup-d-x-lower" fill="#FFFFFF" fill-rule="evenodd" d="M831 121 L895 196 Q898 199 894 199 H847 Q844 199 842 197 L805 153 Q803 151 805 149 Z"/>\n</g>'
|
|
9
9
|
});
|
|
10
10
|
const GODX_MARK_LIGHT = Object.freeze({
|
|
11
11
|
viewBox: "30 30 241.000000 182.000000",
|
|
12
|
-
markup: '<defs>\n <radialGradient id="__GXID__-gx-mark-l-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#
|
|
12
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-mark-l-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#008066"/><stop offset="0.46" stop-color="#00513F"/><stop offset="1" stop-color="#03241D"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-mark-l-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#008066"/><stop offset="1" stop-color="#00A383"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#006E57"/><stop offset="0.40" stop-color="#00A383"/><stop offset="1" stop-color="#5CE6C4"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.28" stop-color="#024034"/><stop offset="0.62" stop-color="#00A383"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.70" stop-color="#023328"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#008066"/><stop offset="0.55" stop-color="#023328"/><stop offset="1" stop-color="#03241D"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#008066"/><stop offset="0.6" stop-color="#2FBF9C"/><stop offset="1" stop-color="#B8EBDD"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#D9F5EE"/><stop offset="0.46" stop-color="#4FD1AE"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-mark-l-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-mark-l-godx-icon" transform="translate(5 7)">\n<path id="__GXID__-gx-mark-l-icon-body" fill="url(#__GXID__-gx-mark-l-iconBodyGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-mark-l-icon-arrow" fill="url(#__GXID__-gx-mark-l-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-mark-l-arrow-fold" clip-path="url(#__GXID__-gx-mark-l-arrowClip)" fill="url(#__GXID__-gx-mark-l-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n</g>'
|
|
13
13
|
});
|
|
14
14
|
const GODX_MARK_DARK = Object.freeze({
|
|
15
15
|
viewBox: "30 30 241.000000 182.000000",
|
|
16
|
-
markup: '<defs>\n <radialGradient id="__GXID__-gx-mark-d-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#
|
|
16
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-mark-d-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#008066"/><stop offset="0.46" stop-color="#00513F"/><stop offset="1" stop-color="#03241D"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-mark-d-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#008066"/><stop offset="1" stop-color="#00A383"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#006E57"/><stop offset="0.40" stop-color="#00A383"/><stop offset="1" stop-color="#5CE6C4"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.28" stop-color="#024034"/><stop offset="0.62" stop-color="#00A383"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#03241D"/><stop offset="0.70" stop-color="#023328"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#008066"/><stop offset="0.55" stop-color="#023328"/><stop offset="1" stop-color="#03241D"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#008066"/><stop offset="0.6" stop-color="#2FBF9C"/><stop offset="1" stop-color="#B8EBDD"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#D9F5EE"/><stop offset="0.46" stop-color="#4FD1AE"/><stop offset="1" stop-color="#008066"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-mark-d-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-mark-d-godx-icon" transform="translate(5 7)">\n<path id="__GXID__-gx-mark-d-icon-body" fill="url(#__GXID__-gx-mark-d-reverseIconGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-mark-d-icon-arrow" fill="url(#__GXID__-gx-mark-d-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-mark-d-arrow-fold" clip-path="url(#__GXID__-gx-mark-d-arrowClip)" fill="url(#__GXID__-gx-mark-d-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n</g>'
|
|
17
17
|
});
|
|
18
18
|
export {
|
|
19
19
|
GODX_ARTWORK_ID_TOKEN,
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* and its `--check` guard compare against, so the email mark cannot drift from the package's own
|
|
17
17
|
* flat artwork — the drift that was caught once already.
|
|
18
18
|
*
|
|
19
|
-
* MONOCHROME. The kit also ships a gradient cut (#7A00FF → #3700A6 → #0B0F3B
|
|
20
|
-
* not used: this mark is painted by a token (`--logo-godx-color` on the web, a colour argument in
|
|
19
|
+
* MONOCHROME. The kit also ships a gradient cut (#7A00FF → #3700A6 → #0B0F3B; the web master's
|
|
20
|
+
* stops are emerald-teal since gh#1345). It is deliberately not used: this mark is painted by a token (`--logo-godx-color` on the web, a colour argument in
|
|
21
21
|
* email) so it re-tints per theme and knocks out on dark surfaces. A baked gradient can do neither,
|
|
22
22
|
* and email clients are worse at gradients than they are at paths.
|
|
23
23
|
*/
|
|
@@ -3,8 +3,8 @@ import type { TranslatableValue } from "../../props/components/data-entry.prop.j
|
|
|
3
3
|
export type { TranslatableValue, TranslatableInputProp, TranslatableInputProp as TranslatableInputProps, TranslatableTextareaProp, TranslatableTextareaProp as TranslatableTextareaProps, } from "../../props/components/data-entry.prop.js";
|
|
4
4
|
/**
|
|
5
5
|
* TranslatableInput — ONE text field that holds a value per locale (`{ ja, en, vi }`), switched by
|
|
6
|
-
* locale tabs above it (gh#1336). The locale list
|
|
7
|
-
* `
|
|
6
|
+
* locale tabs above it (gh#1336). The locale list and the first tab come from `AppProvider`
|
|
7
|
+
* `contentLocales` (gh#1347), the fallback from its `fallbackLocale`; each is overridable per field; an empty locale shows the fallback locale's text as
|
|
8
8
|
* its placeholder; a locale with an error is marked on its tab. Every other `Input` prop applies to
|
|
9
9
|
* the single control, and `ref` is that control's `<input>`.
|
|
10
10
|
*/
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { CircleAlert } from "lucide-react";
|
|
5
|
+
import { useOptionalAppContext } from "../../app/app-provider.js";
|
|
5
6
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
6
7
|
import { getRegisteredLocales } from "../../i18n/locale-tags.js";
|
|
7
8
|
import { mergeAriaIds, useReportFieldError } from "../../lib/field-a11y.js";
|
|
@@ -35,14 +36,16 @@ function TranslatableField({
|
|
|
35
36
|
...rest
|
|
36
37
|
}) {
|
|
37
38
|
const { t, locale: uiLocale, fallbackLocale: appFallbackLocale } = useTranslation();
|
|
39
|
+
const appContentLocales = useOptionalAppContext()?.contentLocales;
|
|
40
|
+
const contentLocales = appContentLocales?.length ? appContentLocales : void 0;
|
|
38
41
|
const locales = React.useMemo(() => {
|
|
39
|
-
const list = localesProp ?? getRegisteredLocales();
|
|
42
|
+
const list = localesProp ?? contentLocales ?? getRegisteredLocales();
|
|
40
43
|
return list.length > 0 ? list : [uiLocale];
|
|
41
|
-
}, [localesProp, uiLocale]);
|
|
44
|
+
}, [localesProp, contentLocales, uiLocale]);
|
|
42
45
|
const pick = (candidates) => candidates.find((code) => code !== void 0 && locales.includes(code)) ?? locales[0];
|
|
43
46
|
const fallbackLocale = pick([fallbackLocaleProp, appFallbackLocale]);
|
|
44
47
|
const [activeState, setActiveState] = React.useState(
|
|
45
|
-
() => pick([defaultLocale, uiLocale, fallbackLocale])
|
|
48
|
+
() => pick([defaultLocale, contentLocales?.[0], uiLocale, fallbackLocale])
|
|
46
49
|
);
|
|
47
50
|
const active = locales.includes(activeState) ? activeState : pick([defaultLocale, fallbackLocale]);
|
|
48
51
|
const [innerValue, setInnerValue] = React.useState(defaultValue ?? NO_VALUE);
|
|
@@ -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.
|
|
3
|
+
"version": "33.6.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,
|
|
@@ -155,7 +155,7 @@ export declare const EMAIL_COLOR_SOURCE_GODX: {
|
|
|
155
155
|
};
|
|
156
156
|
readonly primary: {
|
|
157
157
|
readonly cssVar: "--primary";
|
|
158
|
-
readonly hsl: "
|
|
158
|
+
readonly hsl: "168 100% 25%";
|
|
159
159
|
};
|
|
160
160
|
readonly primaryForeground: {
|
|
161
161
|
readonly cssVar: "--primary-foreground";
|
|
@@ -163,11 +163,11 @@ export declare const EMAIL_COLOR_SOURCE_GODX: {
|
|
|
163
163
|
};
|
|
164
164
|
readonly focus: {
|
|
165
165
|
readonly cssVar: "--primary";
|
|
166
|
-
readonly hsl: "
|
|
166
|
+
readonly hsl: "168 100% 25%";
|
|
167
167
|
};
|
|
168
168
|
readonly brand: {
|
|
169
169
|
readonly cssVar: "--brand";
|
|
170
|
-
readonly hsl: "
|
|
170
|
+
readonly hsl: "168 100% 25%";
|
|
171
171
|
};
|
|
172
172
|
readonly brandForeground: {
|
|
173
173
|
readonly cssVar: "--brand-foreground";
|
|
@@ -214,7 +214,7 @@ export declare const EMAIL_COLOR_SOURCE_GODX_DARK: {
|
|
|
214
214
|
};
|
|
215
215
|
readonly primary: {
|
|
216
216
|
readonly cssVar: "--primary";
|
|
217
|
-
readonly hsl: "
|
|
217
|
+
readonly hsl: "168 60% 60%";
|
|
218
218
|
};
|
|
219
219
|
readonly primaryForeground: {
|
|
220
220
|
readonly cssVar: "--primary-foreground";
|
|
@@ -222,11 +222,11 @@ export declare const EMAIL_COLOR_SOURCE_GODX_DARK: {
|
|
|
222
222
|
};
|
|
223
223
|
readonly focus: {
|
|
224
224
|
readonly cssVar: "--primary";
|
|
225
|
-
readonly hsl: "
|
|
225
|
+
readonly hsl: "168 60% 60%";
|
|
226
226
|
};
|
|
227
227
|
readonly brand: {
|
|
228
228
|
readonly cssVar: "--brand";
|
|
229
|
-
readonly hsl: "
|
|
229
|
+
readonly hsl: "168 60% 60%";
|
|
230
230
|
};
|
|
231
231
|
readonly brandForeground: {
|
|
232
232
|
readonly cssVar: "--brand-foreground";
|
|
@@ -145,7 +145,7 @@ const EMAIL_COLOR_SOURCE_GODX = {
|
|
|
145
145
|
},
|
|
146
146
|
"primary": {
|
|
147
147
|
"cssVar": "--primary",
|
|
148
|
-
"hsl": "
|
|
148
|
+
"hsl": "168 100% 25%"
|
|
149
149
|
},
|
|
150
150
|
"primaryForeground": {
|
|
151
151
|
"cssVar": "--primary-foreground",
|
|
@@ -153,11 +153,11 @@ const EMAIL_COLOR_SOURCE_GODX = {
|
|
|
153
153
|
},
|
|
154
154
|
"focus": {
|
|
155
155
|
"cssVar": "--primary",
|
|
156
|
-
"hsl": "
|
|
156
|
+
"hsl": "168 100% 25%"
|
|
157
157
|
},
|
|
158
158
|
"brand": {
|
|
159
159
|
"cssVar": "--brand",
|
|
160
|
-
"hsl": "
|
|
160
|
+
"hsl": "168 100% 25%"
|
|
161
161
|
},
|
|
162
162
|
"brandForeground": {
|
|
163
163
|
"cssVar": "--brand-foreground",
|
|
@@ -203,7 +203,7 @@ const EMAIL_COLOR_SOURCE_GODX_DARK = {
|
|
|
203
203
|
},
|
|
204
204
|
"primary": {
|
|
205
205
|
"cssVar": "--primary",
|
|
206
|
-
"hsl": "
|
|
206
|
+
"hsl": "168 60% 60%"
|
|
207
207
|
},
|
|
208
208
|
"primaryForeground": {
|
|
209
209
|
"cssVar": "--primary-foreground",
|
|
@@ -211,11 +211,11 @@ const EMAIL_COLOR_SOURCE_GODX_DARK = {
|
|
|
211
211
|
},
|
|
212
212
|
"focus": {
|
|
213
213
|
"cssVar": "--primary",
|
|
214
|
-
"hsl": "
|
|
214
|
+
"hsl": "168 60% 60%"
|
|
215
215
|
},
|
|
216
216
|
"brand": {
|
|
217
217
|
"cssVar": "--brand",
|
|
218
|
-
"hsl": "
|
|
218
|
+
"hsl": "168 60% 60%"
|
|
219
219
|
},
|
|
220
220
|
"brandForeground": {
|
|
221
221
|
"cssVar": "--brand-foreground",
|
|
@@ -46,6 +46,15 @@ export type AppProviderProp = {
|
|
|
46
46
|
* the full IANA list; set to restrict (e.g.
|
|
47
47
|
*/
|
|
48
48
|
timezoneOptions?: readonly AppTimezone[];
|
|
49
|
+
/**
|
|
50
|
+
* The languages the app stores USER CONTENT in (a product name in `ja`/`en`/`vi`), in order —
|
|
51
|
+
* source language first. Not the UI locale and not the registered UI catalogs: a Japanese UI
|
|
52
|
+
* can edit content in ja · en · vi, and content may be stored in a language the UI has no
|
|
53
|
+
* catalog for. Every `TranslatableInput` / `TranslatableTextarea` without its own `locales`
|
|
54
|
+
* takes its tabs from here and selects the first one. Omit to keep the per-field default
|
|
55
|
+
* (`getRegisteredLocales()`, first tab = the UI locale). App configuration, never persisted.
|
|
56
|
+
*/
|
|
57
|
+
contentLocales?: readonly string[];
|
|
49
58
|
/** localStorage key. Default: `godxjp.app`. */
|
|
50
59
|
storageKey?: string;
|
|
51
60
|
/**
|
|
@@ -167,6 +176,8 @@ export type AppContextValue = {
|
|
|
167
176
|
requestHeaders: AppRequestHeaders;
|
|
168
177
|
/** Configured timezone list; `undefined` → full IANA in the timezone-picker recipe. */
|
|
169
178
|
timezoneOptions?: readonly AppTimezone[];
|
|
179
|
+
/** The app's content languages, source first; `undefined` when `contentLocales` is not set. */
|
|
180
|
+
contentLocales?: readonly string[];
|
|
170
181
|
/**
|
|
171
182
|
* Current theme axes (mirror `<html data-*>` / inline `--scaling`). `theme` is the user's
|
|
172
183
|
* CHOICE — it can be `"system"`, which `<html data-theme>` never is.
|
|
@@ -244,11 +244,15 @@ type TranslatableFieldProp = {
|
|
|
244
244
|
/** The WHOLE map after an edit — every other locale's text is carried over untouched. */
|
|
245
245
|
onValueChange?: OnValueChangeProp<TranslatableValue>;
|
|
246
246
|
/**
|
|
247
|
-
* The locales the field edits, in tab order. Default:
|
|
248
|
-
* (`getRegisteredLocales()` — the built-in
|
|
247
|
+
* The locales the field edits, in tab order. Default: the AppProvider's `contentLocales` when
|
|
248
|
+
* set, else every locale registered with the app (`getRegisteredLocales()` — the built-in
|
|
249
|
+
* `vi`/`en`/`ja` plus `registerLocale(...)`).
|
|
249
250
|
*/
|
|
250
251
|
locales?: readonly string[];
|
|
251
|
-
/**
|
|
252
|
+
/**
|
|
253
|
+
* The locale tab selected first. Default: the first of the AppProvider's `contentLocales` (the
|
|
254
|
+
* source language) when set and in `locales`, else the AppProvider's active locale when it is.
|
|
255
|
+
*/
|
|
252
256
|
defaultLocale?: string;
|
|
253
257
|
/**
|
|
254
258
|
* The locale whose text shows as the placeholder of an EMPTY locale. Default: the AppProvider's
|
package/dist/styles/layers.json
CHANGED
|
@@ -1,41 +1,45 @@
|
|
|
1
1
|
|
|
2
2
|
:root {
|
|
3
3
|
|
|
4
|
-
--primary:
|
|
4
|
+
--primary: 168 100% 25%;
|
|
5
5
|
--primary-foreground: 60 33% 99%;
|
|
6
6
|
|
|
7
|
-
--brand:
|
|
7
|
+
--brand: 168 100% 25%;
|
|
8
8
|
--brand-foreground: 60 33% 99%;
|
|
9
|
+
|
|
10
|
+
--shadow-color: 18 43 38;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
.dark,
|
|
12
14
|
:root[data-theme="dark"] {
|
|
13
15
|
|
|
14
|
-
--primary:
|
|
16
|
+
--primary: 168 60% 60%;
|
|
15
17
|
--primary-foreground: 48 9% 9%;
|
|
16
|
-
--brand:
|
|
18
|
+
--brand: 168 60% 60%;
|
|
17
19
|
--brand-foreground: 48 9% 9%;
|
|
20
|
+
|
|
21
|
+
--shadow-color: 6 14 13;
|
|
18
22
|
}
|
|
19
23
|
|
|
20
24
|
@supports not (color: hsl(from red h s l)) {
|
|
21
25
|
:root {
|
|
22
|
-
--primary-hover:
|
|
23
|
-
--primary-active:
|
|
24
|
-
--primary-border:
|
|
25
|
-
--control-outline:
|
|
26
|
-
--text-link:
|
|
27
|
-
--text-brand:
|
|
28
|
-
--text-primary:
|
|
26
|
+
--primary-hover: 168 100% 16.6%;
|
|
27
|
+
--primary-active: 168 100% 9.5%;
|
|
28
|
+
--primary-border: 168 68% 41%;
|
|
29
|
+
--control-outline: 168 100% 19.7%;
|
|
30
|
+
--text-link: 168 100% 16.6%;
|
|
31
|
+
--text-brand: 168 100% 16.6%;
|
|
32
|
+
--text-primary: 168 100% 9.5%;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
.dark,
|
|
32
36
|
:root[data-theme="dark"] {
|
|
33
|
-
--primary-hover:
|
|
34
|
-
--primary-active:
|
|
35
|
-
--primary-border:
|
|
36
|
-
--control-outline:
|
|
37
|
-
--text-link:
|
|
38
|
-
--text-brand:
|
|
39
|
-
--text-primary:
|
|
37
|
+
--primary-hover: 168 60% 65.8%;
|
|
38
|
+
--primary-active: 168 60% 71.6%;
|
|
39
|
+
--primary-border: 168 28% 16.2%;
|
|
40
|
+
--control-outline: 168 59.4% 34.9%;
|
|
41
|
+
--text-link: 168 60% 60%;
|
|
42
|
+
--text-brand: 168 60% 60%;
|
|
43
|
+
--text-primary: 168 60% 65.8%;
|
|
40
44
|
}
|
|
41
45
|
}
|
package/dist/themes/godx.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AppPreset } from "../app/preset.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* The GoDX PRESET (v32, gh#1220): the product defaults GoDX surfaces shipped with in 31.x, now
|
|
4
4
|
* opt-in so the package's own defaults stay neutral. Pair it with the stylesheet that restores the
|
|
5
|
-
*
|
|
5
|
+
* GoDX identity colour (emerald-teal #008066 since 33.6.0, gh#1345):
|
|
6
6
|
*
|
|
7
7
|
* import "@godxjp/ui/themes/godx.css";
|
|
8
8
|
* import { godxPreset } from "@godxjp/ui/themes/godx";
|
package/dist/themes/godx.js
CHANGED
|
@@ -3,7 +3,10 @@ import { Logo } from "../components/general/logo.js";
|
|
|
3
3
|
const godxPreset = Object.freeze({
|
|
4
4
|
name: "godx",
|
|
5
5
|
defaultLocale: "vi",
|
|
6
|
-
|
|
6
|
+
// `tone: "primary"` (gh#1345): the mark, its wordmark and the primary button are ONE colour —
|
|
7
|
+
// the brand green the stylesheet sets on `--primary` and `--brand` alike. "success" would name
|
|
8
|
+
// the 若竹 status role, which this mark is not.
|
|
9
|
+
brandMark: createElement(Logo, { mark: "godx", tone: "primary" }),
|
|
7
10
|
emailBrandLabel: "GoDX"
|
|
8
11
|
});
|
|
9
12
|
export {
|
package/docs/CUSTOMER-THEMING.md
CHANGED
|
@@ -75,12 +75,13 @@ choose the colour rather than at the point a user cannot read a link.
|
|
|
75
75
|
**The two things it does that hand-authoring keeps getting wrong:**
|
|
76
76
|
|
|
77
77
|
- **A dark seed.** Nothing in CSS lifts a light seed onto the dark spine, so a brand file that sets
|
|
78
|
-
`--primary` only in `:root` keeps the GoDX
|
|
78
|
+
`--primary` only in `:root` keeps the package's (or the GoDX preset's) dark seed in dark mode and
|
|
79
|
+
nothing says so. The generator
|
|
79
80
|
holds your hue and saturation and moves lightness until the dark seed reads against the dark
|
|
80
81
|
canvas the way the light seed reads against the light one.
|
|
81
82
|
- **Email.** `src/email/tokens.generated.ts` bakes literal hex at build time, because Gmail strips
|
|
82
83
|
`<style>` and Outlook ignores custom properties. Those literals are _this package's_ seed, so a
|
|
83
|
-
re-themed product still sends
|
|
84
|
+
re-themed product still sends mail in the package's colours — the one surface no amount of CSS reaches. The
|
|
84
85
|
emitted `acme.email.ts` is the override that corrects it.
|
|
85
86
|
|
|
86
87
|
**What it deliberately leaves out**, because writing them would be a regression:
|
|
@@ -415,7 +416,7 @@ Measured, for the two shapes where a naive rule fails:
|
|
|
415
416
|
| customer hex | label chosen | ratio | what "always white" would have given |
|
|
416
417
|
| ------------ | ------------ | ------- | ------------------------------------ |
|
|
417
418
|
| `#0071bd` | `#ffffff` | 5.13:1 | 5.13:1 |
|
|
418
|
-
| `#
|
|
419
|
+
| `#008066` | `#ffffff` | 4.91:1 | 4.91:1 |
|
|
419
420
|
| `#FFD400` | `#000000` | 14.67:1 | **1.29:1** |
|
|
420
421
|
| `#0A1F44` | `#ffffff` | 16.25:1 | 16.25:1 |
|
|
421
422
|
| `#E30613` | `#ffffff` | 4.88:1 | 4.88:1 |
|
|
@@ -475,8 +476,8 @@ tenantTheme("#FFD400").vars["--text-brand"]; // "49.88 100% 24.4%" — 4.56:1, n
|
|
|
475
476
|
tenantTheme("#7C3AED").vars["--text-brand"]; // "262.12 83.26% 49.44%" — the ramp step, untouched
|
|
476
477
|
```
|
|
477
478
|
|
|
478
|
-
**A seed whose ramp step already clears is emitted unchanged**, so the
|
|
479
|
-
|
|
479
|
+
**A seed whose ramp step already clears is emitted unchanged**, so the GoDX preset's emerald-teal
|
|
480
|
+
`#008066` gets exactly the derived.css ramp step, and so do the middle seeds. `tenant-theme.test.ts` sweeps
|
|
480
481
|
the whole sRGB cube: the worst case is 4.5:1 on either surface, for all three roles.
|
|
481
482
|
|
|
482
483
|
**`surface` is the darkest surface the ink lands on, not the page canvas.** It defaults to the
|
package/docs/DESIGN-AUTHORITY.md
CHANGED
|
@@ -18,7 +18,7 @@ It changes no code by itself. It is the tie-breaker a reviewer points at.
|
|
|
18
18
|
| Behaviour primitives | **Radix** | already the implementation — 193 references |
|
|
19
19
|
| Component composition shape | **shadcn** | already the structural convention — 23 references |
|
|
20
20
|
| Component taxonomy / grouping | **Ant Design** groups | already the catalog shape: `data-entry`, `data-display`, `layout`, `feedback`, `navigation`, `general` — a naming precedent, nothing is installed |
|
|
21
|
-
| Colour foundation | **SmartHR**, brand roles aside | the NEUTRAL spine is SmartHR's — `--foreground` = TEXT_BLACK, `--border` = BORDER. `--primary` was SmartHR MAIN `#0071bd` until identity v2.3 took the brand roles back:
|
|
21
|
+
| Colour foundation | **SmartHR**, brand roles aside | the NEUTRAL spine is SmartHR's — `--foreground` = TEXT_BLACK, `--border` = BORDER. `--primary` was SmartHR MAIN `#0071bd` until identity v2.3 took the brand roles back: GoDX preset — `#008066` (gh#1345) |
|
|
22
22
|
| **Derived colour — the interaction states hanging off each seed** | **Measured contrast (WCAG 2.2 / JIS X 8341-3)** | Authored in `src/tokens/derived.css`; no algorithm derives them. Four contrast suites read that file and hold every value to a threshold, and a fifth holds it to the seed's HUE (gh#648) — see below |
|
|
23
23
|
| **Japanese UI convention — density, JP typography, form patterns** | **SmartHR** | **NEW — this decision.** Extends SmartHR from "where the colours came from" to the authority for how a JP business screen behaves |
|
|
24
24
|
| **Japanese accessibility / public-sector convention** | **デジタル庁 Design System** (Digital Agency) | **NEW — this decision.** The reference when a JP customer asks which standard a screen meets (JIS X 8341-3) |
|
|
@@ -666,6 +666,11 @@ the kit's `action.primary.hover` and then reflects the pressed step, because the
|
|
|
666
666
|
| dark `--primary-hover` | kit #E8DAFF | #ecdaff · 13.51:1 |
|
|
667
667
|
| dark `--primary-active` | #fbf7ff · 1.056:1 from white | #cd9fff · 8.41:1 (sign flipped) |
|
|
668
668
|
|
|
669
|
+
The formula was fitted on that violet and still reproduces it (`derived-seed-sweep.test.ts`). Since
|
|
670
|
+
gh#1345 the GoDX preset's seed is emerald-teal `168 100% 25%` / `168 60% 60%`, and the same formula
|
|
671
|
+
gives light hover #005544 · 8.72:1 and pressed #003027 · 14.17:1, dark hover #73dcc7 · 10.82:1 and
|
|
672
|
+
pressed #8be2d1 · 11.74:1 — no reflection, because the dark seed sits at 60% L.
|
|
673
|
+
|
|
669
674
|
**The ratio is blind to hue, and that cost a release (gh#648).** Identity v2.3 moved the seed 63
|
|
670
675
|
degrees and this tier stayed on the blue it was derived from: 24.0.0 and 24.1.0 shipped a primary
|
|
671
676
|
button that was violet at rest and navy on hover, with all four contrast suites green throughout,
|
package/package.json
CHANGED
|
@@ -7,34 +7,9 @@
|
|
|
7
7
|
* that the consumer did not choose and cannot change without abandoning the GoDX brand (gh#823).
|
|
8
8
|
* `scripts/visual-audit-rules.mjs` exempts exactly these from the 渋み chroma bound.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* ONLY ACCENTS OVER THE BOUND (OKLCH chroma > 0.18), and LIGHT SCHEME ONLY: an accent
|
|
11
|
+
* inside the bound never reaches an exemption, so listing it would widen the carve-out for nothing.
|
|
12
|
+
* Empty since gh#1345 — the GoDX emerald-teal #008066 measures chroma 0.103 (the violet it replaced,
|
|
13
|
+
* #7A00FF, measured 0.293), and the neutral ink is grey.
|
|
13
14
|
*/
|
|
14
|
-
export const SHIPPED_BRAND_ACCENTS = [
|
|
15
|
-
{
|
|
16
|
-
"cssVars": [
|
|
17
|
-
"--primary",
|
|
18
|
-
"--brand"
|
|
19
|
-
],
|
|
20
|
-
"hsl": "240 6% 10%",
|
|
21
|
-
"rgb": {
|
|
22
|
-
"r": 24,
|
|
23
|
-
"g": 24,
|
|
24
|
-
"b": 27
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"cssVars": [
|
|
29
|
-
"--primary",
|
|
30
|
-
"--brand"
|
|
31
|
-
],
|
|
32
|
-
"hsl": "268.7 100% 50%",
|
|
33
|
-
"rgb": {
|
|
34
|
-
"r": 122,
|
|
35
|
-
"g": 0,
|
|
36
|
-
"b": 255
|
|
37
|
-
},
|
|
38
|
-
"source": "src/themes/godx-tokens.css"
|
|
39
|
-
}
|
|
40
|
-
];
|
|
15
|
+
export const SHIPPED_BRAND_ACCENTS = [];
|
|
@@ -106,6 +106,10 @@ export const CHROMA_LIMIT = 0.18;
|
|
|
106
106
|
/**
|
|
107
107
|
* Per-channel sRGB tolerance for "this IS the accent we ship" (gh#823).
|
|
108
108
|
*
|
|
109
|
+
* The measurements below were taken on the violet #7A00FF the GoDX preset shipped until gh#1345.
|
|
110
|
+
* Its emerald-teal successor sits inside the bound, so the exemption list is empty today; the
|
|
111
|
+
* tolerance is kept for the next accent that would need it.
|
|
112
|
+
*
|
|
109
113
|
* The audit reads a computed `rgb()` off a live page, so the match has to survive whatever rounding
|
|
110
114
|
* the engine applied on the way there. Measured in Chromium (playwright 1.61), all four routes to
|
|
111
115
|
* the token — `#7A00FF`, `hsl(268.7 100% 50%)`, the legacy comma form, and `hsl(var(--primary))` —
|
|
@@ -142,8 +146,8 @@ export function isShippedBrandAccent({ r, g, b }) {
|
|
|
142
146
|
|
|
143
147
|
/**
|
|
144
148
|
* @returns {boolean} true when an accent surface exceeds the 渋み chroma limit.
|
|
145
|
-
*
|
|
146
|
-
* any consumer made, so reporting it warns every page about a colour nobody can act on, and the
|
|
149
|
+
* A shipped brand accent over the bound is exempt (the violet was, chroma 0.293, until gh#1345) —
|
|
150
|
+
* it is not a choice any consumer made, so reporting it warns every page about a colour nobody can act on, and the
|
|
147
151
|
* first reader to hit it silences the rule along with every real finding it would have caught.
|
|
148
152
|
*/
|
|
149
153
|
export function isOversaturated(rgb, limit = CHROMA_LIMIT) {
|