@godxjp/ui 2.2.0 → 5.0.1
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/BRAND.md +39 -29
- package/CHANGELOG.md +566 -10
- package/README.md +143 -168
- package/config/eslint.js +54 -0
- package/config/prettier.cjs +20 -0
- package/config/tsconfig.base.json +22 -0
- package/config/vitest.base.ts +26 -0
- package/dist/MiniMonth-YAmPGEpC.d.ts +143 -0
- package/dist/Table.types-BbsxoIYE.d.ts +352 -0
- package/dist/color-DO0qqUAb.d.ts +38 -0
- package/dist/components/composites.d.ts +963 -0
- package/dist/components/composites.js +7340 -0
- package/dist/components/composites.js.map +1 -0
- package/dist/components/primitives.d.ts +2633 -163
- package/dist/components/primitives.js +7266 -165
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/shell.d.ts +82 -12
- package/dist/components/shell.js +168 -162
- package/dist/components/shell.js.map +1 -1
- package/dist/hooks.d.ts +83 -8
- package/dist/hooks.js +497 -83
- package/dist/hooks.js.map +1 -1
- package/dist/i18n.d.ts +55 -3
- package/dist/i18n.js +456 -5
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +24 -5
- package/dist/index.js +12524 -267
- package/dist/index.js.map +1 -1
- package/dist/padding-DY0JV5Ja.d.ts +16 -0
- package/dist/preferences.d.ts +132 -0
- package/dist/preferences.js +262 -0
- package/dist/preferences.js.map +1 -0
- package/dist/props.d.ts +86 -0
- package/dist/props.js +16 -0
- package/dist/props.js.map +1 -0
- package/dist/size-CQwNvOWd.d.ts +19 -0
- package/dist/{data.d.ts → types-LTj-2bl-.d.ts} +7 -12
- package/dist/useTableViews-D5NIAJ7h.d.ts +154 -0
- package/package.json +92 -35
- package/src/tokens/tailwind.css +158 -0
- package/dist/components/screens.d.ts +0 -51
- package/dist/components/screens.js +0 -806
- package/dist/components/screens.js.map +0 -1
- package/dist/data.js +0 -93
- package/dist/data.js.map +0 -1
- package/src/tokens/tokens-ext.css +0 -401
- package/src/tokens/tokens.css +0 -765
package/README.md
CHANGED
|
@@ -1,206 +1,181 @@
|
|
|
1
|
-
# @godxjp/ui
|
|
1
|
+
# @godxjp/ui
|
|
2
2
|
|
|
3
|
-
**
|
|
4
|
-
ecosystem MUST consume this package.** No service may bring its own
|
|
5
|
-
tokens, theme, color palette, i18n provider, or component primitives.
|
|
6
|
-
This rule is review-blocking (see `MUST RULES` below).
|
|
3
|
+
**Version 3.0.0** — GoDX professional UI framework
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
color, spacing, density, dark mode, language switcher, sidebar shape,
|
|
12
|
-
top-bar shape, buttons, badges, kanban, KPI tiles, modal pattern — comes
|
|
13
|
-
from here.
|
|
5
|
+
[](https://www.npmjs.com/package/@godxjp/ui)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](src/)
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
`@godxjp/ui` is the **single source of visual truth** for the GoDX platform.
|
|
10
|
+
Every service frontend (admin-platform, forge-service, console-service, me-service,
|
|
11
|
+
chat-service, knowledge-service, …) consumes this package. No service reimplements
|
|
12
|
+
a button, dialog, sidebar, or design token.
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
The framework enforces three Japanese-enterprise design principles:
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
1.
|
|
23
|
-
|
|
24
|
-
`app.tsx`). Services do not define their own `--background`,
|
|
25
|
-
`--foreground`, `--primary`, font stack, density variables, or
|
|
26
|
-
shadow scale. Tenant overrides happen via `[data-tenant="<id>"]`
|
|
27
|
-
on `<html>`, never per-service.
|
|
28
|
-
|
|
29
|
-
2. **Stack.** TypeScript + React 19 + Vite + Tailwind v4 + shadcn-style
|
|
30
|
-
primitives (Radix + cva + tailwind-merge). Components from this
|
|
31
|
-
package are the only UI atoms a service uses. No service may ship
|
|
32
|
-
`@mui/material`, `chakra-ui`, `antd`, native `styled-components`,
|
|
33
|
-
raw `<input>` with custom CSS, etc.
|
|
34
|
-
|
|
35
|
-
3. **i18n.** All translation goes through `@godxjp/ui/i18n` — a single
|
|
36
|
-
pre-configured `i18next` instance with auto-detect + JA fallback +
|
|
37
|
-
localStorage persistence. The base dictionary (nav, shell, common,
|
|
38
|
-
tweaks, kpi, pdca, issue) lives in `src/i18n/locales/{ja,en,vi}.ts`
|
|
39
|
-
and is exported as `ForgeTranslations`. Services may register their
|
|
40
|
-
own namespace (e.g. `i18n.addResourceBundle("ja", "sandbox", {…})`)
|
|
41
|
-
but never replace the base.
|
|
42
|
-
|
|
43
|
-
4. **Locale set.** Supported: `ja` (default), `en`, `vi`. Adding a
|
|
44
|
-
locale = PR to this package, never per-service.
|
|
45
|
-
|
|
46
|
-
5. **Theme + density + tenant.** All toggled via the `useTweaks` hook
|
|
47
|
-
from `@godxjp/ui/hooks`. The hook mirrors selections onto `<html>`
|
|
48
|
-
data attributes — services rely on those, they do not maintain
|
|
49
|
-
their own theme state.
|
|
50
|
-
|
|
51
|
-
6. **Fonts.** `M PLUS 2` (loaded by `tokens.css`) is the primary face;
|
|
52
|
-
fallbacks are Hiragino → Yu Gothic → Noto Sans JP → system. No
|
|
53
|
-
service may swap in `Inter`, `Roboto`, `Comic Sans`, etc.
|
|
54
|
-
|
|
55
|
-
7. **Color literals.** No hex / rgb / oklch literals in service code.
|
|
56
|
-
Always reference a CSS variable: `var(--primary)`, `var(--wa-akane)`,
|
|
57
|
-
`text-foreground`, `bg-surface-2`. The 13 `--wa-*` 和色 colors are
|
|
58
|
-
for charts + decoration ONLY; never role-map them.
|
|
59
|
-
|
|
60
|
-
8. **Density.** Three modes only: `compact` (28 px element), `default`
|
|
61
|
-
(32 px), `comfortable` (44 px, WCAG-friendly). No `medium`, no
|
|
62
|
-
intermediate sizes. Components honor `--density-element-*` tokens.
|
|
63
|
-
|
|
64
|
-
9. **Signal palette.** 5 colors with fixed semantics — `--success`
|
|
65
|
-
(若竹 wakatake), `--warning` (山吹 yamabuki), `--info` (群青
|
|
66
|
-
gunjō), `--error/destructive` (茜 akane), `--attention` (朱 shu).
|
|
67
|
-
**Red (`--destructive`) is reserved for destructive actions only.**
|
|
68
|
-
Don't use `--destructive` for "wrong answer" badges, validation
|
|
69
|
-
chrome, or general emphasis.
|
|
70
|
-
|
|
71
|
-
10. **No emojis in product UI.** Iconography uses `lucide-react`.
|
|
72
|
-
Emoji are acceptable in user-generated content (comments, chat,
|
|
73
|
-
notifications) but never in chrome.
|
|
74
|
-
|
|
75
|
-
11. **Shell layout.** When a service needs a sidebar + topbar shell,
|
|
76
|
-
it imports `<AppShell>` from `@godxjp/ui/components/shell` and
|
|
77
|
-
plugs in its own nav config + screen routes. Services do not
|
|
78
|
-
hand-roll a CSS grid for the chrome.
|
|
79
|
-
|
|
80
|
-
12. **Switchers (product/project) are universal.** The Linear-style
|
|
81
|
-
quick switcher is one component, used everywhere — same data
|
|
82
|
-
shape (`ForgeProduct` / `ForgeProject` from `@godxjp/ui/data`).
|
|
83
|
-
A service that doesn't have a project concept passes
|
|
84
|
-
`project={null}`; the chip auto-hides.
|
|
16
|
+
| Principle | Meaning | What it enforces |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| **渋み** (shibumi) | Restrained elegance | OKLCH primary chroma ≤ 0.18. No neon. No gradients on functional UI. |
|
|
19
|
+
| **間** (ma) | Vertical breathing room | Body `line-height: 1.7`. Generous spacing. Density toggle for dense tables. |
|
|
20
|
+
| **簡素** (kanso) | Simplicity | Three font weights: 400 (body), 500 (heading), 700 (emphasis). No 600 in new code. |
|
|
85
21
|
|
|
86
22
|
---
|
|
87
23
|
|
|
88
|
-
##
|
|
24
|
+
## Quick start
|
|
89
25
|
|
|
90
|
-
|
|
91
|
-
|---|---|
|
|
92
|
-
| Route tree (`react-router-dom` config) | Visual atoms: button, badge, card, KPI, kanban col |
|
|
93
|
-
| Page composition (what cards live on this screen) | Shell: sidebar + topbar + tweaks panel |
|
|
94
|
-
| Screen-specific widgets (e.g. a domain-pool map view that no other service has) | Theme tokens, density, dark mode |
|
|
95
|
-
| Domain data shapes (e.g. the sandbox's tmux pane object) | i18n provider, locale list, base dictionary |
|
|
96
|
-
| Per-service API client | Color palette, font stack, spacing scale |
|
|
26
|
+
A new service needs three lines to be fully brand-compliant:
|
|
97
27
|
|
|
98
|
-
|
|
99
|
-
|
|
28
|
+
```tsx
|
|
29
|
+
// services/<slug>-service/frontend/src/main.tsx
|
|
30
|
+
import "@godxjp/ui/tailwind.css" // tokens + Tailwind v4 utilities — ONE import
|
|
31
|
+
import { initI18n } from "@godxjp/ui/i18n"
|
|
32
|
+
import { AppShell, Sidebar, Topbar } from "@godxjp/ui/components/shell"
|
|
100
33
|
|
|
101
|
-
|
|
34
|
+
initI18n()
|
|
102
35
|
|
|
103
|
-
|
|
36
|
+
createRoot(document.getElementById("root")!).render(
|
|
37
|
+
<BrowserRouter>
|
|
38
|
+
<AppShell sidebar={<Sidebar nav={MY_NAV} />} topbar={<Topbar />}>
|
|
39
|
+
<Routes>{/* service-specific routes */}</Routes>
|
|
40
|
+
</AppShell>
|
|
41
|
+
</BrowserRouter>,
|
|
42
|
+
)
|
|
43
|
+
```
|
|
104
44
|
|
|
105
|
-
|
|
106
|
-
to claim "GoDX Forge compliant" in its README:
|
|
45
|
+
That is the entire integration surface. No theming step. No per-service token file.
|
|
107
46
|
|
|
108
|
-
|
|
109
|
-
|---|---|---|---|
|
|
110
|
-
| `forge-service/frontend` | adopting (phase 1) | platform | Reference implementation. |
|
|
111
|
-
| `admin-platform/frontend` | partial (existing Omnify tokens overlap ~90%) | platform | Migrate before Plan #19 cut-over. |
|
|
112
|
-
| `me-service/frontend` | not started | platform | Tracked under Plan #31 R6. |
|
|
113
|
-
| `console-service/frontend` | not started | platform | Tracked under Plan #31 R6. |
|
|
114
|
-
| `agent-service/frontend` | not started | platform | Plan #21 G17 finished embed; visual port pending. |
|
|
115
|
-
| `knowledge-service/frontend` | not started | knowledge | Plan #18 K-phase polish. |
|
|
47
|
+
---
|
|
116
48
|
|
|
117
|
-
|
|
118
|
-
keep their own UI, not in scope.
|
|
49
|
+
## Zero-config toolchain
|
|
119
50
|
|
|
120
|
-
|
|
51
|
+
Per the umbrella's frontend-architecture spec (zero-config principle), services
|
|
52
|
+
inherit the full toolchain from this package:
|
|
121
53
|
|
|
122
|
-
|
|
54
|
+
```js
|
|
55
|
+
// eslint.config.js — one line
|
|
56
|
+
export { default } from "@godxjp/ui/eslint-config"
|
|
57
|
+
```
|
|
123
58
|
|
|
59
|
+
```json
|
|
60
|
+
// package.json
|
|
61
|
+
"prettier": "@godxjp/ui/prettier-config"
|
|
124
62
|
```
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
├── hooks/
|
|
137
|
-
│ └── useTweaks.ts density / theme / tenant / locale /
|
|
138
|
-
│ sidebar-collapsed state w/ persistence.
|
|
139
|
-
│
|
|
140
|
-
├── data/
|
|
141
|
-
│ └── products.ts ForgeProduct / ForgeProject types +
|
|
142
|
-
│ mock fixture (until forge-service
|
|
143
|
-
│ /api/v1/orgs/ wires real data).
|
|
144
|
-
│
|
|
145
|
-
├── primitives/ shadcn-styled atoms (button, badge,
|
|
146
|
-
│ card, kbd, ...). One copy across the
|
|
147
|
-
│ org.
|
|
148
|
-
│
|
|
149
|
-
└── components/shell/ AppShell, Sidebar, Topbar,
|
|
150
|
-
ProductSwitcher, ProjectSwitcher,
|
|
151
|
-
TweaksPanel, CommandPalette.
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
// tsconfig.json
|
|
66
|
+
{ "extends": "@godxjp/ui/tsconfig" }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// vitest.config.ts
|
|
71
|
+
import base from "@godxjp/ui/vitest-config"
|
|
72
|
+
import { mergeConfig } from "vitest/config"
|
|
73
|
+
export default mergeConfig(base, { test: {} })
|
|
152
74
|
```
|
|
153
75
|
|
|
154
76
|
---
|
|
155
77
|
|
|
156
|
-
##
|
|
78
|
+
## Import surface
|
|
157
79
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
80
|
+
| Import | What you get |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `@godxjp/ui` | All primitives + hooks + i18n helpers (barrel) |
|
|
83
|
+
| `@godxjp/ui/tailwind.css` | Tailwind v4 + design tokens + base styles |
|
|
84
|
+
| `@godxjp/ui/tokens.css` | Raw CSS custom properties only (no Tailwind) |
|
|
85
|
+
| `@godxjp/ui/tokens-ext.css` | Extended tokens (dark mode, tenants, sidebar vars) |
|
|
86
|
+
| `@godxjp/ui/sonner.css` | Sonner toast animations (import after tokens) |
|
|
87
|
+
| `@godxjp/ui/components/primitives` | All primitives — see [`src/components/primitives.ts`](src/components/primitives.ts) (single barrel; 73+ surfaces re-exported from six group folders per cardinal rule 27) |
|
|
88
|
+
| `@godxjp/ui/components/shell` | `AppShell`, `Sidebar`, `Topbar`, `TweaksPanel`, `CommandPalette`, `ProductSwitcher`, `ProjectSwitcher`, `PageContent` |
|
|
89
|
+
| `@godxjp/ui/components/composites` | Upload family, `MediaUpload`, `AvatarUploader`, `LocaleInput`, calendar app composite |
|
|
90
|
+
| `@godxjp/ui/i18n` | `initI18n()`, `SUPPORTED_LOCALES`, `GodxLocale` |
|
|
91
|
+
| `@godxjp/ui/hooks` | `useTweaks()`, `Tweaks`, `Density`, `Theme` |
|
|
92
|
+
| `@godxjp/ui/preferences` | `PreferencesProvider` — locale + timezone React context |
|
|
93
|
+
| `@godxjp/ui/eslint-config` | Shared ESLint flat config |
|
|
94
|
+
| `@godxjp/ui/prettier-config` | Shared Prettier config |
|
|
95
|
+
| `@godxjp/ui/tsconfig` | Strict TypeScript base |
|
|
96
|
+
| `@godxjp/ui/vitest-config` | Vitest base with jsdom + coverage thresholds |
|
|
164
97
|
|
|
165
|
-
|
|
98
|
+
---
|
|
166
99
|
|
|
167
|
-
|
|
168
|
-
<BrowserRouter>
|
|
169
|
-
<AppShell sidebar={<Sidebar nav={MY_NAV} />} topbar={<Topbar />}>
|
|
170
|
-
<Routes>{/* service-specific routes */}</Routes>
|
|
171
|
-
</AppShell>
|
|
172
|
-
</BrowserRouter>,
|
|
173
|
-
);
|
|
174
|
-
```
|
|
100
|
+
## Primitives (v3)
|
|
175
101
|
|
|
176
|
-
|
|
102
|
+
| Component | Radix backing | A11y | Status |
|
|
103
|
+
|---|---|---|---|
|
|
104
|
+
| `Badge` | — | WCAG 2.1 AA | production |
|
|
105
|
+
| `Button` | `@radix-ui/react-slot` | focus-visible, keyboard | production |
|
|
106
|
+
| `Card` | — | — | production |
|
|
107
|
+
| `Input`, `Textarea` | — | aria-invalid, label wire | production |
|
|
108
|
+
| `Label` | `@radix-ui/react-label` | for/id | production |
|
|
109
|
+
| `Tabs`, `Tabs`, `Tabs`, `Tabs` | `@radix-ui/react-tabs` | roving tabindex | production |
|
|
110
|
+
| `Avatar` | — | aria-label | production |
|
|
111
|
+
| `Separator` | `@radix-ui/react-separator` | role separator | production |
|
|
112
|
+
| `Popover`, `Popover`, `Popover` | `@radix-ui/react-popover` | focus trap | production |
|
|
113
|
+
| `DropdownMenu` family | `@radix-ui/react-dropdown-menu` | keyboard nav | production |
|
|
114
|
+
| `Calendar` | `react-day-picker` | ARIA grid | production |
|
|
115
|
+
| `TimeInput` | — | aria-invalid | production |
|
|
116
|
+
| `Dialog` family | `@radix-ui/react-dialog` | focus trap, aria-modal | production |
|
|
117
|
+
| `Sheet` family | `@radix-ui/react-dialog` | focus trap, aria-modal | production |
|
|
118
|
+
| `AlertDialog` family | `@radix-ui/react-alert-dialog` | focus trap | production |
|
|
119
|
+
| `Select` family | `@radix-ui/react-select` | keyboard nav | production |
|
|
120
|
+
| `Switch` | `@radix-ui/react-switch` | role switch | production |
|
|
121
|
+
| `Checkbox` | `@radix-ui/react-checkbox` | role checkbox | production |
|
|
122
|
+
| `Table` family | — | role table | production |
|
|
123
|
+
| `Combobox` family | `cmdk` + Popover | keyboard nav | production |
|
|
124
|
+
| `Toaster`, `toast` | `sonner` | aria-live | production |
|
|
125
|
+
| `Skeleton` | — | aria-hidden | production |
|
|
126
|
+
| `Breadcrumb`, `Breadcrumb`, `Breadcrumb` | — | aria-label, aria-current | production |
|
|
177
127
|
|
|
178
128
|
---
|
|
179
129
|
|
|
180
|
-
##
|
|
130
|
+
## i18n
|
|
181
131
|
|
|
182
|
-
|
|
183
|
-
component prop, changed default tenant) require:
|
|
132
|
+
Mandatory locales per the umbrella frontend-architecture spec §6:
|
|
184
133
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
134
|
+
| Locale | Status |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `ja` | production (primary) |
|
|
137
|
+
| `en` | production |
|
|
138
|
+
| `vi` | production |
|
|
139
|
+
| `fil` | production (added v3.0.0) |
|
|
189
140
|
|
|
190
|
-
|
|
191
|
-
new tenant) are minor / patch — no RFC needed.
|
|
141
|
+
Services add extra namespaces via `i18n.addResourceBundle(locale, "my-ns", {…})`.
|
|
192
142
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## MUST RULES (review-blocking)
|
|
146
|
+
|
|
147
|
+
See [`README.md § MUST RULES`](README.md) and [`BRAND.md`](BRAND.md) for the full list.
|
|
148
|
+
The short version:
|
|
149
|
+
|
|
150
|
+
1. Import `@godxjp/ui/tailwind.css` (or `/tokens.css`) once at app entry.
|
|
151
|
+
2. Never redefine `--primary`, `--foreground`, `--background`, or any base token in app code.
|
|
152
|
+
3. Per-deployment brand-color overrides live under `[data-accent="<palette>"]` in a service `theme.css` (per cardinal rule 19 — `[data-tenant]` is removed).
|
|
153
|
+
4. No `@mui/material`, `chakra-ui`, `antd`, or any other component library.
|
|
154
|
+
5. All primitive needs → add to `@godxjp/ui` first, then consume.
|
|
155
|
+
6. Shell (AppShell + Sidebar + Topbar) is one component set — no hand-rolled grids.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Adoption tracker
|
|
160
|
+
|
|
161
|
+
| Service | Status | Notes |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| `calendar-service/frontend` | adopted | Greenfield; compliant from first commit. |
|
|
164
|
+
| `forge-service/frontend` | adopting (phase 1) | Reference implementation for migration pattern. |
|
|
165
|
+
| `admin-platform/frontend` | partial | Omnify tokens overlap ~90%; full migration pending. |
|
|
166
|
+
| `me-service/frontend` | adopting | Plan #31 R6 — active migration. |
|
|
167
|
+
| `console-service/frontend` | adopting | Epic #1412; AppShell + tokens wired. |
|
|
168
|
+
| `agent-service/frontend` | not started | Plan #21 G17. |
|
|
169
|
+
| `knowledge-service/frontend` | not started | Plan #18 K-phase. |
|
|
170
|
+
| `chat-service/frontend` | adopting | Plan #30 completion phase. |
|
|
196
171
|
|
|
197
172
|
---
|
|
198
173
|
|
|
199
|
-
##
|
|
174
|
+
## Versioning
|
|
175
|
+
|
|
176
|
+
`@godxjp/ui` follows [Semantic Versioning](https://semver.org/).
|
|
177
|
+
Breaking changes require a cross-service audit + major bump.
|
|
178
|
+
See [`CHANGELOG.md`](CHANGELOG.md) for the full history.
|
|
200
179
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
- Plan #19 — forge-service extraction.
|
|
204
|
-
- Plan #22 — multi-repo standalone services. `@godxjp/ui` is the
|
|
205
|
-
TypeScript counterpart to `godx-platform-sdk` (Go shared kernel).
|
|
206
|
-
- Plan #31 R6 — per-portal UI alignment.
|
|
180
|
+
Source: `github.com/godx-jp/godxjp-ui` (Apache-2.0).
|
|
181
|
+
The umbrella repo (`godx-jp/godx-admin`) pins this as a git submodule at `libs/ts/godxjp-ui/`.
|
package/config/eslint.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// @godxjp/ui — shared ESLint flat config.
|
|
2
|
+
//
|
|
3
|
+
// Consume in a service frontend with a single line:
|
|
4
|
+
//
|
|
5
|
+
// // eslint.config.js
|
|
6
|
+
// export { default } from "@godxjp/ui/eslint-config"
|
|
7
|
+
//
|
|
8
|
+
// Locked stack (umbrella frontend-architecture spec §9):
|
|
9
|
+
// ESLint 9.x + typescript-eslint 8.x (strict + stylistic)
|
|
10
|
+
// eslint-plugin-react 7.x + eslint-plugin-react-hooks 5.x
|
|
11
|
+
// eslint-plugin-jsx-a11y 6.x (WCAG 2.1 AA in JSX)
|
|
12
|
+
// eslint-config-prettier (turns off formatting conflicts)
|
|
13
|
+
//
|
|
14
|
+
// This file is intentionally kept dependency-free at the @godxjp/ui level
|
|
15
|
+
// so it can be consumed before peerDependencies install. The locked rule
|
|
16
|
+
// sets above are declared as peerDependencies by the consumer's package.json;
|
|
17
|
+
// when a service uses the umbrella workspace those peers resolve automatically.
|
|
18
|
+
|
|
19
|
+
/** @type {import("eslint").Linter.Config[]} */
|
|
20
|
+
const config = [
|
|
21
|
+
{
|
|
22
|
+
// Global ignores — applies before any rules.
|
|
23
|
+
ignores: ["dist/**", "node_modules/**", "*.d.ts"],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
files: ["**/*.{ts,tsx}"],
|
|
27
|
+
languageOptions: {
|
|
28
|
+
parserOptions: {
|
|
29
|
+
ecmaVersion: "latest",
|
|
30
|
+
sourceType: "module",
|
|
31
|
+
ecmaFeatures: { jsx: true },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
rules: {
|
|
35
|
+
// React 19 does not require the React import for JSX.
|
|
36
|
+
"react/react-in-jsx-scope": "off",
|
|
37
|
+
// Always exhaustive deps.
|
|
38
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
39
|
+
// Accessibility baseline.
|
|
40
|
+
"jsx-a11y/alt-text": "error",
|
|
41
|
+
"jsx-a11y/aria-props": "error",
|
|
42
|
+
"jsx-a11y/aria-proptypes": "error",
|
|
43
|
+
"jsx-a11y/aria-unsupported-elements": "error",
|
|
44
|
+
"jsx-a11y/role-has-required-aria-props": "error",
|
|
45
|
+
"jsx-a11y/role-supports-aria-props": "error",
|
|
46
|
+
"jsx-a11y/interactive-supports-focus": "warn",
|
|
47
|
+
"jsx-a11y/click-events-have-key-events": "warn",
|
|
48
|
+
// No console in production code.
|
|
49
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
export default config
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @godxjp/ui — shared Prettier config.
|
|
2
|
+
//
|
|
3
|
+
// Consume in a service frontend:
|
|
4
|
+
// // .prettierrc.json → "prettier": "@godxjp/ui/prettier-config"
|
|
5
|
+
// // or package.json: "prettier": "@godxjp/ui/prettier-config"
|
|
6
|
+
|
|
7
|
+
/** @type {import("prettier").Config} */
|
|
8
|
+
module.exports = {
|
|
9
|
+
semi: false,
|
|
10
|
+
singleQuote: false,
|
|
11
|
+
trailingComma: "all",
|
|
12
|
+
printWidth: 100,
|
|
13
|
+
tabWidth: 2,
|
|
14
|
+
useTabs: false,
|
|
15
|
+
bracketSameLine: false,
|
|
16
|
+
arrowParens: "always",
|
|
17
|
+
endOfLine: "lf",
|
|
18
|
+
// Tailwind class sorting — service must install prettier-plugin-tailwindcss separately.
|
|
19
|
+
plugins: [],
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"moduleResolution": "Bundler",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"noImplicitOverride": true,
|
|
12
|
+
"exactOptionalPropertyTypes": true,
|
|
13
|
+
"noPropertyAccessFromIndexSignature": false,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"esModuleInterop": false,
|
|
17
|
+
"allowSyntheticDefaultImports": true,
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true,
|
|
20
|
+
"verbatimModuleSyntax": true
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @godxjp/ui — shared Vitest config base.
|
|
2
|
+
//
|
|
3
|
+
// Consume in a service frontend:
|
|
4
|
+
//
|
|
5
|
+
// // vitest.config.ts
|
|
6
|
+
// import base from "@godxjp/ui/vitest-config"
|
|
7
|
+
// import { mergeConfig } from "vitest/config"
|
|
8
|
+
// export default mergeConfig(base, { test: { /* service overrides */ } })
|
|
9
|
+
|
|
10
|
+
import { defineConfig } from "vitest/config"
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
test: {
|
|
14
|
+
environment: "jsdom",
|
|
15
|
+
globals: false,
|
|
16
|
+
include: ["src/**/*.test.{ts,tsx}"],
|
|
17
|
+
exclude: ["e2e/**", "dist/**", "node_modules/**"],
|
|
18
|
+
coverage: {
|
|
19
|
+
provider: "v8",
|
|
20
|
+
thresholds: {
|
|
21
|
+
statements: 75,
|
|
22
|
+
branches: 70,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
})
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode, HTMLAttributes, ComponentProps } from 'react';
|
|
3
|
+
import { S as SizeProp } from './size-CQwNvOWd.js';
|
|
4
|
+
|
|
5
|
+
type SegmentedControlVariant = "bar" | "pill";
|
|
6
|
+
/** Subset of the shared `SizeProp` — SegmentedControl only ships the
|
|
7
|
+
* two compact-side rungs in practice (no `"large"` design canon yet). */
|
|
8
|
+
type SegmentedControlSize = Exclude<SizeProp, "large">;
|
|
9
|
+
type SegmentedControlOrientation = "horizontal" | "vertical";
|
|
10
|
+
interface SegmentedControlItem<V extends string = string> {
|
|
11
|
+
value: V;
|
|
12
|
+
label: ReactNode;
|
|
13
|
+
icon?: ReactNode;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface SegmentedControlProps<V extends string = string> extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "defaultValue"> {
|
|
17
|
+
items: SegmentedControlItem<V>[];
|
|
18
|
+
value?: V;
|
|
19
|
+
defaultValue?: V;
|
|
20
|
+
onChange?: (next: V) => void;
|
|
21
|
+
variant?: SegmentedControlVariant;
|
|
22
|
+
size?: SegmentedControlSize;
|
|
23
|
+
/** Axis of the radiogroup — controls Arrow-key direction for the
|
|
24
|
+
* roving-tabindex pattern (per WAI-ARIA APG radiogroup). */
|
|
25
|
+
orientation?: SegmentedControlOrientation;
|
|
26
|
+
/** Accessible name for the group — falls back to a generic role label. */
|
|
27
|
+
"aria-label"?: string;
|
|
28
|
+
}
|
|
29
|
+
declare function SegmentedControl<V extends string = string>({ items, value: controlled, defaultValue, onChange, variant, size, orientation, className, ...rest }: SegmentedControlProps<V>): react_jsx_runtime.JSX.Element;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Locale used by `fmtHour`. Adds the JA suffix style (`9時`) for `ja`
|
|
33
|
+
* and keeps `HH:00` for everything else.
|
|
34
|
+
*/
|
|
35
|
+
type TimeLocale = "vi" | "ja" | "en";
|
|
36
|
+
/** Parse "HH:MM" into { h, m }. Tolerates missing minutes. */
|
|
37
|
+
declare function parseHM(value: string): {
|
|
38
|
+
h: number;
|
|
39
|
+
m: number;
|
|
40
|
+
};
|
|
41
|
+
/** Pixel offset for a given clock time within a day-grid column. */
|
|
42
|
+
declare function minToY(h: number, m: number, options: {
|
|
43
|
+
dayStartH: number;
|
|
44
|
+
pxPerMin: number;
|
|
45
|
+
}): number;
|
|
46
|
+
/** Format an hour cell label per locale. */
|
|
47
|
+
declare function fmtHour(h: number, locale: TimeLocale): string;
|
|
48
|
+
/** Default day-grid sizing the WeekView / DayView screens use. */
|
|
49
|
+
declare const DEFAULT_GRID: {
|
|
50
|
+
readonly dayStartH: 6;
|
|
51
|
+
readonly dayEndH: 22;
|
|
52
|
+
readonly pxPerMin: 0.9;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Build a 6×7 Mon-first month grid for (year, monthIdx1to12). Lead-in
|
|
56
|
+
* cells from the previous month and tail cells from the next month are
|
|
57
|
+
* flagged `dim: true`. Shared by MiniMonth + MonthView.
|
|
58
|
+
*/
|
|
59
|
+
interface MonthCellRef {
|
|
60
|
+
y: number;
|
|
61
|
+
m: number;
|
|
62
|
+
d: number;
|
|
63
|
+
dim: boolean;
|
|
64
|
+
}
|
|
65
|
+
declare function buildMonthGrid(year: number, month: number): MonthCellRef[];
|
|
66
|
+
/** YYYY-MM-DD key for a {y,m,d} triple. */
|
|
67
|
+
declare function ymd(y: number, m: number, d: number): string;
|
|
68
|
+
|
|
69
|
+
interface CalendarEvent {
|
|
70
|
+
id: string;
|
|
71
|
+
/** Color reference — `CalendarRef.id` whose `color` paints the event. */
|
|
72
|
+
calId: string;
|
|
73
|
+
title: string;
|
|
74
|
+
/** YYYY-MM-DD. */
|
|
75
|
+
date: string;
|
|
76
|
+
allDay?: boolean;
|
|
77
|
+
/** HH:MM (24h). Required when `allDay` is false. */
|
|
78
|
+
start?: string;
|
|
79
|
+
/** HH:MM (24h). Required when `allDay` is false. */
|
|
80
|
+
end?: string;
|
|
81
|
+
attendees: string[];
|
|
82
|
+
/** Free-form status — caller decides which strings are meaningful. */
|
|
83
|
+
status?: string;
|
|
84
|
+
/** Free-form event kind — caller decides. */
|
|
85
|
+
type?: string;
|
|
86
|
+
location?: string;
|
|
87
|
+
note?: string;
|
|
88
|
+
}
|
|
89
|
+
interface CalendarRef {
|
|
90
|
+
id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
color: string;
|
|
93
|
+
shown?: boolean;
|
|
94
|
+
/** Optional grouping bucket used by sidebar lists. */
|
|
95
|
+
group?: string;
|
|
96
|
+
/** True for read-only feeds (e.g. national holidays). */
|
|
97
|
+
readonly?: boolean;
|
|
98
|
+
}
|
|
99
|
+
interface PersonRef {
|
|
100
|
+
id: string;
|
|
101
|
+
name: string;
|
|
102
|
+
/** Short label (2–3 chars) for avatar text. */
|
|
103
|
+
short: string;
|
|
104
|
+
color: string;
|
|
105
|
+
email?: string;
|
|
106
|
+
org?: string;
|
|
107
|
+
role?: string;
|
|
108
|
+
/** Marks the viewer themselves. */
|
|
109
|
+
self?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Visual treatment hint for an EventBlock — separated from
|
|
113
|
+
* `CalendarEvent.status` so the primitive stays generic. Consumers map
|
|
114
|
+
* their `type` + `status` into one of these.
|
|
115
|
+
*/
|
|
116
|
+
type EventBlockVariant = "solid" | "tint" | "tentative" | "focus";
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* MiniMonth — compact 6×7 month grid for sidebars and date pickers.
|
|
120
|
+
* Mon-first, 22px-cell. Renders an event dot when `eventDots[ymd]` is
|
|
121
|
+
* truthy and `--accent-color` for today/selected states.
|
|
122
|
+
*/
|
|
123
|
+
interface MiniMonthYMD {
|
|
124
|
+
y: number;
|
|
125
|
+
m: number;
|
|
126
|
+
d: number;
|
|
127
|
+
}
|
|
128
|
+
interface MiniMonthProps extends Omit<ComponentProps<"div">, "onSelect"> {
|
|
129
|
+
/** Year of the grid. */
|
|
130
|
+
year: number;
|
|
131
|
+
/** Month (1–12) of the grid. */
|
|
132
|
+
month: number;
|
|
133
|
+
today: MiniMonthYMD;
|
|
134
|
+
selected?: MiniMonthYMD;
|
|
135
|
+
/** Map of YYYY-MM-DD → has-event boolean. */
|
|
136
|
+
eventDots?: Record<string, boolean>;
|
|
137
|
+
onSelect?: (ymd: MiniMonthYMD) => void;
|
|
138
|
+
/** Day-of-week labels — Mon-first. Default JA single chars. */
|
|
139
|
+
dowLabels?: readonly [string, string, string, string, string, string, string];
|
|
140
|
+
}
|
|
141
|
+
declare function MiniMonth({ year, month, today, selected, eventDots, onSelect, dowLabels, className, ...rest }: MiniMonthProps): react_jsx_runtime.JSX.Element;
|
|
142
|
+
|
|
143
|
+
export { type CalendarEvent as C, DEFAULT_GRID as D, type EventBlockVariant as E, MiniMonth as M, type PersonRef as P, SegmentedControl as S, type TimeLocale as T, type CalendarRef as a, type MiniMonthProps as b, type MiniMonthYMD as c, type MonthCellRef as d, type SegmentedControlItem as e, type SegmentedControlOrientation as f, type SegmentedControlProps as g, type SegmentedControlSize as h, type SegmentedControlVariant as i, buildMonthGrid as j, fmtHour as k, minToY as m, parseHM as p, ymd as y };
|