@cakejp/design-system 0.13.0 → 0.14.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.
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "meta": {
3
3
  "name": "Cake.jp Design System — Component Contracts",
4
- "version": "0.1.0",
4
+ "version": "0.14.0",
5
5
  "description": "全コンポーネントの構造化定義。バリアント・アクセシビリティ要件・使用ルールを機械可読形式で管理。",
6
6
  "kind": "kind:\"shell\" は複数ページで再利用されるレイアウト枠(AdminShell / WorkspaceShell / MypageShell 等)。無印は部品コンポーネント。固有ページを組むときは該当 shell から始める。src/components/pages/ 配下のストーリーは特定ページ専用・非配布のため contracts の対象外。",
7
+ "naming": "コンポーネント名は**用途ではなく機能**で付ける。用途名(QuantitySelector = カート数量)にすると、同じ機能を別の文脈で探した人が見つけられず二重実装が生まれる(実例: 用途名だったため NumberInput が別途作られ、意匠の違うステッパーが 2 つになった)。「〜Selector」「〜Picker」等の用途接尾辞を付ける前に、その部品が何をするものかで名前が付けられないかを先に検討する。既存名を機能名へ変える場合は deprecatedAliases に旧名を残す。",
7
8
  "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
9
  "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)。",
9
10
  "counts": {
10
- "foundations": 50,
11
- "primitives": 47,
11
+ "foundations": 51,
12
+ "primitives": 49,
12
13
  "ec": 24,
13
- "total": 121,
14
+ "total": 124,
14
15
  "note": "counts は各ティアの実装ファイル数(scripts/check-drift.sh が src/components/<tier>/*.tsx と突き合わせる)。subcomponents / deprecatedAliases は含まない。"
15
16
  }
16
17
  },
@@ -19,13 +20,6 @@
19
20
  "name": "Accordion",
20
21
  "path": "src/components/foundations/accordion.tsx"
21
22
  },
22
- {
23
- "name": "AlertDialog",
24
- "path": "src/components/foundations/alert-dialog.tsx",
25
- "rules": [
26
- "破壊的操作の確認に使用。削除ボタン押下後に必ず挟む"
27
- ]
28
- },
29
23
  {
30
24
  "name": "Alert",
31
25
  "path": "src/components/foundations/alert.tsx",
@@ -47,6 +41,18 @@
47
41
  "inline variant(inline-info/inline-caution/inline-warning)も同じ prop-based API に対応(#109)。フォーム内・セクション内の軽量な補足情報用。アイコンは20pxで自動選択"
48
42
  ]
49
43
  },
44
+ {
45
+ "name": "AlertDialog",
46
+ "path": "src/components/foundations/alert-dialog.tsx",
47
+ "sizes": [
48
+ "default",
49
+ "sm"
50
+ ],
51
+ "rules": [
52
+ "破壊的操作の確認に使用。削除ボタン押下後に必ず挟む",
53
+ "幅上限は default=480px / sm=320px。SP では画面端から上下左右 40px の余白を保つ(コンポーネントが持つので consumer 側で margin を足さない)"
54
+ ]
55
+ },
50
56
  {
51
57
  "name": "AspectRatio",
52
58
  "path": "src/components/foundations/aspect-ratio.tsx",
@@ -107,7 +113,7 @@
107
113
  ],
108
114
  "rules": [
109
115
  "<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 なので、入力行にボタンを並置しても揃う",
116
+ "高さは size='default'=44px(h-11) / xs=24px / sm=32px / lg=48px / xl=56px / hero=min 56px。default はフォーム入力コントロール(Input / SelectTrigger default / DatePicker trigger)と同じ 44px なので、入力行にボタンを並置しても揃う",
111
117
  "⚠️ variant='secondary' はブランドアクセント意匠(Surface-Accent-Primary-Light地+Brand-Cake-Orange文字)。Material/Bootstrap/shadcn の secondary(グレー・控えめ)とは別物なので、他DSの感覚で選ばない",
112
118
  "「戻る」「キャンセル」「閉じる」「スキップ」「あとで」等の後退・中立アクションは variant='tertiary'(Surface-Tertiary地+Text-High-Emphasis文字のニュートラルなグレー)を使う。主CTAの隣に置く2番目のボタンでも、役割が後退なら secondary ではなく tertiary",
113
119
  "variant='secondary' を使うのは、主CTAと別方向の“前進”を促す副CTAのとき(例: 主='購入する' に対し 副='サンプルを見る')",
@@ -145,6 +151,14 @@
145
151
  "DSのSectionを使わない自前のグレー地では、親要素に className='[--card-surface:var(--Surface-Primary)]' を宣言すれば配下Cardが白になる(darkにも配慮するなら dark:[--card-surface:var(--Surface-Secondary)] を併記)。1枚だけ地に馴染ませたいときは className='bg-card' で上書きする"
146
152
  ]
147
153
  },
