@cakejp/design-system 0.12.0 → 0.13.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/CHANGELOG.md +43 -0
- package/CLAUDE.md +6 -2
- package/bin/check-duplicates.mjs +133 -9
- package/bin/exports-parser.mjs +54 -0
- package/bin/init.js +3 -0
- package/contracts/components.json +229 -25
- package/contracts/composition.json +10 -7
- package/contracts/rules.json +6 -4
- package/dist/index.css +1 -1
- package/dist/index.js +2951 -2204
- package/dist/types/components/ec/admin-shell.d.ts +30 -2
- package/dist/types/components/foundations/card.d.ts +27 -3
- package/dist/types/components/foundations/field.d.ts +26 -3
- package/dist/types/components/foundations/input.d.ts +3 -1
- package/dist/types/components/foundations/textarea.d.ts +3 -1
- package/dist/types/components/primitives/chat-composer.d.ts +87 -0
- package/dist/types/components/primitives/content-carousel.d.ts +7 -1
- package/dist/types/components/primitives/date-picker.d.ts +15 -3
- package/dist/types/components/primitives/funnel-shell.d.ts +2 -0
- package/dist/types/components/primitives/image-input.d.ts +119 -0
- package/dist/types/components/primitives/section-header.d.ts +9 -2
- package/dist/types/components/primitives/section.d.ts +35 -2
- package/dist/types/components/primitives/timeline.d.ts +23 -0
- package/dist/types/components/primitives/workspace-shell.d.ts +2 -0
- package/dist/types/index.d.ts +17 -5
- package/dist/types/lib/pagination-range.d.ts +16 -0
- package/dist/types/lib/use-value-length.d.ts +31 -0
- package/package.json +2 -1
- package/src/preset-standalone.css +16 -0
- package/src/preset.css +17 -0
- package/src/styles/typography.css +7 -0
- package/templates/AGENTS.md +2 -0
- package/templates/CLAUDE.md +2 -0
- package/tokens.json +9 -2
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
"version": "0.1.0",
|
|
5
5
|
"description": "全コンポーネントの構造化定義。バリアント・アクセシビリティ要件・使用ルールを機械可読形式で管理。",
|
|
6
6
|
"kind": "kind:\"shell\" は複数ページで再利用されるレイアウト枠(AdminShell / WorkspaceShell / MypageShell 等)。無印は部品コンポーネント。固有ページを組むときは該当 shell から始める。src/components/pages/ 配下のストーリーは特定ページ専用・非配布のため contracts の対象外。",
|
|
7
|
+
"exportNaming": "name は原則そのまま @cakejp/design-system から import できる export 名。例外は機械可読に印を付ける — exported:false=name は実装ファイル/グループ名で import できない(実 export は subcomponents 側。例: CheckboxCard → CheckboxCardGroup / CheckboxCardItem)、exportedAs=別名で export される(例: FormField → CakeFormField)、deprecatedAliases=互換のため残す旧 export 名(新規利用禁止)。この対応は __tests__/contracts-export-integrity.test.ts が src/index.ts と突き合わせて固定し、bin/check-duplicates.mjs の照合対象もこの規約に従う。",
|
|
8
|
+
"formBinding": "react-hook-form との繋ぎ方。formBinding:\"register\"=ネイティブ form control に props/ref を透過するので {...register(\"name\")} を直接 spread できる(Input / Textarea)。formBinding:\"controller\"=Radix ベースで ref が <button> 等に着地する、または値が Date/File など非文字列のため Controller の field.value / field.onChange に繋ぐ。formBinding:\"layout\"=値を持たないレイアウト部品でバインド対象ではない(Field / Form / FormField / ProductOption)。formBinding:\"none\"=値は扱うが単一フィールドのバインド対象ではない自己完結フォーム・複合ウィジェット(DataTable / SearchBar / ReviewForm)。この切り分けは __tests__/react-hook-form-integration.test.tsx が実挙動で固定する(issue #151 / #152)。",
|
|
7
9
|
"counts": {
|
|
8
10
|
"foundations": 50,
|
|
9
|
-
"primitives":
|
|
11
|
+
"primitives": 47,
|
|
10
12
|
"ec": 24,
|
|
11
|
-
"total":
|
|
13
|
+
"total": 121,
|
|
14
|
+
"note": "counts は各ティアの実装ファイル数(scripts/check-drift.sh が src/components/<tier>/*.tsx と突き合わせる)。subcomponents / deprecatedAliases は含まない。"
|
|
12
15
|
}
|
|
13
16
|
},
|
|
14
17
|
"foundations": [
|
|
@@ -104,6 +107,10 @@
|
|
|
104
107
|
],
|
|
105
108
|
"rules": [
|
|
106
109
|
"<button>を直接使わない。必ずButtonコンポーネントを使う",
|
|
110
|
+
"高さは size='default'=44px(h-11) / xs=24px / sm=32px / lg=48px / xl=56px / hero=min 56px。default はフォーム入力コントロール(Input / SelectTrigger default / DatePicker trigger)と同じ 44px なので、入力行にボタンを並置しても揃う",
|
|
111
|
+
"⚠️ variant='secondary' はブランドアクセント意匠(Surface-Accent-Primary-Light地+Brand-Cake-Orange文字)。Material/Bootstrap/shadcn の secondary(グレー・控えめ)とは別物なので、他DSの感覚で選ばない",
|
|
112
|
+
"「戻る」「キャンセル」「閉じる」「スキップ」「あとで」等の後退・中立アクションは variant='tertiary'(Surface-Tertiary地+Text-High-Emphasis文字のニュートラルなグレー)を使う。主CTAの隣に置く2番目のボタンでも、役割が後退なら secondary ではなく tertiary",
|
|
113
|
+
"variant='secondary' を使うのは、主CTAと別方向の“前進”を促す副CTAのとき(例: 主='購入する' に対し 副='サンプルを見る')",
|
|
107
114
|
"variant='overlay'は画像・メディアの上に載せる操作ボタン専用(半透過白のSurface-Overlay-Light下地+shadow-md+backdrop-blur-sm)。ImageCarousel矢印と同系の意匠。size='icon'+className='rounded-full'で円形にできる"
|
|
108
115
|
]
|
|
109
116
|
},
|
|
@@ -133,20 +140,33 @@
|
|
|
133
140
|
"rules": [
|
|
134
141
|
"paddingはCard本体のp-4で一括管理。全幅コンテンツは-mx-4で突き破る",
|
|
135
142
|
"子要素の縦間隔はCard本体のflex-col gap-4(16px)で一括管理。直下の子にmargin-top/bottom/space-yを足さない(gapと二重がけになり間延びする)。丸アイコンはIconBadgeを使う(外側marginを持たない)",
|
|
136
|
-
"surface='default'(既定)は
|
|
143
|
+
"surface='default'(既定)は --card-surface(親から伝播したサーフェス文脈)→無ければ --card(Surface-Secondary)。surface='primary'は文脈に関係なく白(Surface-Primary)で固定する",
|
|
144
|
+
"Section background='subtle'|'accent-subtle' と、地がSurface-Secondaryのシェル(AdminShell / WorkspaceShell / FunnelShell)の配下では --card-surface が伝播するため、Card は surface 未指定のまま自動で白になる(surface='primary' の明示指定は従来通り有効で優先)",
|
|
145
|
+
"DSのSectionを使わない自前のグレー地では、親要素に className='[--card-surface:var(--Surface-Primary)]' を宣言すれば配下Cardが白になる(darkにも配慮するなら dark:[--card-surface:var(--Surface-Secondary)] を併記)。1枚だけ地に馴染ませたいときは className='bg-card' で上書きする"
|
|
137
146
|
]
|
|
138
147
|
},
|
|
139
148
|
{
|
|
140
149
|
"name": "CheckboxCard",
|
|
141
|
-
"path": "src/components/foundations/checkbox-card.tsx"
|
|
150
|
+
"path": "src/components/foundations/checkbox-card.tsx",
|
|
151
|
+
"formBinding": "controller",
|
|
152
|
+
"exported": false,
|
|
153
|
+
"subcomponents": [
|
|
154
|
+
"CheckboxCardGroup",
|
|
155
|
+
"CheckboxCardItem"
|
|
156
|
+
]
|
|
142
157
|
},
|
|
143
158
|
{
|
|
144
159
|
"name": "CheckboxGroup",
|
|
145
|
-
"path": "src/components/foundations/checkbox-group.tsx"
|
|
160
|
+
"path": "src/components/foundations/checkbox-group.tsx",
|
|
161
|
+
"formBinding": "controller",
|
|
162
|
+
"subcomponents": [
|
|
163
|
+
"CheckboxGroupItem"
|
|
164
|
+
]
|
|
146
165
|
},
|
|
147
166
|
{
|
|
148
167
|
"name": "Checkbox",
|
|
149
168
|
"path": "src/components/foundations/checkbox.tsx",
|
|
169
|
+
"formBinding": "controller",
|
|
150
170
|
"accessibility": [
|
|
151
171
|
"必ずLabelと紐付ける"
|
|
152
172
|
]
|
|
@@ -170,6 +190,7 @@
|
|
|
170
190
|
{
|
|
171
191
|
"name": "DataTable",
|
|
172
192
|
"path": "src/components/foundations/data-table.tsx",
|
|
193
|
+
"formBinding": "none",
|
|
173
194
|
"rules": [
|
|
174
195
|
"管理画面のテーブルはui/tableでなくこちらを使う。ソート・選択行・アクションメニュー対応",
|
|
175
196
|
"ActionCellのメニュー操作は行のonClickへ伝播しない(本体でstopPropagation済み)。行クリック選択との併用時も利用側ガードは不要"
|
|
@@ -202,7 +223,9 @@
|
|
|
202
223
|
{
|
|
203
224
|
"name": "Field",
|
|
204
225
|
"path": "src/components/foundations/field.tsx",
|
|
226
|
+
"formBinding": "layout",
|
|
205
227
|
"subcomponents": [
|
|
228
|
+
"FieldLabel",
|
|
206
229
|
"FieldSet",
|
|
207
230
|
"FieldLegend",
|
|
208
231
|
"FieldGroup",
|
|
@@ -211,7 +234,8 @@
|
|
|
211
234
|
"FieldSeparator"
|
|
212
235
|
],
|
|
213
236
|
"rules": [
|
|
214
|
-
"
|
|
237
|
+
"フォーム全体の骨格を組む補助群。ラベル+入力+エラーが一体で済むなら FormField が最短。ラベル・入力・説明・エラーを個別に組むときは Field + FieldLabel を使う",
|
|
238
|
+
"Field は 1 フィールド分の箱(縦リズムの最小単位)。orientation='vertical'(既定)/'horizontal'/'responsive'。responsive は FieldGroup の @container/field-group を基準に狭い=縦・広い=横へ切り替わる",
|
|
215
239
|
"余白は縦リズムに従う(FieldSet=gap-6 / FieldGroup=gap-4)。手で mt-/mb- を足さない",
|
|
216
240
|
"見出しは FieldLegend、グループ横断の区切りは FieldSeparator を使う"
|
|
217
241
|
]
|
|
@@ -219,6 +243,15 @@
|
|
|
219
243
|
{
|
|
220
244
|
"name": "Form",
|
|
221
245
|
"path": "src/components/foundations/form.tsx",
|
|
246
|
+
"formBinding": "layout",
|
|
247
|
+
"subcomponents": [
|
|
248
|
+
"FormField",
|
|
249
|
+
"FormItem",
|
|
250
|
+
"FormLabel",
|
|
251
|
+
"FormControl",
|
|
252
|
+
"FormDescription",
|
|
253
|
+
"FormMessage"
|
|
254
|
+
],
|
|
222
255
|
"accessibility": [
|
|
223
256
|
"aria-describedbyでエラーメッセージを紐付ける"
|
|
224
257
|
]
|
|
@@ -245,12 +278,16 @@
|
|
|
245
278
|
{
|
|
246
279
|
"name": "Input",
|
|
247
280
|
"path": "src/components/foundations/input.tsx",
|
|
281
|
+
"formBinding": "register",
|
|
248
282
|
"accessibility": [
|
|
249
283
|
"必ずLabelと紐付ける"
|
|
250
284
|
],
|
|
251
285
|
"rules": [
|
|
252
286
|
"<input>を直接使わない。type='email'/'tel'を適切に指定する",
|
|
253
|
-
"
|
|
287
|
+
"高さは 44px(h-11)。フォーム入力コントロールと Button の既定(Input / SelectTrigger default / DatePicker trigger / Button size='default')は 44px で統一されており、検索+絞り込みセレクト+ボタンのような並置でも揃う",
|
|
288
|
+
"44px は rules.json の touchTarget『Text input』の min を満たす値であり、DS の既定として採用している。recommended の 48px まで上げたい画面は consumer が className='h-12' で上書きする",
|
|
289
|
+
"文字数カウンタは showCount + maxLength で有効化(右下に {現在}/{max}、上限で Text-Caution)。制御/非制御両対応",
|
|
290
|
+
"非制御は react-hook-form の register() / reset() で ref 経由に値が入る実利用経路まで story とテストで検証する"
|
|
254
291
|
]
|
|
255
292
|
},
|
|
256
293
|
{
|
|
@@ -288,21 +325,33 @@
|
|
|
288
325
|
{
|
|
289
326
|
"name": "RadioGroup",
|
|
290
327
|
"path": "src/components/foundations/radio-group.tsx",
|
|
328
|
+
"formBinding": "controller",
|
|
329
|
+
"subcomponents": [
|
|
330
|
+
"RadioGroupItem"
|
|
331
|
+
],
|
|
291
332
|
"variants": [
|
|
292
333
|
"tile",
|
|
293
334
|
"chip"
|
|
294
335
|
],
|
|
295
336
|
"accessibility": [
|
|
296
|
-
"各RadioGroupItem
|
|
337
|
+
"各RadioGroupItemにラベルテキスト必須。ラベルは children として RadioGroupItem の内側に書く(<RadioGroupItem value='x'>ラベル</RadioGroupItem>)。RadioGroupItem が内部で <label> 相当の関連付けまで行うため、外側に <Label htmlFor> を併置してはいけない(ラベル重複になる)"
|
|
338
|
+
],
|
|
339
|
+
"props": [
|
|
340
|
+
"children: ラベル本文(必須。tile/chip 共通)",
|
|
341
|
+
"description?: ReactNode — ラベル下の補足説明(tile のみ)",
|
|
342
|
+
"expandedContent?: ReactNode — 選択時に展開する追加コンテンツ(tile のみ)"
|
|
297
343
|
],
|
|
298
344
|
"rules": [
|
|
299
345
|
"variant='tile'(既定)=ラジオ丸+ラベル+補足説明+展開コンテンツのタイル型",
|
|
346
|
+
"⚠️ タイルの枠(border/角丸/余白/選択状態の意匠)は RadioGroupItem 自身が描画する。consumer 側で <div className='border rounded-lg ...'> 等で囲むと枠が二重になる。囲まずにそのまま並べる",
|
|
347
|
+
"ラベルは children で渡す。<RadioGroupItem/> と <Label htmlFor> を兄弟に並べる書き方は誤り(枠の二重化+ラベル重複を招く)",
|
|
300
348
|
"variant='chip'=ラベルを内包したChoice Chip意匠の排他選択(タグ選択・絞り込み等)。ラジオ丸は描画せず、Chip本体と同じchipVariantsを再利用して選択状態をaccent意匠(静止=薄オレンジ/hover=ベタ塗り)で示す。description/expandedContentは持たない。Radixのキーボード操作・a11yは維持"
|
|
301
349
|
]
|
|
302
350
|
},
|
|
303
351
|
{
|
|
304
352
|
"name": "FileInput",
|
|
305
353
|
"path": "src/components/foundations/file-input.tsx",
|
|
354
|
+
"formBinding": "controller",
|
|
306
355
|
"accessibility": [
|
|
307
356
|
"idをLabel/FormFieldのhtmlForと揃えて紐付ける",
|
|
308
357
|
"ネイティブ<input type='file'>をvisually-hiddenで内包しキーボード・SR操作可能",
|
|
@@ -310,7 +359,8 @@
|
|
|
310
359
|
],
|
|
311
360
|
"rules": [
|
|
312
361
|
"<input type='file'>を直接書かない。汎用の添付(PDF/CSV/画像混在)はFileInputを使う",
|
|
313
|
-
"
|
|
362
|
+
"画像1枚の入力(プレビュー+形式/サイズ検証+値のバインド)はImageInputを使う",
|
|
363
|
+
"複数枚の画像を並べて管理するグリッドはImageUploaderを使う",
|
|
314
364
|
"複数選択時(multiple)は選択済みを「n件選択」で集約表示",
|
|
315
365
|
"maxSize(バイト)超過ファイルは受理せずonErrorを呼ぶ"
|
|
316
366
|
]
|
|
@@ -329,8 +379,10 @@
|
|
|
329
379
|
{
|
|
330
380
|
"name": "Select",
|
|
331
381
|
"path": "src/components/foundations/select.tsx",
|
|
382
|
+
"formBinding": "controller",
|
|
332
383
|
"rules": [
|
|
333
|
-
"<select>HTMLネイティブを使わない"
|
|
384
|
+
"<select>HTMLネイティブを使わない",
|
|
385
|
+
"SelectTrigger の高さは size='default'=44px(h-11)で Input / DatePicker trigger / Button default と揃う。size='sm'=36px。高さは素のクラスで当てているため className='h-12' 等で上書きできる(data 属性セレクタではない)"
|
|
334
386
|
]
|
|
335
387
|
},
|
|
336
388
|
{
|
|
@@ -373,13 +425,15 @@
|
|
|
373
425
|
},
|
|
374
426
|
{
|
|
375
427
|
"name": "Slider",
|
|
376
|
-
"path": "src/components/foundations/slider.tsx"
|
|
428
|
+
"path": "src/components/foundations/slider.tsx",
|
|
429
|
+
"formBinding": "controller"
|
|
377
430
|
},
|
|
378
431
|
{
|
|
379
|
-
"name": "
|
|
432
|
+
"name": "Toaster",
|
|
380
433
|
"path": "src/components/foundations/sonner.tsx",
|
|
381
434
|
"rules": [
|
|
382
|
-
"トースト内にアクションリンクを入れない。左ボーダーではなく背景色全体で状態を表現"
|
|
435
|
+
"トースト内にアクションリンクを入れない。左ボーダーではなく背景色全体で状態を表現",
|
|
436
|
+
"アプリのルートに <Toaster /> を1つ置き、表示は toast()(sonner の再 export)で呼ぶ"
|
|
383
437
|
]
|
|
384
438
|
},
|
|
385
439
|
{
|
|
@@ -389,6 +443,7 @@
|
|
|
389
443
|
{
|
|
390
444
|
"name": "Switch",
|
|
391
445
|
"path": "src/components/foundations/switch.tsx",
|
|
446
|
+
"formBinding": "controller",
|
|
392
447
|
"accessibility": [
|
|
393
448
|
"Label必須"
|
|
394
449
|
]
|
|
@@ -412,23 +467,27 @@
|
|
|
412
467
|
{
|
|
413
468
|
"name": "Textarea",
|
|
414
469
|
"path": "src/components/foundations/textarea.tsx",
|
|
470
|
+
"formBinding": "register",
|
|
415
471
|
"accessibility": [
|
|
416
472
|
"Label必須"
|
|
417
473
|
],
|
|
418
474
|
"rules": [
|
|
419
|
-
"文字数カウンタは showCount + maxLength で有効化(右下に {現在}/{max}、上限で Text-Caution)。制御/非制御両対応"
|
|
475
|
+
"文字数カウンタは showCount + maxLength で有効化(右下に {現在}/{max}、上限で Text-Caution)。制御/非制御両対応",
|
|
476
|
+
"非制御は react-hook-form の register() / reset() で ref 経由に値が入る実利用経路まで story とテストで検証する"
|
|
420
477
|
]
|
|
421
478
|
},
|
|
422
479
|
{
|
|
423
480
|
"name": "ToggleGroup",
|
|
424
481
|
"path": "src/components/foundations/toggle-group.tsx",
|
|
482
|
+
"formBinding": "controller",
|
|
425
483
|
"rules": [
|
|
426
484
|
"水平パディングはコンポーネント内に入れない。親が管理する"
|
|
427
485
|
]
|
|
428
486
|
},
|
|
429
487
|
{
|
|
430
488
|
"name": "Toggle",
|
|
431
|
-
"path": "src/components/foundations/toggle.tsx"
|
|
489
|
+
"path": "src/components/foundations/toggle.tsx",
|
|
490
|
+
"formBinding": "controller"
|
|
432
491
|
},
|
|
433
492
|
{
|
|
434
493
|
"name": "Tooltip",
|
|
@@ -454,10 +513,12 @@
|
|
|
454
513
|
"scroll-snap",
|
|
455
514
|
"dots",
|
|
456
515
|
"arrows",
|
|
457
|
-
"autoPlay"
|
|
516
|
+
"autoPlay",
|
|
517
|
+
"itemsPerView"
|
|
458
518
|
],
|
|
459
519
|
"rules": [
|
|
460
520
|
"ReactNode スライド対応(slides: ReactNode[])。テキスト主体のヒーローバナー用",
|
|
521
|
+
"itemsPerView=2|3|4 で PC の複数カード表示に対応。SP は1枚表示を維持し、EC 商品以外の求人・記事カード等にも使う",
|
|
461
522
|
"画像だけのバナーは ImageCarousel を使う",
|
|
462
523
|
"矢印・ドットの意匠は ImageCarousel と同一"
|
|
463
524
|
]
|
|
@@ -491,6 +552,35 @@
|
|
|
491
552
|
"name": "CategoryScroll",
|
|
492
553
|
"path": "src/components/primitives/category-scroll.tsx"
|
|
493
554
|
},
|
|
555
|
+
{
|
|
556
|
+
"name": "ChatComposer",
|
|
557
|
+
"path": "src/components/primitives/chat-composer.tsx",
|
|
558
|
+
"formBinding": "controller",
|
|
559
|
+
"variants": [
|
|
560
|
+
"submitKey:enter",
|
|
561
|
+
"submitKey:mod-enter"
|
|
562
|
+
],
|
|
563
|
+
"features": [
|
|
564
|
+
"attachments",
|
|
565
|
+
"maxFiles",
|
|
566
|
+
"maxSizeMb",
|
|
567
|
+
"maxLength",
|
|
568
|
+
"isSubmitting"
|
|
569
|
+
],
|
|
570
|
+
"accessibility": [
|
|
571
|
+
"入力欄はvisually-hiddenのlabel(label prop)とhtmlForで紐付ける",
|
|
572
|
+
"送信ボタンのaria-labelは日本語(送信 / 送信中)",
|
|
573
|
+
"添付削除はChipのremovableで操作でき、キーボードで到達できる"
|
|
574
|
+
],
|
|
575
|
+
"rules": [
|
|
576
|
+
"チャット・問い合わせ・返信の入力欄をTextarea+Buttonで手組みしない",
|
|
577
|
+
"既定はEnter送信・Shift+Enter改行。長文が主なsubmitKey='mod-enter'を使う",
|
|
578
|
+
"IME変換中のEnterでは送信しない(日本語入力の誤送信防止)",
|
|
579
|
+
"添付は内蔵のFileInputで選択し、選択済みはChipのremovableで表示・削除する",
|
|
580
|
+
"送信中はisSubmittingを立てる(送信ボタン無効化で二重送信を防ぐ)",
|
|
581
|
+
"<form>を内包しないため、フォーム内に置いても入れ子にならない"
|
|
582
|
+
]
|
|
583
|
+
},
|
|
494
584
|
{
|
|
495
585
|
"name": "Chip",
|
|
496
586
|
"path": "src/components/primitives/chip.tsx",
|
|
@@ -510,6 +600,7 @@
|
|
|
510
600
|
{
|
|
511
601
|
"name": "DatePicker",
|
|
512
602
|
"path": "src/components/primitives/date-picker.tsx",
|
|
603
|
+
"formBinding": "controller",
|
|
513
604
|
"subcomponents": [
|
|
514
605
|
"DateTimePicker"
|
|
515
606
|
],
|
|
@@ -562,6 +653,8 @@
|
|
|
562
653
|
{
|
|
563
654
|
"name": "FormField",
|
|
564
655
|
"path": "src/components/primitives/form-field.tsx",
|
|
656
|
+
"formBinding": "layout",
|
|
657
|
+
"exportedAs": "CakeFormField",
|
|
565
658
|
"variants": {
|
|
566
659
|
"descriptionPosition": [
|
|
567
660
|
"above",
|
|
@@ -570,7 +663,8 @@
|
|
|
570
663
|
},
|
|
571
664
|
"rules": [
|
|
572
665
|
"Label+Input+エラーメッセージをセットで管理",
|
|
573
|
-
"グリッド横並び時は descriptionPosition='below' で高さを揃える"
|
|
666
|
+
"グリッド横並び時は descriptionPosition='below' で高さを揃える",
|
|
667
|
+
"npm 経由では CakeFormField として import する(foundations/form.tsx の FormField と名前が衝突するため別名で export)"
|
|
574
668
|
]
|
|
575
669
|
},
|
|
576
670
|
{
|
|
@@ -587,6 +681,52 @@
|
|
|
587
681
|
"name": "ImageGallery",
|
|
588
682
|
"path": "src/components/primitives/image-gallery.tsx"
|
|
589
683
|
},
|
|
684
|
+
{
|
|
685
|
+
"name": "ImageInput",
|
|
686
|
+
"path": "src/components/primitives/image-input.tsx",
|
|
687
|
+
"formBinding": "controller",
|
|
688
|
+
"variants": [
|
|
689
|
+
"aspect:square",
|
|
690
|
+
"aspect:landscape",
|
|
691
|
+
"size:sm",
|
|
692
|
+
"size:md",
|
|
693
|
+
"size:lg",
|
|
694
|
+
"objectFit:cover",
|
|
695
|
+
"objectFit:contain"
|
|
696
|
+
],
|
|
697
|
+
"features": [
|
|
698
|
+
"preview",
|
|
699
|
+
"accept",
|
|
700
|
+
"maxSizeMb",
|
|
701
|
+
"clear",
|
|
702
|
+
"formBinding"
|
|
703
|
+
],
|
|
704
|
+
"props": [
|
|
705
|
+
"value: File | string | null — Fileは新規選択・stringは保存済み画像のURL(必須)",
|
|
706
|
+
"onChange: (file: File | null) => void — 検証を通ったファイルのみ渡る(必須)",
|
|
707
|
+
"onBlur?: () => void — フォーカスが部品外へ抜けたとき(React Hook Form の touched 連携)",
|
|
708
|
+
"id? / name? — 内包 input に付与。FormField の htmlFor と揃える",
|
|
709
|
+
"accept?: string — 既定 'image/png,image/jpeg'",
|
|
710
|
+
"maxSizeMb?: number — 既定 2",
|
|
711
|
+
"error?: string — 外部(RHF等)のエラー。内蔵検証のエラーより優先して表示",
|
|
712
|
+
"onValidationError?: (error) => void — 検証エラーをモーダル等で出したい場合のみ"
|
|
713
|
+
],
|
|
714
|
+
"accessibility": [
|
|
715
|
+
"検証エラーはFieldError(role='alert')にインライン表示し、色だけで伝えない",
|
|
716
|
+
"内包inputにaria-invalid / aria-describedbyを付けてエラーと紐付ける",
|
|
717
|
+
"クリアボタンのaria-labelは日本語(画像を削除)",
|
|
718
|
+
"ファイル選択の口はFileInputを内包し、キーボード・SRで操作できる"
|
|
719
|
+
],
|
|
720
|
+
"rules": [
|
|
721
|
+
"画像1枚の入力を<input type='file'>+<img>で手組みしない",
|
|
722
|
+
"value/onChangeの制御コンポーネント。保存済み画像はURL文字列をそのまま渡す",
|
|
723
|
+
"プレビューのobjectURLは内部でrevokeされる。consumer側でcreateObjectURLしない",
|
|
724
|
+
"検証エラーの既定はインライン表示。モーダルは強すぎるため既定にしない",
|
|
725
|
+
"表示サイズはaspect(square/landscape)×size(sm/md/lg)で指定し、任意のw-[Npx]を足さない",
|
|
726
|
+
"非同期検証(画像寸法チェック等)は持たない。onChange後にconsumer側で検証しerrorで戻す",
|
|
727
|
+
"汎用の添付はFileInput(foundations)、複数枚のグリッド管理はImageUploader(primitives)"
|
|
728
|
+
]
|
|
729
|
+
},
|
|
590
730
|
{
|
|
591
731
|
"name": "ImageUploader",
|
|
592
732
|
"path": "src/components/primitives/image-uploader.tsx",
|
|
@@ -594,6 +734,10 @@
|
|
|
594
734
|
"upload",
|
|
595
735
|
"delete",
|
|
596
736
|
"grid"
|
|
737
|
+
],
|
|
738
|
+
"rules": [
|
|
739
|
+
"複数枚の画像を並べて管理するグリッド。ファイル選択の口は持たず、追加はonAddでconsumerが実装する",
|
|
740
|
+
"画像1枚の入力(プレビュー+検証+値のバインド)はImageInputを使う"
|
|
597
741
|
]
|
|
598
742
|
},
|
|
599
743
|
{
|
|
@@ -646,9 +790,24 @@
|
|
|
646
790
|
"name": "ProgressSteps",
|
|
647
791
|
"path": "src/components/primitives/progress-steps.tsx"
|
|
648
792
|
},
|
|
793
|
+
{
|
|
794
|
+
"name": "Timeline",
|
|
795
|
+
"path": "src/components/primitives/timeline.tsx",
|
|
796
|
+
"features": [
|
|
797
|
+
"vertical",
|
|
798
|
+
"custom-marker",
|
|
799
|
+
"connector"
|
|
800
|
+
],
|
|
801
|
+
"rules": [
|
|
802
|
+
"本文付きの縦タイムラインに使う。現在位置を示す横型インジケータは ProgressSteps を使う",
|
|
803
|
+
"marker 省略時は連番。IconBadge 等の ReactNode を渡せる",
|
|
804
|
+
"コネクター線は Timeline が所有するため consumer が ::before / ::after で手組みしない"
|
|
805
|
+
]
|
|
806
|
+
},
|
|
649
807
|
{
|
|
650
808
|
"name": "QuantitySelector",
|
|
651
809
|
"path": "src/components/primitives/quantity-selector.tsx",
|
|
810
|
+
"formBinding": "controller",
|
|
652
811
|
"features": [
|
|
653
812
|
"increment",
|
|
654
813
|
"decrement",
|
|
@@ -657,7 +816,8 @@
|
|
|
657
816
|
},
|
|
658
817
|
{
|
|
659
818
|
"name": "SearchBar",
|
|
660
|
-
"path": "src/components/primitives/search-bar.tsx"
|
|
819
|
+
"path": "src/components/primitives/search-bar.tsx",
|
|
820
|
+
"formBinding": "none"
|
|
661
821
|
},
|
|
662
822
|
{
|
|
663
823
|
"name": "SearchPanel",
|
|
@@ -684,12 +844,18 @@
|
|
|
684
844
|
"path": "src/components/primitives/section.tsx",
|
|
685
845
|
"variants": [
|
|
686
846
|
"spacing: sm | md | lg | xl",
|
|
687
|
-
"background: none | subtle | accent-subtle"
|
|
847
|
+
"background: none | subtle | accent-subtle",
|
|
848
|
+
"scrim: none | dark | light | bottom-dark"
|
|
688
849
|
],
|
|
689
850
|
"rules": [
|
|
690
851
|
"全幅の縦リズム+背景帯。左右paddingを持たない(左右余白はContainerが唯一の担い手)",
|
|
852
|
+
"背景画像上に文字を載せる場合は backgroundImage + scrim を使う。consumer が gradient overlay を ::before / ::after で手組みしない",
|
|
853
|
+
"scrim は Surface-Overlay-Light / Dark を使い、dark / light / bottom-dark の意匠を DS が所有する",
|
|
691
854
|
"背景色はSection(全幅)が持ち中央寄せはContainerが持つ → 背景帯は画面端まで・コンテンツは中央寄せが二重がけなしで成立",
|
|
692
|
-
"縦余白はSP/PCペアで --Space-Section-* トークンを消費(rem直書き撲滅)"
|
|
855
|
+
"縦余白はSP/PCペアで --Space-Section-* トークンを消費(rem直書き撲滅)",
|
|
856
|
+
"background='subtle'|'accent-subtle'(色地)は配下に --card-surface: var(--Surface-Primary) を流す → 配下のCardはsurface未指定でも白になる(グレー地にカードが沈む事故を構造で防ぐ)。伝播はCSSカスタムプロパティのみでReact context不使用=Server Componentのまま使える",
|
|
857
|
+
"background='none'は文脈をリセットしない。色地Sectionの内側に入れ子にしたnoneは背景が透過して外側の色地が見えるため、配下Cardも白のままが正しい",
|
|
858
|
+
"darkでは伝播値をSurface-Secondaryに据え置く(darkのSurface-Secondaryは半透明白=色地に重なって一段明るく浮くのでそもそも沈まない。Surface-Primaryを強制すると地より暗い穴になりelevationが反転する)"
|
|
693
859
|
]
|
|
694
860
|
},
|
|
695
861
|
{
|
|
@@ -697,11 +863,13 @@
|
|
|
697
863
|
"path": "src/components/primitives/section-header.tsx",
|
|
698
864
|
"variants": [
|
|
699
865
|
"size: 3xl | 2xl | xl | lg | md | sm",
|
|
866
|
+
"desktopSize: 5xl | 4xl",
|
|
700
867
|
"align: start | center"
|
|
701
868
|
],
|
|
702
869
|
"rules": [
|
|
703
870
|
"タイトル+もっと見るボタンをCardTitle+Button手書き禁止。SectionHeaderを使う",
|
|
704
|
-
"中央寄せ大見出し(ランディング/ガイド系)は align=\"center\" を使う。eyebrow プロップに Badge 等を載せられる。手書きの中央寄せ見出し禁止"
|
|
871
|
+
"中央寄せ大見出し(ランディング/ガイド系)は align=\"center\" を使う。eyebrow プロップに Badge 等を載せられる。手書きの中央寄せ見出し禁止",
|
|
872
|
+
"3xl(28px)は通常ページの主見出しにも使う。4xl/5xlはLP・マーケティング系ヒーロー専用で、size=\"3xl\" に desktopSize=\"4xl\" または desktopSize=\"5xl\" を加えてPC時だけ拡大する"
|
|
705
873
|
]
|
|
706
874
|
},
|
|
707
875
|
{
|
|
@@ -716,7 +884,8 @@
|
|
|
716
884
|
"name": "StatusCountTabs",
|
|
717
885
|
"path": "src/components/primitives/status-count-tabs.tsx",
|
|
718
886
|
"rules": [
|
|
719
|
-
"ToggleGroup+Badge手書き禁止。Chip count propを使う"
|
|
887
|
+
"ToggleGroup+Badge手書き禁止。Chip count propを使う",
|
|
888
|
+
"activeIndex は初期値だけでなく、マウント後の外部変更にも表示が追従する"
|
|
720
889
|
]
|
|
721
890
|
},
|
|
722
891
|
{
|
|
@@ -758,6 +927,9 @@
|
|
|
758
927
|
"name": "StandardPageShell",
|
|
759
928
|
"path": "src/components/primitives/standard-page-shell.tsx",
|
|
760
929
|
"kind": "shell",
|
|
930
|
+
"deprecatedAliases": [
|
|
931
|
+
"EcPageShell"
|
|
932
|
+
],
|
|
761
933
|
"variants": [],
|
|
762
934
|
"rules": [
|
|
763
935
|
"消費者向け標準ページ(Standard Page(View / Edit))の骨格。composition.json pageSkeletons(mobile / desktop)の実装体。min-h-dvh flex flex-col の全高コンテナに header / main / bottomTab / footer を積む",
|
|
@@ -773,6 +945,9 @@
|
|
|
773
945
|
"name": "WorkspaceShell",
|
|
774
946
|
"path": "src/components/primitives/workspace-shell.tsx",
|
|
775
947
|
"kind": "shell",
|
|
948
|
+
"deprecatedAliases": [
|
|
949
|
+
"WorkspaceLayout"
|
|
950
|
+
],
|
|
776
951
|
"variants": [
|
|
777
952
|
"headerLayout=start",
|
|
778
953
|
"headerLayout=center"
|
|
@@ -784,6 +959,7 @@
|
|
|
784
959
|
"primaryActionはワークスペース全体の上位アクション(公開申請・承認依頼等)がある場合のみ。セクション/行単位の操作はコンテンツ内に置く",
|
|
785
960
|
"標準の編集はAdminShellのStandard Page(Edit)(旧Form Page)。複雑・複数情報をまたぐ集中編集・没入執筆のみWorkspaceShellを使う",
|
|
786
961
|
"sectionNavは編集内ナビ(アンカー/ステップ)のみ。PCでサイド表示・SPで非表示",
|
|
962
|
+
"地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き",
|
|
787
963
|
"a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
|
|
788
964
|
]
|
|
789
965
|
},
|
|
@@ -799,6 +975,7 @@
|
|
|
799
975
|
"グローバルナビ・BottomTabBar・パンくずを持たない(構造的に置けない)。離脱を誘う導線を出さず購入に集中させる",
|
|
800
976
|
"bottomAction(StickyActionBar 等)を渡すと本文の下余白はシェルが管理する。ページ側で pb を書かない(付け忘れ/二重がけの構造的防止)",
|
|
801
977
|
"左右 padding は持たない(Container の責務)。管理画面の複雑な集中編集は WorkspaceShell を使う(EC 購入導線=FunnelShell)",
|
|
978
|
+
"地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き",
|
|
802
979
|
"a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
|
|
803
980
|
]
|
|
804
981
|
},
|
|
@@ -825,6 +1002,7 @@
|
|
|
825
1002
|
"rules": [
|
|
826
1003
|
"管理画面向けサイドナビの汎用枠。PC は左端固定アイコンレール(ホバーでサブメニュー)、SP は制御ドロワー(サブメニューはアコーディオン)",
|
|
827
1004
|
"項目データ(メニュー定義・文言)は全て items prop で受ける。特定事業のメニューを部品側に焼き込まない(Cake.jp 既定は AdminShell が持つ)",
|
|
1005
|
+
"PC レールのラベルは max-w-12 + typo-label-xs + 中央揃えを本体が所有する。5文字超も語のまとまりで折り返せるため、consumer が data-slot セレクタで内部上書きしない",
|
|
828
1006
|
"SP ドロワー開閉は open / onOpenChange で制御する(内部 state を持たない)",
|
|
829
1007
|
"icon は ReactNode か描画コンテキスト(active / placement)で出し分ける関数を渡す"
|
|
830
1008
|
]
|
|
@@ -844,14 +1022,23 @@
|
|
|
844
1022
|
"name": "AdminShell",
|
|
845
1023
|
"path": "src/components/ec/admin-shell.tsx",
|
|
846
1024
|
"kind": "shell",
|
|
1025
|
+
"deprecatedAliases": [
|
|
1026
|
+
"AdminLayout"
|
|
1027
|
+
],
|
|
1028
|
+
"subcomponents": [
|
|
1029
|
+
"MissingComponent"
|
|
1030
|
+
],
|
|
847
1031
|
"rules": [
|
|
848
1032
|
"管理画面のレイアウトシェル。枠は primitives の AdminSideNav / AdminHeader を組み込む",
|
|
849
1033
|
"Cake.jp 管理メニュー8項目+サブメニュー・通知ベル・プロフィール・『{shopName}管理』を既定値として同梱する(ec 層)",
|
|
850
1034
|
"navItems で既定メニューを差し替え可、headerActions でヘッダー右アクションを差し替え可",
|
|
1035
|
+
"⚠️ PC の左サイドナビは 72px のアイコンレール(アイコン+短ラベル、サブメニューは hover ポップアップ)。バッジ+見出し+説明文のようなブランドブロックをレール上部に置く領域は無い。幅広サイドバー前提の画面はこの骨格では置き換えられない",
|
|
1036
|
+
"他ブランドで使う場合、ヘッダー左のブランド表示は brand(ReactNode。既定=『{shopName}管理』の文字列)で差し替える。SP ドロワー上部の見出しは sidebarHeader(ReactNode。既定=shopName)で差し替える",
|
|
851
1037
|
"戻る導線(onBack)はパンくずの上に置く。onBack を渡すとシェルが main 内・パンくずより上に戻るボタンを描画する(backLabel で文言変更・既定『戻る』)。子コンテンツ内に戻るリンクを手書きしない",
|
|
852
1038
|
"タイトル直下の上位アクション(AI商品作成・PDF出力等)は h1 と同じ左端に左寄せする。右端フロートにしない",
|
|
853
1039
|
"既定値は props で差し替え可能で、骨格(Header + SideNav + Main)自体は他事業(ジョブボードの管理画面等)でも再利用できる",
|
|
854
|
-
"a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
|
|
1040
|
+
"a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化",
|
|
1041
|
+
"地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き"
|
|
855
1042
|
]
|
|
856
1043
|
},
|
|
857
1044
|
{
|
|
@@ -923,8 +1110,11 @@
|
|
|
923
1110
|
"path": "src/components/ec/order-summary.tsx"
|
|
924
1111
|
},
|
|
925
1112
|
{
|
|
926
|
-
"name": "
|
|
927
|
-
"path": "src/components/ec/payment-method.tsx"
|
|
1113
|
+
"name": "PaymentMethodDisplay",
|
|
1114
|
+
"path": "src/components/ec/payment-method.tsx",
|
|
1115
|
+
"subcomponents": [
|
|
1116
|
+
"CreditCardIcon"
|
|
1117
|
+
]
|
|
928
1118
|
},
|
|
929
1119
|
{
|
|
930
1120
|
"name": "ProductCard",
|
|
@@ -970,6 +1160,13 @@
|
|
|
970
1160
|
{
|
|
971
1161
|
"name": "ProductOption",
|
|
972
1162
|
"path": "src/components/ec/product-option.tsx",
|
|
1163
|
+
"formBinding": "layout",
|
|
1164
|
+
"subcomponents": [
|
|
1165
|
+
"OptionQuantity",
|
|
1166
|
+
"OptionSelect",
|
|
1167
|
+
"OptionText",
|
|
1168
|
+
"OptionImageUpload"
|
|
1169
|
+
],
|
|
973
1170
|
"variants": [
|
|
974
1171
|
"quantity",
|
|
975
1172
|
"select",
|
|
@@ -983,6 +1180,9 @@
|
|
|
983
1180
|
{
|
|
984
1181
|
"name": "RatingStars",
|
|
985
1182
|
"path": "src/components/ec/rating-stars.tsx",
|
|
1183
|
+
"subcomponents": [
|
|
1184
|
+
"SparkleIcon"
|
|
1185
|
+
],
|
|
986
1186
|
"features": [
|
|
987
1187
|
"sparkle-icon",
|
|
988
1188
|
"review-count"
|
|
@@ -1004,6 +1204,7 @@
|
|
|
1004
1204
|
{
|
|
1005
1205
|
"name": "ReviewForm",
|
|
1006
1206
|
"path": "src/components/ec/review-form.tsx",
|
|
1207
|
+
"formBinding": "none",
|
|
1007
1208
|
"features": [
|
|
1008
1209
|
"rating",
|
|
1009
1210
|
"text",
|
|
@@ -1013,6 +1214,9 @@
|
|
|
1013
1214
|
{
|
|
1014
1215
|
"name": "ReviewSummary",
|
|
1015
1216
|
"path": "src/components/ec/review-summary.tsx",
|
|
1217
|
+
"subcomponents": [
|
|
1218
|
+
"ReviewItem"
|
|
1219
|
+
],
|
|
1016
1220
|
"features": [
|
|
1017
1221
|
"average-score",
|
|
1018
1222
|
"star-gauge"
|
|
@@ -122,7 +122,8 @@
|
|
|
122
122
|
{ "depth": 2, "token": "--Surface-Secondary", "hex": "#FBF9F8", "usage": "ネストしたセクション・交互行" },
|
|
123
123
|
{ "depth": 3, "token": "--Surface-Tertiary", "hex": "#F4F2F1", "usage": "抑えたコンテナ・無効領域" }
|
|
124
124
|
],
|
|
125
|
-
"rule": "ネストは3層まで。4層目以降は情報設計を見直す。背景は Surface トークンで明示(未指定で親を透かさない)。"
|
|
125
|
+
"rule": "ネストは3層まで。4層目以降は情報設計を見直す。背景は Surface トークンで明示(未指定で親を透かさない)。",
|
|
126
|
+
"surfaceContext": "色地 Section(background='subtle'|'accent-subtle')と、地が Surface-Secondary のシェル(AdminShell / WorkspaceShell / FunnelShell)は配下に --card-surface: var(--Surface-Primary) を流すため、その中の Card は surface 未指定でも白(depth 1)になる。DS の Section を使わない自前の色地では、親要素に className='[--card-surface:var(--Surface-Primary)]' を宣言して同じ文脈を作る。dark は伝播値を Surface-Secondary に据え置く(半透明白が地に重なって浮くため、白を強制すると elevation が反転する)。"
|
|
126
127
|
},
|
|
127
128
|
"textHierarchy": {
|
|
128
129
|
"description": "typo-* とテキスト強調トークンの組み合わせで階層を作るツリー。上ほど強い階層。トークン名は tokens.json の typography.* / semantic.text.* に対応。",
|
|
@@ -137,17 +138,19 @@
|
|
|
137
138
|
"accentNote": "価格などの最強調は typo-label-lg + --Text-Accent-Primary(オレンジ)。強調は色ではなく typo 系(heading/label)で表現し、font-bold を足さない。"
|
|
138
139
|
},
|
|
139
140
|
"ctaHierarchy": {
|
|
140
|
-
"description": "Button の variant 優先順位。1ビューポート内での CTA
|
|
141
|
+
"description": "Button の variant 優先順位。1ビューポート内での CTA 密度を制御する。⚠️ これは「前進アクションの強さ」の序列であり、画面に並べた2番目のボタンが自動的に secondary になるわけではない。戻る/キャンセル/閉じるのような後退・中立アクションは序列ではなく役割で選ぶ(→ tertiary)。選ぶ前に各項目の appearance(実際の意匠)を必ず確認すること。",
|
|
141
142
|
"priority": [
|
|
142
|
-
{ "variant": "default", "role": "Primary CTA
|
|
143
|
-
{ "variant": "secondary", "role": "Secondary action" },
|
|
144
|
-
{ "variant": "tertiary", "role": "Tertiary action" },
|
|
145
|
-
{ "variant": "ghost", "role": "Minimal action(メニュー・ツールバー内)" },
|
|
146
|
-
{ "variant": "link", "role": "Inline link" }
|
|
143
|
+
{ "variant": "default", "role": "Primary CTA(前進・確定)", "appearance": "ブランドオレンジのベタ塗り", "note": "1ビューポートに1つまで(唯一の主 CTA)" },
|
|
144
|
+
{ "variant": "secondary", "role": "Secondary action(前進系の副 CTA。例: 「サンプルを見る」「詳細を見る」)", "appearance": "⚠️ ブランドアクセント(Surface-Accent-Primary-Light 地 + Brand-Cake-Orange 文字)。Material / Bootstrap / shadcn の secondary(グレー・控えめ)とは別物", "note": "アクセント色が付くため、戻る・キャンセル・閉じる等の後退/中立アクションには使わない(→ tertiary)" },
|
|
145
|
+
{ "variant": "tertiary", "role": "Tertiary action / 後退・中立アクション(戻る・キャンセル・閉じる・スキップ・あとで)", "appearance": "ニュートラルなグレー(Surface-Tertiary 地 + Text-High-Emphasis 文字)", "note": "他 DS の secondary に相当する見た目。主 CTA の隣に置く「戻る」「キャンセル」はこれを使う" },
|
|
146
|
+
{ "variant": "ghost", "role": "Minimal action(メニュー・ツールバー内)", "appearance": "下地なし・hover で薄い下地" },
|
|
147
|
+
{ "variant": "link", "role": "Inline link", "appearance": "テキストリンク意匠" }
|
|
147
148
|
],
|
|
148
149
|
"rules": [
|
|
149
150
|
"default(オレンジ)の CTA は1ビューポートに1つまで。主アクションを1つに絞る",
|
|
150
151
|
"複数アクションを並べる時は default を tertiary / ghost と組み合わせる",
|
|
152
|
+
"「戻る」「キャンセル」「閉じる」「スキップ」「あとで」は tertiary(グレー)。secondary はアクセント色なので後退アクションに使わない",
|
|
153
|
+
"secondary を使うのは、主 CTA と別方向の“前進”を促す副 CTA のとき(例: 主=「購入する」に対し副=「サンプルを見る」)",
|
|
151
154
|
"モバイルの全幅下部 CTA は size=\"xl\" + w-full(StickyActionBar 内)"
|
|
152
155
|
]
|
|
153
156
|
}
|