@serendie/ui 2.2.8 → 2.3.0-dev.202512051042

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/README.md CHANGED
@@ -105,11 +105,48 @@ export default defineConfig({
105
105
 
106
106
  より実践的な例は、こちらの[サンプルプロジェクト](https://github.com/serendie/bootcamp?tab=readme-ov-file#%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%A8%E4%BD%B5%E7%94%A8%E3%81%99%E3%82%8B)を参考にしてください。
107
107
 
108
+ ## 多言語対応
109
+
110
+ Serendie UIは日本語・英語の多言語対応をサポートしています。`SerendieProvider`を使用して、アプリケーション全体の言語を設定できます。なお、 SerendieProvider の利用は必須ではありません。利用しない場合は、デフォルトで日本語が適用されます。
111
+
112
+ ```tsx
113
+ import { SerendieProvider } from "@serendie/ui";
114
+
115
+ function App() {
116
+ return (
117
+ <SerendieProvider lang="ja">{/* アプリケーション全体 */}</SerendieProvider>
118
+ );
119
+ }
120
+ ```
121
+
122
+ #### Next.js App Routerでの多言語対応
123
+
124
+ ```tsx
125
+ // app/layout.tsx
126
+ import { SerendieProvider } from "@serendie/ui";
127
+
128
+ export default function RootLayout({
129
+ children,
130
+ params,
131
+ }: {
132
+ children: React.ReactNode;
133
+ params: { lang: "ja" | "en" };
134
+ }) {
135
+ return (
136
+ <html lang={params.lang}>
137
+ <body>
138
+ <SerendieProvider lang={params.lang}>{children}</SerendieProvider>
139
+ </body>
140
+ </html>
141
+ );
142
+ }
143
+ ```
144
+
108
145
  ## APIを詳しく知る
109
146
 
110
147
  Serendie UIはヘッドレスUIとして、[Ark UI](https://ark-ui.com/)を内部的に利用しており、各コンポーネントのAPIはArk UIを継承します。Selectコンポーネントなどインタラクションが複雑なコンポーネントは、Ark UIの[APIリファレンス](https://ark-ui.com/react/docs/components/select#api-reference)を合わせて参照してください。
111
148
 
112
- ## Serendie UIの開発
149
+ ## Serendie UI開発者向け
113
150
 
114
151
  Serendie UIに新しくコンポーネントを追加する場合は、Ark UIをベースにしてください。
115
152
 
@@ -128,6 +165,73 @@ npm run connect:publish
128
165
 
129
166
  storiesファイルに変更が入ると上記が[GitHub Actions](https://github.com/serendie/serendie/blob/main/.github/workflows/publish-code-connect.yml)によって実行されます。
130
167
 
168
+ ### 翻訳データの管理
169
+
170
+ Serendie UIの翻訳データは`src/i18n/dictionary.ts`で管理されており、Figma Variablesと同期できます。
171
+
172
+ #### コンポーネント内での翻訳の使用
173
+
174
+ `useTranslations`フックを使用して、コンポーネント内で翻訳テキストを取得できます:
175
+
176
+ ```tsx
177
+ import { useTranslations } from "@serendie/ui";
178
+
179
+ function MyComponent() {
180
+ const t = useTranslations();
181
+
182
+ return (
183
+ <div>
184
+ {/* 変数なし */}
185
+ <label>{t("common.required")}</label>
186
+
187
+ {/* 変数あり - {{key}} プレースホルダーを使用 */}
188
+ <span>{t("pagination.page", { page: 5 })}</span>
189
+ </div>
190
+ );
191
+ }
192
+ ```
193
+
194
+ 翻訳辞書では`{{key}}`形式のプレースホルダーを使用します:
195
+
196
+ ```typescript
197
+ // src/i18n/dictionary.ts
198
+ export const dictionary = {
199
+ ja: {
200
+ "common.required": "必須",
201
+ "pagination.page": "{{page}}ページ目",
202
+ },
203
+ en: {
204
+ "common.required": "Required",
205
+ "pagination.page": "Page {{page}}",
206
+ },
207
+ } as const;
208
+ ```
209
+
210
+ #### 環境設定
211
+
212
+ `.env`ファイルに以下を設定してください:
213
+
214
+ ```env
215
+ FIGMA_ACCESS_TOKEN="YOUR_TOKEN"
216
+ FIGMA_FILE_KEY="YOUR_FILE_KEY"
217
+ # FIGMA_TRANSLATION_COLLECTION="locales" # オプション(デフォルト: locales)
218
+ ```
219
+
220
+ #### 翻訳管理コマンド
221
+
222
+ ```bash
223
+ # Figmaから翻訳データを取得して src/i18n/dictionary.ts を更新
224
+ npm run locales:pull
225
+
226
+ # ローカルの翻訳データをFigma Variablesに反映
227
+ npm run locales:push
228
+
229
+ # 翻訳データの整合性チェック(キーの不足や空文字のチェック)
230
+ npm run locales:lint
231
+ ```
232
+
233
+ 翻訳データの詳細については[scripts/locales/README.md](scripts/locales/README.md)を参照してください。
234
+
131
235
  ## Resources
132
236
 
133
237
  Serendie Design Systemは、Serendie UI (本リポジトリ) のほか以下の関連リポジトリから構成されています。
package/dist/client.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { SerendiePreset as e } from "./preset.js";
3
3
  import { Accordion as a } from "./components/Accordion/Accordion.js";
4
4
  import { AccordionGroup as m } from "./components/Accordion/AccordionGroup.js";
5
- import { Avatar as x, AvatarStyle as n } from "./components/Avatar/Avatar.js";
5
+ import { Avatar as i, AvatarStyle as n } from "./components/Avatar/Avatar.js";
6
6
  import { Badge as s, BadgeCloseButton as c, BadgeStyle as d } from "./components/Badge/Badge.js";
7
7
  import { Banner as h } from "./components/Banner/Banner.js";
8
8
  import { BottomNavigation as S } from "./components/BottomNavigation/BottomNavigation.js";
@@ -18,7 +18,7 @@ import { DatePicker as Z } from "./components/DatePicker/DatePicker.js";
18
18
  import { Divider as $, DividerStyle as oo } from "./components/Divider/Divider.js";
19
19
  import { Drawer as eo } from "./components/Drawer/Drawer.js";
20
20
  import { DropdownMenu as ao, DropdownMenuStyle as po } from "./components/DropdownMenu/DropdownMenu.js";
21
- import { IconButton as io, IconButtonStyle as xo } from "./components/IconButton/IconButton.js";
21
+ import { IconButton as xo, IconButtonStyle as io } from "./components/IconButton/IconButton.js";
22
22
  import { List as fo } from "./components/List/List.js";
23
23
  import { ListItem as co, ListItemStyle as lo } from "./components/List/ListItem.js";
24
24
  import { ModalDialog as Co } from "./components/ModalDialog/ModalDialog.js";
@@ -31,20 +31,21 @@ import { RadioButton as Mo, RadioButtonStyle as wo, radioCheckedIconCss as Ao, r
31
31
  import { RadioGroup as Fo } from "./components/RadioButton/RadioGroup.js";
32
32
  import { Search as Uo, SearchStyle as Wo } from "./components/Search/Search.js";
33
33
  import { Select as qo, SelectStyle as zo } from "./components/Select/Select.js";
34
- import { Switch as Ho, SwitchStyle as Jo } from "./components/Switch/Switch.js";
35
- import { Tabs as Oo, TabsStyle as Qo } from "./components/Tabs/Tabs.js";
36
- import { TabItem as Xo, TabItemStyle as Yo } from "./components/Tabs/TabItem.js";
37
- import { TextArea as _o } from "./components/TextArea/TextArea.js";
38
- import { TextField as or } from "./components/TextField/TextField.js";
39
- import { Toast as er, ToastStyle as tr, toaster as ar } from "./components/Toast/Toast.js";
40
- import { Tooltip as mr } from "./components/Tooltip/Tooltip.js";
41
- import { TopAppBar as xr } from "./components/TopAppBar/TopAppBar.js";
42
- import { DataTableComponent as fr } from "./components/DataTable/DataTableComponent.js";
43
- import { parse as cr } from "./node_modules/@zag-js/date-picker/dist/index.js";
34
+ import { Steps as Ho } from "./components/Steps/Steps.js";
35
+ import { Switch as Ko, SwitchStyle as Oo } from "./components/Switch/Switch.js";
36
+ import { Tabs as Vo, TabsStyle as Xo } from "./components/Tabs/Tabs.js";
37
+ import { TabItem as Zo, TabItemStyle as _o } from "./components/Tabs/TabItem.js";
38
+ import { TextArea as or } from "./components/TextArea/TextArea.js";
39
+ import { TextField as er } from "./components/TextField/TextField.js";
40
+ import { Toast as ar, ToastStyle as pr, toaster as mr } from "./components/Toast/Toast.js";
41
+ import { Tooltip as ir } from "./components/Tooltip/Tooltip.js";
42
+ import { TopAppBar as fr } from "./components/TopAppBar/TopAppBar.js";
43
+ import { DataTableComponent as cr } from "./components/DataTable/DataTableComponent.js";
44
+ import { parse as lr } from "./node_modules/@zag-js/date-picker/dist/index.js";
44
45
  export {
45
46
  a as Accordion,
46
47
  m as AccordionGroup,
47
- x as Avatar,
48
+ i as Avatar,
48
49
  n as AvatarStyle,
49
50
  s as Badge,
50
51
  c as BadgeCloseButton,
@@ -61,15 +62,15 @@ export {
61
62
  K as ChoiceBoxStyle,
62
63
  Q as DashboardWidget,
63
64
  X as DataTable,
64
- fr as DataTableComponent,
65
+ cr as DataTableComponent,
65
66
  Z as DatePicker,
66
67
  $ as Divider,
67
68
  oo as DividerStyle,
68
69
  eo as Drawer,
69
70
  ao as DropdownMenu,
70
71
  po as DropdownMenuStyle,
71
- io as IconButton,
72
- xo as IconButtonStyle,
72
+ xo as IconButton,
73
+ io as IconButtonStyle,
73
74
  fo as List,
74
75
  co as ListItem,
75
76
  lo as ListItemStyle,
@@ -89,18 +90,19 @@ export {
89
90
  zo as SelectStyle,
90
91
  D as SerendieChartTheme,
91
92
  e as SerendiePreset,
92
- Ho as Switch,
93
- Jo as SwitchStyle,
94
- Xo as TabItem,
95
- Yo as TabItemStyle,
96
- Oo as Tabs,
97
- Qo as TabsStyle,
98
- _o as TextArea,
99
- or as TextField,
100
- er as Toast,
101
- tr as ToastStyle,
102
- mr as Tooltip,
103
- xr as TopAppBar,
93
+ Ho as Steps,
94
+ Ko as Switch,
95
+ Oo as SwitchStyle,
96
+ Zo as TabItem,
97
+ _o as TabItemStyle,
98
+ Vo as Tabs,
99
+ Xo as TabsStyle,
100
+ or as TextArea,
101
+ er as TextField,
102
+ ar as Toast,
103
+ pr as ToastStyle,
104
+ ir as Tooltip,
105
+ fr as TopAppBar,
104
106
  q as checkboxCheckedIconCss,
105
107
  z as checkboxIconCss,
106
108
  E as checkboxUncheckedIconCss,
@@ -109,12 +111,12 @@ export {
109
111
  M as getChartColor,
110
112
  w as getChartColors,
111
113
  A as legendChartMargin,
112
- cr as parseDate,
114
+ lr as parseDate,
113
115
  Ao as radioCheckedIconCss,
114
116
  Lo as radioIconCss,
115
117
  No as radioUncheckedIconCss,
116
118
  L as spaciousChartMargin,
117
- ar as toaster,
119
+ mr as toaster,
118
120
  N as useBarChartProps,
119
121
  R as useChartProps,
120
122
  F as useLineChartProps,
@@ -0,0 +1,13 @@
1
+ import { default as React } from 'react';
2
+ export interface StepsItemProps {
3
+ status?: "checked" | "active" | "disabled";
4
+ title: string;
5
+ description?: string;
6
+ index: number;
7
+ }
8
+ export interface StepsProps extends React.ComponentProps<"div"> {
9
+ items: StepsItemProps[];
10
+ direction?: "horizontal" | "vertical";
11
+ type?: "default" | "subtle";
12
+ }
13
+ export declare const Steps: React.ForwardRefExoticComponent<Omit<StepsProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,370 @@
1
+ import { jsx as t, jsxs as l } from "react/jsx-runtime";
2
+ import S from "react";
3
+ import { SerendieSymbolCheck as v } from "@serendie/symbols";
4
+ import { sva as C } from "../../styled-system/css/sva.js";
5
+ import { cx as z } from "../../styled-system/css/cx.js";
6
+ const m = C({
7
+ slots: [
8
+ "root",
9
+ "item",
10
+ "itemContent",
11
+ "icon",
12
+ "iconInner",
13
+ "checkIcon",
14
+ "number",
15
+ "connector",
16
+ "textContent",
17
+ "title",
18
+ "description"
19
+ ],
20
+ base: {
21
+ root: {
22
+ display: "flex",
23
+ gap: "0"
24
+ },
25
+ connector: {
26
+ position: "absolute",
27
+ backgroundColor: "sd.reference.color.scale.gray.200",
28
+ zIndex: 0
29
+ },
30
+ item: {
31
+ display: "flex",
32
+ position: "relative",
33
+ flex: "1"
34
+ },
35
+ itemContent: {
36
+ display: "flex",
37
+ alignItems: "center",
38
+ gap: "sd.system.dimension.spacing.small"
39
+ },
40
+ icon: {
41
+ display: "flex",
42
+ alignItems: "center",
43
+ justifyContent: "center",
44
+ borderRadius: "50%",
45
+ flexShrink: 0,
46
+ position: "relative",
47
+ zIndex: 1,
48
+ backgroundColor: "sd.system.color.component.surface"
49
+ },
50
+ iconInner: {
51
+ display: "flex",
52
+ alignItems: "center",
53
+ justifyContent: "center",
54
+ width: "100%",
55
+ height: "100%",
56
+ borderRadius: "50%"
57
+ },
58
+ checkIcon: {
59
+ width: "100%",
60
+ height: "100%"
61
+ },
62
+ number: {
63
+ fontWeight: "500"
64
+ },
65
+ textContent: {
66
+ display: "flex",
67
+ flexDirection: "column",
68
+ gap: "sd.system.dimension.spacing.twoExtraSmall",
69
+ zIndex: 1
70
+ },
71
+ title: {
72
+ textStyle: "sd.system.typography.label.large",
73
+ color: "sd.system.color.component.onSurface"
74
+ },
75
+ description: {
76
+ textStyle: "sd.system.typography.label.small",
77
+ color: "sd.system.color.component.onSurfaceVariant"
78
+ }
79
+ },
80
+ variants: {
81
+ direction: {
82
+ horizontal: {
83
+ root: {
84
+ flexDirection: "row"
85
+ },
86
+ connector: {
87
+ height: "2px"
88
+ },
89
+ item: {
90
+ flexDirection: "column"
91
+ },
92
+ itemContent: {
93
+ flexDirection: "column"
94
+ }
95
+ },
96
+ vertical: {
97
+ root: {
98
+ flexDirection: "column"
99
+ },
100
+ connector: {
101
+ width: "2px"
102
+ },
103
+ item: {
104
+ flexDirection: "row"
105
+ },
106
+ itemContent: {
107
+ flexDirection: "row"
108
+ }
109
+ }
110
+ },
111
+ size: {
112
+ large: {
113
+ icon: {
114
+ width: "40px",
115
+ height: "40px"
116
+ },
117
+ number: {
118
+ textStyle: "sd.system.typography.label.large"
119
+ }
120
+ },
121
+ small: {
122
+ icon: {
123
+ width: "12px",
124
+ height: "12px"
125
+ },
126
+ number: {
127
+ textStyle: "sd.system.typography.label.small"
128
+ },
129
+ title: {
130
+ textStyle: "sd.system.typography.label.medium"
131
+ },
132
+ description: {
133
+ textStyle: "sd.system.typography.label.small"
134
+ }
135
+ }
136
+ },
137
+ status: {
138
+ checked: {
139
+ icon: {
140
+ backgroundColor: "sd.system.color.impression.primary"
141
+ },
142
+ iconInner: {
143
+ color: "sd.system.color.impression.onPrimary"
144
+ }
145
+ },
146
+ active: {
147
+ icon: {
148
+ backgroundColor: "sd.system.color.impression.primary"
149
+ },
150
+ iconInner: {
151
+ color: "sd.system.color.impression.onPrimary"
152
+ }
153
+ },
154
+ disabled: {
155
+ icon: {
156
+ backgroundColor: "sd.reference.color.scale.gray.100"
157
+ },
158
+ iconInner: {
159
+ color: "sd.reference.color.scale.gray.400"
160
+ },
161
+ number: {
162
+ color: "sd.reference.color.scale.gray.400"
163
+ },
164
+ title: {
165
+ color: "sd.reference.color.scale.gray.400"
166
+ },
167
+ description: {
168
+ color: "sd.reference.color.scale.gray.400"
169
+ }
170
+ }
171
+ },
172
+ type: {
173
+ default: {},
174
+ subtle: {}
175
+ },
176
+ connectorState: {
177
+ default: {},
178
+ progress: {
179
+ connector: {
180
+ backgroundColor: "sd.system.color.impression.primary"
181
+ }
182
+ }
183
+ }
184
+ },
185
+ compoundVariants: [
186
+ {
187
+ status: "checked",
188
+ type: "subtle",
189
+ css: {
190
+ icon: {
191
+ border: "none",
192
+ backgroundColor: "sd.system.color.impression.primary"
193
+ }
194
+ }
195
+ },
196
+ {
197
+ status: "active",
198
+ type: "subtle",
199
+ css: {
200
+ icon: {
201
+ border: "2px solid",
202
+ borderColor: "sd.system.color.impression.primary",
203
+ backgroundColor: "sd.system.color.component.surface"
204
+ }
205
+ }
206
+ },
207
+ {
208
+ status: "disabled",
209
+ type: "subtle",
210
+ css: {
211
+ icon: {
212
+ border: "none",
213
+ backgroundColor: "sd.reference.color.scale.gray.400"
214
+ }
215
+ }
216
+ },
217
+ {
218
+ direction: "horizontal",
219
+ size: "large",
220
+ css: {
221
+ connector: {
222
+ top: "20px",
223
+ left: "calc(50% + 20px)",
224
+ right: "calc(-50% + 20px)"
225
+ },
226
+ title: {
227
+ textAlign: "center"
228
+ },
229
+ description: {
230
+ fontSize: "10px",
231
+ lineHeight: "10px",
232
+ textAlign: "center"
233
+ }
234
+ }
235
+ },
236
+ {
237
+ direction: "horizontal",
238
+ size: "small",
239
+ css: {
240
+ connector: {
241
+ top: "6px",
242
+ left: "calc(50% + 6px)",
243
+ right: "calc(-50% + 6px)"
244
+ },
245
+ title: {
246
+ textAlign: "center"
247
+ },
248
+ description: {
249
+ fontSize: "10px",
250
+ lineHeight: "10px",
251
+ textAlign: "center"
252
+ }
253
+ }
254
+ },
255
+ {
256
+ direction: "vertical",
257
+ size: "large",
258
+ css: {
259
+ item: {
260
+ paddingBottom: "24px"
261
+ },
262
+ connector: {
263
+ left: "19px",
264
+ top: "40px",
265
+ bottom: "calc(-40px)"
266
+ },
267
+ title: {
268
+ textStyle: "sd.system.typography.label.extraLarge"
269
+ },
270
+ description: {
271
+ fontSize: "9px",
272
+ lineHeight: "9px"
273
+ }
274
+ }
275
+ },
276
+ {
277
+ direction: "vertical",
278
+ size: "small",
279
+ css: {
280
+ item: {
281
+ paddingBottom: "16px"
282
+ },
283
+ connector: {
284
+ left: "5px",
285
+ top: "12px",
286
+ bottom: "calc(-12px)"
287
+ },
288
+ title: {
289
+ textStyle: "sd.system.typography.label.extraLarge"
290
+ },
291
+ description: {
292
+ fontSize: "9px",
293
+ lineHeight: "9px"
294
+ }
295
+ }
296
+ },
297
+ {
298
+ size: "large",
299
+ status: "checked",
300
+ type: "default",
301
+ css: {
302
+ icon: {
303
+ backgroundColor: "sd.system.color.component.inversePrimary"
304
+ },
305
+ iconInner: {
306
+ color: "sd.system.color.impression.primary"
307
+ }
308
+ }
309
+ },
310
+ {
311
+ size: "small",
312
+ status: "active",
313
+ type: "default",
314
+ css: {
315
+ icon: {
316
+ border: "2px solid",
317
+ borderColor: "sd.system.color.impression.primary",
318
+ backgroundColor: "sd.system.color.component.surface"
319
+ }
320
+ }
321
+ },
322
+ {
323
+ direction: "vertical",
324
+ size: "small",
325
+ type: "subtle",
326
+ css: {
327
+ connector: {
328
+ top: "16px",
329
+ bottom: "calc(-10px)"
330
+ }
331
+ }
332
+ }
333
+ ],
334
+ defaultVariants: {
335
+ direction: "horizontal",
336
+ status: "disabled",
337
+ type: "default",
338
+ connectorState: "default"
339
+ }
340
+ }), k = S.forwardRef(
341
+ ({ items: n, direction: c = "horizontal", type: r = "default", className: y, ...x }, u) => {
342
+ const a = r === "subtle" ? "small" : "large", g = m({ direction: c, size: a, type: r });
343
+ return /* @__PURE__ */ t("div", { ref: u, className: z(g.root, y), ...x, children: n.map((o, i) => {
344
+ const s = n[i + 1], h = (s == null ? void 0 : s.status) === "active" || (s == null ? void 0 : s.status) === "checked" ? "progress" : "default", e = m({
345
+ direction: c,
346
+ size: a,
347
+ status: o.status,
348
+ type: r,
349
+ connectorState: h
350
+ }), d = !(i === n.length - 1), p = c === "vertical" && r === "subtle", f = p ? {
351
+ top: "30px",
352
+ bottom: "-8px"
353
+ } : void 0, b = p && d ? { paddingBottom: "31.5px" } : void 0;
354
+ return /* @__PURE__ */ l("div", { className: e.item, style: b, children: [
355
+ /* @__PURE__ */ l("div", { className: e.itemContent, children: [
356
+ /* @__PURE__ */ t("div", { className: e.icon, children: /* @__PURE__ */ t("div", { className: e.iconInner, children: r === "subtle" ? null : o.status === "checked" ? /* @__PURE__ */ t(v, { className: e.checkIcon }) : /* @__PURE__ */ t("span", { className: e.number, children: o.index }) }) }),
357
+ /* @__PURE__ */ l("div", { className: e.textContent, children: [
358
+ /* @__PURE__ */ t("div", { className: e.title, children: o.title }),
359
+ o.description && /* @__PURE__ */ t("div", { className: e.description, children: o.description })
360
+ ] })
361
+ ] }),
362
+ d && /* @__PURE__ */ t("div", { className: e.connector, style: f })
363
+ ] }, i);
364
+ }) });
365
+ }
366
+ );
367
+ k.displayName = "Steps";
368
+ export {
369
+ k as Steps
370
+ };
@@ -0,0 +1,2 @@
1
+ export { Steps } from './Steps';
2
+ export type { StepsProps, StepsItemProps } from './Steps';
@@ -0,0 +1,4 @@
1
+ import { Steps as p } from "./Steps.js";
2
+ export {
3
+ p as Steps
4
+ };