154
+ {
155
+ "name": "Checkbox",
156
+ "path": "src/components/foundations/checkbox.tsx",
157
+ "formBinding": "controller",
158
+ "accessibility": [
159
+ "必ずLabelと紐付ける"
160
+ ]
161
+ },
148
162
  {
149
163
  "name": "CheckboxCard",
150
164
  "path": "src/components/foundations/checkbox-card.tsx",
@@ -163,14 +177,6 @@
163
177
  "CheckboxGroupItem"
164
178
  ]
165
179
  },
166
- {
167
- "name": "Checkbox",
168
- "path": "src/components/foundations/checkbox.tsx",
169
- "formBinding": "controller",
170
- "accessibility": [
171
- "必ずLabelと紐付ける"
172
- ]
173
- },
174
180
  {
175
181
  "name": "Collapsible",
176
182
  "path": "src/components/foundations/collapsible.tsx",
@@ -240,6 +246,23 @@
240
246
  "見出しは FieldLegend、グループ横断の区切りは FieldSeparator を使う"
241
247
  ]
242
248
  },
249
+ {
250
+ "name": "FileInput",
251
+ "path": "src/components/foundations/file-input.tsx",
252
+ "formBinding": "controller",
253
+ "accessibility": [
254
+ "idをLabel/FormFieldのhtmlForと揃えて紐付ける",
255
+ "ネイティブ<input type='file'>をvisually-hiddenで内包しキーボード・SR操作可能",
256
+ "エラー表示はaria-describedbyでFieldErrorと接続"
257
+ ],
258
+ "rules": [
259
+ "<input type='file'>を直接書かない。汎用の添付(PDF/CSV/画像混在)はFileInputを使う",
260
+ "画像1枚の入力(プレビュー+形式/サイズ検証+値のバインド)はImageInputを使う",
261
+ "複数枚の画像を並べて管理するグリッドはImageUploaderを使う",
262
+ "複数選択時(multiple)は選択済みを「n件選択」で集約表示",
263
+ "maxSize(バイト)超過ファイルは受理せずonErrorを呼ぶ"
264
+ ]
265
+ },
243
266
  {
244
267
  "name": "Form",
245
268
  "path": "src/components/foundations/form.tsx",
@@ -348,23 +371,6 @@
348
371
  "variant='chip'=ラベルを内包したChoice Chip意匠の排他選択(タグ選択・絞り込み等)。ラジオ丸は描画せず、Chip本体と同じchipVariantsを再利用して選択状態をaccent意匠(静止=薄オレンジ/hover=ベタ塗り)で示す。description/expandedContentは持たない。Radixのキーボード操作・a11yは維持"
349
372
  ]
350
373
  },
351
- {
352
- "name": "FileInput",
353
- "path": "src/components/foundations/file-input.tsx",
354
- "formBinding": "controller",
355
- "accessibility": [
356
- "idをLabel/FormFieldのhtmlForと揃えて紐付ける",
357
- "ネイティブ<input type='file'>をvisually-hiddenで内包しキーボード・SR操作可能",
358
- "エラー表示はaria-describedbyでFieldErrorと接続"
359
- ],
360
- "rules": [
361
- "<input type='file'>を直接書かない。汎用の添付(PDF/CSV/画像混在)はFileInputを使う",
362
- "画像1枚の入力(プレビュー+形式/サイズ検証+値のバインド)はImageInputを使う",
363
- "複数枚の画像を並べて管理するグリッドはImageUploaderを使う",
364
- "複数選択時(multiple)は選択済みを「n件選択」で集約表示",
365
- "maxSize(バイト)超過ファイルは受理せずonErrorを呼ぶ"
366
- ]
367
- },
368
374
  {
369
375
  "name": "ResponsiveDialog",
370
376
  "path": "src/components/foundations/responsive-dialog.tsx",
@@ -429,11 +435,18 @@
429
435
  "formBinding": "controller"
430
436
  },
431
437
  {
432
- "name": "Toaster",
433
- "path": "src/components/foundations/sonner.tsx",
438
+ "name": "SocialIcon",
439
+ "path": "src/components/foundations/social-icon.tsx",
440
+ "props": [
441
+ "platform",
442
+ "tone?: brand | mono",
443
+ "size?: number"
444
+ ],
434
445
  "rules": [
435
- "トースト内にアクションリンクを入れない。左ボーダーではなく背景色全体で状態を表現",
436
- "アプリのルートに <Toaster /> を1つ置き、表示は toast()(sonner の再 export)で呼ぶ"
446
+ "SNS・外部サービスのロゴSVGは手書きせずSocialIconへ集約する",
447
+ "ブランド色はThird-Partyトークンを使う",
448
+ "ブランド色の地(LINEの緑・Appleの黒)に載せるときはtone=\"mono\"を指定する。brandのままだとアイコンが地と同色になって消える",
449
+ "サイズはsize(px)で指定する。classNameのsize-*はinline styleに負ける"
437
450
  ]
438
451
  },
439
452
  {
@@ -477,11 +490,11 @@
477
490
  ]
478
491
  },
479
492
  {
480
- "name": "ToggleGroup",
481
- "path": "src/components/foundations/toggle-group.tsx",
482
- "formBinding": "controller",
493
+ "name": "Toaster",
494
+ "path": "src/components/foundations/sonner.tsx",
483
495
  "rules": [
484
- "水平パディングはコンポーネント内に入れない。親が管理する"
496
+ "トースト内にアクションリンクを入れない。左ボーダーではなく背景色全体で状態を表現",
497
+ "アプリのルートに <Toaster /> を1つ置き、表示は toast()(sonner の再 export)で呼ぶ"
485
498
  ]
486
499
  },
487
500
  {
@@ -489,6 +502,14 @@
489
502
  "path": "src/components/foundations/toggle.tsx",
490
503
  "formBinding": "controller"
491
504
  },
505
+ {
506
+ "name": "ToggleGroup",
507
+ "path": "src/components/foundations/toggle-group.tsx",
508
+ "formBinding": "controller",
509
+ "rules": [
510
+ "水平パディングはコンポーネント内に入れない。親が管理する"
511
+ ]
512
+ },
492
513
  {
493
514
  "name": "Tooltip",
494
515
  "path": "src/components/foundations/tooltip.tsx",
@@ -499,37 +520,30 @@
499
520
  ],
500
521
  "primitives": [
501
522
  {
502
- "name": "CoachMark",
503
- "path": "src/components/primitives/coach-mark.tsx"
504
- },
505
- {
506
- "name": "BannerCarousel",
507
- "path": "src/components/primitives/banner-carousel.tsx"
508
- },
509
- {
510
- "name": "ContentCarousel",
511
- "path": "src/components/primitives/content-carousel.tsx",
512
- "features": [
513
- "scroll-snap",
514
- "dots",
515
- "arrows",
516
- "autoPlay",
517
- "itemsPerView"
518
- ],
523
+ "name": "AdminHeader",
524
+ "path": "src/components/primitives/admin-header.tsx",
519
525
  "rules": [
520
- "ReactNode スライド対応(slides: ReactNode[])。テキスト主体のヒーローバナー用",
521
- "itemsPerView=2|3|4 で PC の複数カード表示に対応。SP は1枚表示を維持し、EC 商品以外の求人・記事カード等にも使う",
522
- "画像だけのバナーは ImageCarousel を使う",
523
- "矢印・ドットの意匠は ImageCarousel と同一"
526
+ "管理画面向けの上端固定ヘッダーの汎用枠。左に SP ハンバーガー+brand、右に actions slot",
527
+ "文言合成(『{shopName}管理』等)はしない。brand / actions を利用側が組み立てて渡す",
528
+ "onMenuClick 省略時はハンバーガー非表示"
524
529
  ]
525
530
  },
526
531
  {
527
- "name": "StickyActionBar",
528
- "path": "src/components/primitives/sticky-action-bar.tsx",
532
+ "name": "AdminSideNav",
533
+ "path": "src/components/primitives/admin-side-nav.tsx",
534
+ "category": "navigation",
529
535
  "rules": [
530
- "モバイル固定フッターCTA"
536
+ "管理画面向けサイドナビの汎用枠。PC は左端固定アイコンレール(ホバーでサブメニュー)、SP は制御ドロワー(サブメニューはアコーディオン)",
537
+ "項目データ(メニュー定義・文言)は全て items prop で受ける。特定事業のメニューを部品側に焼き込まない(Cake.jp 既定は AdminShell が持つ)",
538
+ "PC レールのラベルは max-w-12 + typo-label-xs + 中央揃えを本体が所有する。5文字超も語のまとまりで折り返せるため、consumer が data-slot セレクタで内部上書きしない",
539
+ "SP ドロワー開閉は open / onOpenChange で制御する(内部 state を持たない)",
540
+ "icon は ReactNode か描画コンテキスト(active / placement)で出し分ける関数を渡す"
531
541
  ]
532
542
  },
543
+ {
544
+ "name": "BannerCarousel",
545
+ "path": "src/components/primitives/banner-carousel.tsx"
546
+ },
533
547
  {
534
548
  "name": "BottomTabBar",
535
549
  "path": "src/components/primitives/bottom-tab-bar.tsx",
@@ -544,14 +558,14 @@
544
558
  "テーブル選択時の一括操作バー。div手書き禁止"
545
559
  ]
546
560
  },
547
- {
548
- "name": "CategoryShortcuts",
549
- "path": "src/components/primitives/category-shortcuts.tsx"
550
- },
551
561
  {
552
562
  "name": "CategoryScroll",
553
563
  "path": "src/components/primitives/category-scroll.tsx"
554
564
  },
565
+ {
566
+ "name": "CategoryShortcuts",
567
+ "path": "src/components/primitives/category-shortcuts.tsx"
568
+ },
555
569
  {
556
570
  "name": "ChatComposer",
557
571
  "path": "src/components/primitives/chat-composer.tsx",
@@ -597,6 +611,58 @@
597
611
  "Tagと違い押せる・削除できる"
598
612
  ]
599
613
  },
614
+ {
615
+ "name": "CoachMark",
616
+ "path": "src/components/primitives/coach-mark.tsx"
617
+ },
618
+ {
619
+ "name": "Combobox",
620
+ "path": "src/components/primitives/combobox.tsx",
621
+ "formBinding": "controller",
622
+ "props": [
623
+ "options: ComboboxOption[]",
624
+ "value?: string",
625
+ "onValueChange?: (value: string) => void",
626
+ "id?: string",
627
+ "aria-invalid?: boolean",
628
+ "aria-describedby?: string"
629
+ ],
630
+ "rules": [
631
+ "検索が必要な単一選択に使う。少数候補はSelectまたはRadioGroupを使う",
632
+ "Popover + Command の検索・キーボード操作を内包する",
633
+ "制御コンポーネント。value と onValueChange を必ず渡す(非制御では選択が反映されない)",
634
+ "FormField と繋ぐときは id を FieldLabel の htmlFor と揃え、エラーは aria-invalid / aria-describedby で FieldError に接続する"
635
+ ]
636
+ },
637
+ {
638
+ "name": "Container",
639
+ "path": "src/components/primitives/container.tsx",
640
+ "variants": [
641
+ "size: page | narrow | wide | fluid",
642
+ "gutter: default | tight | none"
643
+ ],
644
+ "rules": [
645
+ "ページ最大幅と左右paddingの唯一の担い手。これを使う親(Section等)は自身で左右paddingを持たない(二重がけ防止)",
646
+ "縦余白・背景色は持たない(Sectionの責務)"
647
+ ]
648
+ },
649
+ {
650
+ "name": "ContentCarousel",
651
+ "path": "src/components/primitives/content-carousel.tsx",
652
+ "features": [
653
+ "scroll-snap",
654
+ "dots",
655
+ "arrows",
656
+ "autoPlay",
657
+ "itemsPerView"
658
+ ],
659
+ "rules": [
660
+ "ReactNode スライド対応(slides: ReactNode[])。テキスト主体のヒーローバナー用",
661
+ "itemsPerView=2|3|4 で PC の複数カード表示に対応。SP は1枚表示を維持し、EC 商品以外の求人・記事カード等にも使う",
662
+ "画像だけのバナーは ImageCarousel を使う",
663
+ "矢印・ドットの意匠は ImageCarousel と同一"
664
+ ]
665
+ },
600
666
  {
601
667
  "name": "DatePicker",
602
668
  "path": "src/components/primitives/date-picker.tsx",
@@ -667,6 +733,38 @@
667
733
  "npm 経由では CakeFormField として import する(foundations/form.tsx の FormField と名前が衝突するため別名で export)"
668
734
  ]
669
735
  },
736
+ {
737
+ "name": "FunnelShell",
738
+ "path": "src/components/primitives/funnel-shell.tsx",
739
+ "kind": "shell",
740
+ "variants": [],
741
+ "rules": [
742
+ "EC 購入導線等のファネル用集中モード(Full Page)のシェル。集中ヘッダー+進捗インジケータ(steps/activeStep)+ステップ本体+任意の bottomAction で構成。min-h-dvh flex flex-col の全高コンテナ",
743
+ "ヘッダーの基本形は中央ロゴ(logo prop → Header variant=logo-center)。ライブ本番の購入導線(cart_layout.ctp の cartHeader)準拠で離脱導線をロゴのみに絞る。狙いは戻り・離脱をしづらくして途中離脱を抑制すること(=Header の logo-center は決済・申込ページ用の既定バリアント、本番 cartHeader もロゴクリックが /cart/・thanks に限定)。title+back(Header variant=back)は多段申込等でタイトル・戻るが要る場合の代替形。logo と title はどちらか一方を渡す(logo 優先)",
744
+ "あくまで枠。ステップ定義(名前・数)・文言・商品データを焼き込まない。steps / activeStep は利用側(ドメイン)が渡す",
745
+ "グローバルナビ・BottomTabBar・パンくずを持たない(構造的に置けない)。離脱を誘う導線を出さず購入に集中させる",
746
+ "bottomAction(StickyActionBar 等)を渡すと本文の下余白はシェルが管理する。ページ側で pb を書かない(付け忘れ/二重がけの構造的防止)",
747
+ "左右 padding は持たない(Container の責務)。管理画面の複雑な集中編集は WorkspaceShell を使う(EC 購入導線=FunnelShell)",
748
+ "地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き",
749
+ "a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
750
+ ]
751
+ },
752
+ {
753
+ "name": "Header",
754
+ "path": "src/components/primitives/header.tsx",
755
+ "variants": [
756
+ "logo",
757
+ "logo-center",
758
+ "back",
759
+ "back-search"
760
+ ],
761
+ "rules": [
762
+ "variant=\"logo\" の PC 行(@[768px]+)では searchSlot で navItems と actions の間に常設検索を inline 配置できる(flex-1 max-w-[400px] で伸縮)。navItems 無し+searchSlot だけでも PC 行を描画する",
763
+ "SP 行に searchSlot は出さない。SP の常設検索は従来どおり bottomSlot で運用する",
764
+ "bottomSlot はヘッダー下段の全幅スロット(ProductDetailBar 等)。PC 常設検索の置き場に使わない(PC 二段ヘッダーになる)",
765
+ "actions(HeaderAction)はカート・マイページ等の本来リンクである導線には href を指定する。href 指定時は Button asChild + <a> で描画され、中クリック/新規タブ・リンクコピーが効く。onClick と併用可(両方付与される)"
766
+ ]
767
+ },
670
768
  {
671
769
  "name": "ImageCarousel",
672
770
  "path": "src/components/primitives/image-carousel.tsx",
@@ -756,8 +854,23 @@
756
854
  "path": "src/components/primitives/menu-drawer.tsx"
757
855
  },
758
856
  {
759
- "name": "SubNav",
760
- "path": "src/components/primitives/sub-nav.tsx"
857
+ "name": "MultiSelect",
858
+ "path": "src/components/primitives/multi-select.tsx",
859
+ "formBinding": "controller",
860
+ "props": [
861
+ "options: MultiSelectOption[]",
862
+ "value?: string[]",
863
+ "onValueChange?: (value: string[]) => void",
864
+ "id?: string",
865
+ "aria-invalid?: boolean",
866
+ "aria-describedby?: string"
867
+ ],
868
+ "rules": [
869
+ "3件以上を複数選択させる、または候補が多い場合に使う。少数候補はCheckboxGroupを使う",
870
+ "選択済みは削除可能なChipで表示する",
871
+ "制御コンポーネント。value と onValueChange を必ず渡す(非制御では選択が反映されない)",
872
+ "FormField と繋ぐときは id を FieldLabel の htmlFor と揃え、エラーは aria-invalid / aria-describedby で FieldError に接続する"
873
+ ]
761
874
  },
762
875
  {
763
876
  "name": "NotificationBadge",
@@ -791,27 +904,45 @@
791
904
  "path": "src/components/primitives/progress-steps.tsx"
792
905
  },
793
906
  {
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
- },
807
- {
808
- "name": "QuantitySelector",
809
- "path": "src/components/primitives/quantity-selector.tsx",
907
+ "name": "NumberInput",
908
+ "path": "src/components/primitives/number-input.tsx",
810
909
  "formBinding": "controller",
910
+ "deprecatedAliases": [
911
+ "QuantitySelector"
912
+ ],
811
913
  "features": [
812
914
  "increment",
813
915
  "decrement",
814
- "trash-icon"
916
+ "trash-icon",
917
+ "number-format"
918
+ ],
919
+ "sizes": [
920
+ "sm",
921
+ "md"
922
+ ],
923
+ "props": [
924
+ "value?: number",
925
+ "defaultValue?: number",
926
+ "onChange?: (value: number) => void",
927
+ "min?: number",
928
+ "max?: number",
929
+ "step?: number",
930
+ "size?: sm | md",
931
+ "editable?: boolean",
932
+ "error?: boolean",
933
+ "showTrash?: boolean",
934
+ "onDelete?: () => void",
935
+ "formatOptions?: Intl.NumberFormatOptions",
936
+ "locale?: string",
937
+ "inputId?: string"
938
+ ],
939
+ "rules": [
940
+ "DSの数値入力はすべてこれを使う。生の input type=\"number\" は使わない(カート数量・価格・在庫・ポイント等すべて)",
941
+ "意匠は Figma DS の Adjust 準拠。sm=コンパクト型(カート内)/ md=サークル型(商品詳細・管理画面)。この2つ以外の見た目を新規に作らない",
942
+ "カート数量では min=1 が標準(0 にしない — 削除は showTrash + onDelete で行う)",
943
+ "既定は min=1 / max=99 とカート数量向け。価格・在庫など汎用の数値入力では min / max / step を必ず明示する",
944
+ "桁区切り・通貨表示は formatOptions を渡す(編集中は素の数値になる)。JPY の全角¥は半角¥に正規化される",
945
+ "旧名 QuantitySelector は用途名だったため機能名に改名した。旧名は deprecated alias として残るが新規利用は不可"
815
946
  ]
816
947
  },
817
948
  {
@@ -827,18 +958,6 @@
827
958
  "flex"
828
959
  ]
829
960
  },
830
- {
831
- "name": "Container",
832
- "path": "src/components/primitives/container.tsx",
833
- "variants": [
834
- "size: page | narrow | wide | fluid",
835
- "gutter: default | tight | none"
836
- ],
837
- "rules": [
838
- "ページ最大幅と左右paddingの唯一の担い手。これを使う親(Section等)は自身で左右paddingを持たない(二重がけ防止)",
839
- "縦余白・背景色は持たない(Sectionの責務)"
840
- ]
841
- },
842
961
  {
843
962
  "name": "Section",
844
963
  "path": "src/components/primitives/section.tsx",
@@ -872,38 +991,6 @@
872
991
  "3xl(28px)は通常ページの主見出しにも使う。4xl/5xlはLP・マーケティング系ヒーロー専用で、size=\"3xl\" に desktopSize=\"4xl\" または desktopSize=\"5xl\" を加えてPC時だけ拡大する"
873
992
  ]
874
993
  },
875
- {
876
- "name": "ShareButtons",
877
- "path": "src/components/primitives/share-buttons.tsx"
878
- },
879
- {
880
- "name": "SocialLoginButton",
881
- "path": "src/components/primitives/social-login-button.tsx"
882
- },
883
- {
884
- "name": "StatusCountTabs",
885
- "path": "src/components/primitives/status-count-tabs.tsx",
886
- "rules": [
887
- "ToggleGroup+Badge手書き禁止。Chip count propを使う",
888
- "activeIndex は初期値だけでなく、マウント後の外部変更にも表示が追従する"
889
- ]
890
- },
891
- {
892
- "name": "Tag",
893
- "path": "src/components/primitives/tag.tsx",
894
- "rules": [
895
- "表示専用。onClickを付けない(押せるものはChip)"
896
- ]
897
- },
898
- {
899
- "name": "SideNav",
900
- "path": "src/components/primitives/side-nav.tsx",
901
- "category": "navigation",
902
- "rules": [
903
- "ページ間遷移(別 URL へのナビゲーション)に使う。チェブロン付きで「別ページへ移動する」アフォーダンスを持つ",
904
- "ページ内アンカー移動(href=\"#...\")に流用しない → SectionNav を使う(見た目と挙動の不一致を防ぐ)"
905
- ]
906
- },
907
994
  {
908
995
  "name": "SectionNav",
909
996
  "path": "src/components/primitives/section-nav.tsx",
@@ -923,6 +1010,23 @@
923
1010
  "IntersectionObserver は内包しない。activeKey は利用側が制御する(AnchorNav の新設は却下、本コンポーネントの variant で担う)"
924
1011
  ]
925
1012
  },
1013
+ {
1014
+ "name": "ShareButtons",
1015
+ "path": "src/components/primitives/share-buttons.tsx"
1016
+ },
1017
+ {
1018
+ "name": "SideNav",
1019
+ "path": "src/components/primitives/side-nav.tsx",
1020
+ "category": "navigation",
1021
+ "rules": [
1022
+ "ページ間遷移(別 URL へのナビゲーション)に使う。チェブロン付きで「別ページへ移動する」アフォーダンスを持つ",
1023
+ "ページ内アンカー移動(href=\"#...\")に流用しない → SectionNav を使う(見た目と挙動の不一致を防ぐ)"
1024
+ ]
1025
+ },
1026
+ {
1027
+ "name": "SocialLoginButton",
1028
+ "path": "src/components/primitives/social-login-button.tsx"
1029
+ },
926
1030
  {
927
1031
  "name": "StandardPageShell",
928
1032
  "path": "src/components/primitives/standard-page-shell.tsx",
@@ -941,6 +1045,46 @@
941
1045
  "a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content、SkipLink の飛び先と一致)。sr-only で視覚無影響。skipLink={false} で無効化。ページ側で手組みしない"
942
1046
  ]
943
1047
  },
1048
+ {
1049
+ "name": "StatusCountTabs",
1050
+ "path": "src/components/primitives/status-count-tabs.tsx",
1051
+ "rules": [
1052
+ "ToggleGroup+Badge手書き禁止。Chip count propを使う",
1053
+ "activeIndex は初期値だけでなく、マウント後の外部変更にも表示が追従する"
1054
+ ]
1055
+ },
1056
+ {
1057
+ "name": "StickyActionBar",
1058
+ "path": "src/components/primitives/sticky-action-bar.tsx",
1059
+ "rules": [
1060
+ "モバイル固定フッターCTA"
1061
+ ]
1062
+ },
1063
+ {
1064
+ "name": "SubNav",
1065
+ "path": "src/components/primitives/sub-nav.tsx"
1066
+ },
1067
+ {
1068
+ "name": "Tag",
1069
+ "path": "src/components/primitives/tag.tsx",
1070
+ "rules": [
1071
+ "表示専用。onClickを付けない(押せるものはChip)"
1072
+ ]
1073
+ },
1074
+ {
1075
+ "name": "Timeline",
1076
+ "path": "src/components/primitives/timeline.tsx",
1077
+ "features": [
1078
+ "vertical",
1079
+ "custom-marker",
1080
+ "connector"
1081
+ ],
1082
+ "rules": [
1083
+ "本文付きの縦タイムラインに使う。現在位置を示す横型インジケータは ProgressSteps を使う",
1084
+ "marker 省略時は連番。IconBadge 等の ReactNode を渡せる",
1085
+ "コネクター線は Timeline が所有するため consumer が ::before / ::after で手組みしない"
1086
+ ]
1087
+ },
944
1088
  {
945
1089
  "name": "WorkspaceShell",
946
1090
  "path": "src/components/primitives/workspace-shell.tsx",
@@ -962,59 +1106,6 @@
962
1106
  "地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き",
963
1107
  "a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
964
1108
  ]
965
- },
966
- {
967
- "name": "FunnelShell",
968
- "path": "src/components/primitives/funnel-shell.tsx",
969
- "kind": "shell",
970
- "variants": [],
971
- "rules": [
972
- "EC 購入導線等のファネル用集中モード(Full Page)のシェル。集中ヘッダー+進捗インジケータ(steps/activeStep)+ステップ本体+任意の bottomAction で構成。min-h-dvh flex flex-col の全高コンテナ",
973
- "ヘッダーの基本形は中央ロゴ(logo prop → Header variant=logo-center)。ライブ本番の購入導線(cart_layout.ctp の cartHeader)準拠で離脱導線をロゴのみに絞る。狙いは戻り・離脱をしづらくして途中離脱を抑制すること(=Header の logo-center は決済・申込ページ用の既定バリアント、本番 cartHeader もロゴクリックが /cart/・thanks に限定)。title+back(Header variant=back)は多段申込等でタイトル・戻るが要る場合の代替形。logo と title はどちらか一方を渡す(logo 優先)",
974
- "あくまで枠。ステップ定義(名前・数)・文言・商品データを焼き込まない。steps / activeStep は利用側(ドメイン)が渡す",
975
- "グローバルナビ・BottomTabBar・パンくずを持たない(構造的に置けない)。離脱を誘う導線を出さず購入に集中させる",
976
- "bottomAction(StickyActionBar 等)を渡すと本文の下余白はシェルが管理する。ページ側で pb を書かない(付け忘れ/二重がけの構造的防止)",
977
- "左右 padding は持たない(Container の責務)。管理画面の複雑な集中編集は WorkspaceShell を使う(EC 購入導線=FunnelShell)",
978
- "地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き",
979
- "a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
980
- ]
981
- },
982
- {
983
- "name": "Header",
984
- "path": "src/components/primitives/header.tsx",
985
- "variants": [
986
- "logo",
987
- "logo-center",
988
- "back",
989
- "back-search"
990
- ],
991
- "rules": [
992
- "variant=\"logo\" の PC 行(@[768px]+)では searchSlot で navItems と actions の間に常設検索を inline 配置できる(flex-1 max-w-[400px] で伸縮)。navItems 無し+searchSlot だけでも PC 行を描画する",
993
- "SP 行に searchSlot は出さない。SP の常設検索は従来どおり bottomSlot で運用する",
994
- "bottomSlot はヘッダー下段の全幅スロット(ProductDetailBar 等)。PC 常設検索の置き場に使わない(PC 二段ヘッダーになる)",
995
- "actions(HeaderAction)はカート・マイページ等の本来リンクである導線には href を指定する。href 指定時は Button asChild + <a> で描画され、中クリック/新規タブ・リンクコピーが効く。onClick と併用可(両方付与される)"
996
- ]
997
- },
998
- {
999
- "name": "AdminSideNav",
1000
- "path": "src/components/primitives/admin-side-nav.tsx",
1001
- "category": "navigation",
1002
- "rules": [
1003
- "管理画面向けサイドナビの汎用枠。PC は左端固定アイコンレール(ホバーでサブメニュー)、SP は制御ドロワー(サブメニューはアコーディオン)",
1004
- "項目データ(メニュー定義・文言)は全て items prop で受ける。特定事業のメニューを部品側に焼き込まない(Cake.jp 既定は AdminShell が持つ)",
1005
- "PC レールのラベルは max-w-12 + typo-label-xs + 中央揃えを本体が所有する。5文字超も語のまとまりで折り返せるため、consumer が data-slot セレクタで内部上書きしない",
1006
- "SP ドロワー開閉は open / onOpenChange で制御する(内部 state を持たない)",
1007
- "icon は ReactNode か描画コンテキスト(active / placement)で出し分ける関数を渡す"
1008
- ]
1009
- },
1010
- {
1011
- "name": "AdminHeader",
1012
- "path": "src/components/primitives/admin-header.tsx",
1013
- "rules": [
1014
- "管理画面向けの上端固定ヘッダーの汎用枠。左に SP ハンバーガー+brand、右に actions slot",
1015
- "文言合成(『{shopName}管理』等)はしない。brand / actions を利用側が組み立てて渡す",
1016
- "onMenuClick 省略時はハンバーガー非表示"
1017
- ]
1018
1109
  }
1019
1110
  ],
1020
1111
  "ec": [
@@ -1041,28 +1132,6 @@
1041
1132
  "地がSurface-Secondaryなので、シェルが配下Cardのサーフェス文脈(--card-surface: Surface-Primary)を宣言する → Cardはsurface未指定のまま白で地から浮く(#150)。darkは据え置き"
1042
1133
  ]
1043
1134
  },
1044
- {
1045
- "name": "MypageShell",
1046
- "path": "src/components/ec/mypage-shell.tsx",
1047
- "kind": "shell",
1048
- "variants": [],
1049
- "features": [
1050
- "sp-header-back",
1051
- "pc-logo-header",
1052
- "pc-breadcrumb",
1053
- "pc-2column-sidenav",
1054
- "sp-bottom-tab-bar"
1055
- ],
1056
- "rules": [
1057
- "マイページ配下の固有ページ(注文履歴 / ポイント / クーポン / 会員情報 / お届け先 / ブックマーク / 口コミ / 記念日 等)はこの shell で組む",
1058
- "本番の mypage_layout.ctp + menu.ctp 準拠。SP は Header(variant=back)+h1+コンテンツ+BottomTabBar、PC は Header(variant=logo)+Breadcrumb+2カラム(SideNav 256px + main)",
1059
- "サイドナビは既定で ec/_mypage-menu-data の mypageMenuGroups を使用。activeMenu で現在ページを強調する",
1060
- "既定値は props で差し替え可能(menuGroups / breadcrumbs / bottomNavItems / headerActions)で、骨格(ヘッダー+2カラム+BottomTabBar)自体は他事業(ジョブボードのマイページ等)でも再利用できる",
1061
- "breadcrumbs 省略時は「ホーム > {ユーザー}さまのマイページ > {title}」を自動生成する",
1062
- "マイページトップ(Dashboard)はメインカラムを白背景で持たずセクションごとにカード化する別パターンなので、この shell を使わない",
1063
- "a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
1064
- ]
1065
- },
1066
1135
  {
1067
1136
  "name": "AnniversaryCard",
1068
1137
  "path": "src/components/ec/anniversary-card.tsx"
@@ -1096,6 +1165,28 @@
1096
1165
  "name": "DeliveryCalendar",
1097
1166
  "path": "src/components/ec/delivery-calendar.tsx"
1098
1167
  },
1168
+ {
1169
+ "name": "MypageShell",
1170
+ "path": "src/components/ec/mypage-shell.tsx",
1171
+ "kind": "shell",
1172
+ "variants": [],
1173
+ "features": [
1174
+ "sp-header-back",
1175
+ "pc-logo-header",
1176
+ "pc-breadcrumb",
1177
+ "pc-2column-sidenav",
1178
+ "sp-bottom-tab-bar"
1179
+ ],
1180
+ "rules": [
1181
+ "マイページ配下の固有ページ(注文履歴 / ポイント / クーポン / 会員情報 / お届け先 / ブックマーク / 口コミ / 記念日 等)はこの shell で組む",
1182
+ "本番の mypage_layout.ctp + menu.ctp 準拠。SP は Header(variant=back)+h1+コンテンツ+BottomTabBar、PC は Header(variant=logo)+Breadcrumb+2カラム(SideNav 256px + main)",
1183
+ "サイドナビは既定で ec/_mypage-menu-data の mypageMenuGroups を使用。activeMenu で現在ページを強調する",
1184
+ "既定値は props で差し替え可能(menuGroups / breadcrumbs / bottomNavItems / headerActions)で、骨格(ヘッダー+2カラム+BottomTabBar)自体は他事業(ジョブボードのマイページ等)でも再利用できる",
1185
+ "breadcrumbs 省略時は「ホーム > {ユーザー}さまのマイページ > {title}」を自動生成する",
1186
+ "マイページトップ(Dashboard)はメインカラムを白背景で持たずセクションごとにカード化する別パターンなので、この shell を使わない",
1187
+ "a11y: DOM 先頭に SkipLink を標準内蔵し <main id> を制御できる(mainId 既定 main-content)。sr-only で視覚無影響。skipLink={false} で無効化"
1188
+ ]
1189
+ },
1099
1190
  {
1100
1191
  "name": "OrderSection",
1101
1192
  "path": "src/components/ec/order-section.tsx",
@@ -1157,6 +1248,16 @@
1157
1248
  "name": "ProductDetailSidebar",
1158
1249
  "path": "src/components/ec/product-detail-sidebar.tsx"
1159
1250
  },
1251
+ {
1252
+ "name": "ProductListItem",
1253
+ "path": "src/components/ec/product-list-item.tsx",
1254
+ "category": "display",
1255
+ "rules": [
1256
+ "カート/注文履歴/レビュー variant を持つ商品リスト行",
1257
+ "captionは規格・仕様の短い自由記述(例: \"1kg / 冷蔵\")。価格表示の直下にtypo-body-xs / Text-Medium-Emphasisで表示。tags(配送方法等のenum variant)とは別物",
1258
+ "subtotal/subtotalLabel(既定\"小計\")はcart variant専用。数量セレクタ行の右側(収まらなければ下に折り返し)に¥{カンマ区切り}で表示。BtoB/法人ECのロット購入等、商品ごとの単価×数量の内訳を明示したい場合に使う"
1259
+ ]
1260
+ },
1160
1261
  {
1161
1262
  "name": "ProductOption",
1162
1263
  "path": "src/components/ec/product-option.tsx",
@@ -1234,16 +1335,6 @@
1234
1335
  {
1235
1336
  "name": "StatCard",
1236
1337
  "path": "src/components/ec/stat-card.tsx"
1237
- },
1238
- {
1239
- "name": "ProductListItem",
1240
- "path": "src/components/ec/product-list-item.tsx",
1241
- "category": "display",
1242
- "rules": [
1243
- "カート/注文履歴/レビュー variant を持つ商品リスト行",
1244
- "captionは規格・仕様の短い自由記述(例: \"1kg / 冷蔵\")。価格表示の直下にtypo-body-xs / Text-Medium-Emphasisで表示。tags(配送方法等のenum variant)とは別物",
1245
- "subtotal/subtotalLabel(既定\"小計\")はcart variant専用。数量セレクタ行の右側(収まらなければ下に折り返し)に¥{カンマ区切り}で表示。BtoB/法人ECのロット購入等、商品ごとの単価×数量の内訳を明示したい場合に使う"
1246
- ]
1247
1338
  }
1248
1339
  ]
1249
1340
  }