@cakejp/design-system 0.20.1 → 0.21.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 +172 -0
- package/CLAUDE.md +5 -3
- package/MIGRATION.md +3 -3
- package/README.md +31 -11
- package/contracts/components.json +420 -63
- package/contracts/composition.json +38 -4
- package/contracts/rules.json +27 -5
- package/contracts/screen-patterns.json +6 -4
- package/dist/components/ec/admin-shell.js +62 -60
- package/dist/components/ec/anniversary-card.js +13 -12
- package/dist/components/ec/coupon-card.js +11 -11
- package/dist/components/ec/delivery-calendar.js +51 -45
- package/dist/components/ec/mypage-shell.js +80 -69
- package/dist/components/ec/product-card.js +93 -76
- package/dist/components/ec/product-carousel.js +65 -60
- package/dist/components/ec/product-detail-bar.js +13 -11
- package/dist/components/ec/product-detail-sidebar.js +60 -58
- package/dist/components/ec/product-list-item.js +64 -63
- package/dist/components/ec/product-option.js +30 -26
- package/dist/components/ec/rating-stars.js +27 -27
- package/dist/components/ec/review-card.js +32 -32
- package/dist/components/ec/review-form.js +37 -37
- package/dist/components/ec/shop-card.js +21 -19
- package/dist/components/foundations/accordion.js +33 -31
- package/dist/components/foundations/alert-dialog.js +4 -5
- package/dist/components/foundations/badge.js +5 -5
- package/dist/components/foundations/breadcrumb.js +27 -26
- package/dist/components/foundations/button.js +144 -25
- package/dist/components/foundations/calendar.js +28 -26
- package/dist/components/foundations/checkbox-card.js +71 -47
- package/dist/components/foundations/checkbox-group.js +30 -27
- package/dist/components/foundations/checkbox.js +69 -52
- package/dist/components/foundations/chip-variants.js +13 -0
- package/dist/components/foundations/command.js +81 -79
- package/dist/components/foundations/confirm-dialog.js +136 -0
- package/dist/components/foundations/context-menu.js +43 -38
- package/dist/components/foundations/data-table.js +87 -84
- package/dist/components/foundations/dialog.js +45 -36
- package/dist/components/foundations/dropdown-menu.js +47 -42
- package/dist/components/foundations/file-input.js +97 -67
- package/dist/components/foundations/hover-card.js +21 -21
- package/dist/components/foundations/menubar.js +75 -69
- package/dist/components/foundations/navigation-menu.js +31 -26
- package/dist/components/foundations/pagination.js +54 -50
- package/dist/components/foundations/popover.js +7 -7
- package/dist/components/foundations/progress.js +10 -6
- package/dist/components/foundations/radio-group.js +6 -3
- package/dist/components/foundations/responsive-dialog.js +73 -55
- package/dist/components/foundations/scroll-area.js +18 -14
- package/dist/components/foundations/select.js +44 -39
- package/dist/components/foundations/sheet.js +45 -37
- package/dist/components/foundations/skeleton.js +6 -6
- package/dist/components/foundations/skip-link.js +10 -8
- package/dist/components/foundations/slider.js +73 -48
- package/dist/components/foundations/sonner.js +5 -4
- package/dist/components/foundations/spinner.js +7 -5
- package/dist/components/foundations/switch.js +11 -10
- package/dist/components/foundations/tabs.js +54 -39
- package/dist/components/foundations/toggle-group.js +29 -21
- package/dist/components/foundations/toggle.js +20 -16
- package/dist/components/primitives/admin-side-nav.js +65 -62
- package/dist/components/primitives/banner-carousel.js +32 -29
- package/dist/components/primitives/bottom-tab-bar.js +16 -15
- package/dist/components/primitives/category-scroll.js +39 -29
- package/dist/components/primitives/category-shortcuts.js +9 -9
- package/dist/components/primitives/chat-composer.js +77 -74
- package/dist/components/primitives/chip.js +84 -61
- package/dist/components/primitives/combobox.js +63 -47
- package/dist/components/primitives/container.js +9 -9
- package/dist/components/primitives/content-card.js +15 -17
- package/dist/components/primitives/content-carousel.js +79 -68
- package/dist/components/primitives/date-picker.js +137 -99
- package/dist/components/primitives/footer.js +36 -37
- package/dist/components/primitives/header.js +175 -168
- package/dist/components/primitives/image-carousel.js +107 -87
- package/dist/components/primitives/image-gallery.js +32 -27
- package/dist/components/primitives/image-uploader.js +6 -6
- package/dist/components/primitives/list-item.js +59 -51
- package/dist/components/primitives/menu-drawer.js +36 -38
- package/dist/components/primitives/multi-select.js +89 -58
- package/dist/components/primitives/notification-list.js +10 -9
- package/dist/components/primitives/number-input.js +116 -105
- package/dist/components/primitives/scroll-row.js +21 -0
- package/dist/components/primitives/search-bar.js +31 -28
- package/dist/components/primitives/section-header.js +54 -53
- package/dist/components/primitives/side-nav.js +57 -56
- package/dist/components/primitives/sub-nav.js +13 -14
- package/dist/components/primitives/tag.js +4 -2
- package/dist/index.css +1 -1
- package/dist/index.js +3051 -924
- package/dist/lib/field-labelling.js +31 -21
- package/dist/lib/focus-ring.js +22 -4
- package/dist/lib/high-contrast.js +4 -0
- package/dist/lib/image-index.js +8 -0
- package/dist/lib/use-prefers-reduced-motion.js +21 -0
- package/dist/types/components/ec/admin-shell.d.ts +11 -1
- package/dist/types/components/ec/anniversary-card.d.ts +9 -1
- package/dist/types/components/ec/mypage-shell.d.ts +12 -1
- package/dist/types/components/ec/product-card.d.ts +13 -1
- package/dist/types/components/ec/product-carousel.d.ts +13 -1
- package/dist/types/components/ec/product-detail-bar.d.ts +12 -1
- package/dist/types/components/ec/product-detail-sidebar.d.ts +11 -1
- package/dist/types/components/ec/product-list-item.d.ts +9 -1
- package/dist/types/components/ec/rating-stars.d.ts +2 -0
- package/dist/types/components/ec/review-card.d.ts +1 -1
- package/dist/types/components/ec/shop-card.d.ts +8 -1
- package/dist/types/components/foundations/badge.d.ts +1 -1
- package/dist/types/components/foundations/breadcrumb.d.ts +8 -1
- package/dist/types/components/foundations/button.d.ts +38 -3
- package/dist/types/components/foundations/checkbox-card.d.ts +7 -1
- package/dist/types/components/foundations/checkbox.d.ts +1 -1
- package/dist/types/components/foundations/chip-variants.d.ts +2 -2
- package/dist/types/components/foundations/confirm-dialog.d.ts +61 -0
- package/dist/types/components/foundations/data-table.d.ts +9 -2
- package/dist/types/components/foundations/dialog.d.ts +16 -1
- package/dist/types/components/foundations/pagination.d.ts +1 -1
- package/dist/types/components/foundations/responsive-dialog.d.ts +2 -1
- package/dist/types/components/foundations/sheet.d.ts +12 -1
- package/dist/types/components/foundations/skeleton.d.ts +6 -0
- package/dist/types/components/foundations/slider.d.ts +15 -1
- package/dist/types/components/foundations/tabs.d.ts +7 -0
- package/dist/types/components/primitives/admin-side-nav.d.ts +22 -2
- package/dist/types/components/primitives/banner-carousel.d.ts +9 -1
- package/dist/types/components/primitives/bottom-tab-bar.d.ts +13 -2
- package/dist/types/components/primitives/category-scroll.d.ts +10 -1
- package/dist/types/components/primitives/category-shortcuts.d.ts +11 -2
- package/dist/types/components/primitives/chip.d.ts +22 -3
- package/dist/types/components/primitives/combobox.d.ts +7 -2
- package/dist/types/components/primitives/container.d.ts +3 -0
- package/dist/types/components/primitives/content-card.d.ts +1 -1
- package/dist/types/components/primitives/content-carousel.d.ts +12 -4
- package/dist/types/components/primitives/date-picker.d.ts +10 -3
- package/dist/types/components/primitives/footer.d.ts +1 -1
- package/dist/types/components/primitives/header.d.ts +14 -2
- package/dist/types/components/primitives/image-carousel.d.ts +23 -5
- package/dist/types/components/primitives/list-item.d.ts +10 -1
- package/dist/types/components/primitives/menu-drawer.d.ts +1 -1
- package/dist/types/components/primitives/multi-select.d.ts +7 -2
- package/dist/types/components/primitives/notification-list.d.ts +10 -1
- package/dist/types/components/primitives/number-input.d.ts +18 -5
- package/dist/types/components/primitives/scroll-row.d.ts +43 -0
- package/dist/types/components/primitives/section-header.d.ts +9 -2
- package/dist/types/components/primitives/side-nav.d.ts +13 -1
- package/dist/types/components/primitives/sub-nav.d.ts +1 -1
- package/dist/types/components/primitives/tag.d.ts +1 -1
- package/dist/types/index.d.ts +7 -1
- package/dist/types/lib/field-labelling.d.ts +23 -8
- package/dist/types/lib/focus-ring.d.ts +70 -3
- package/dist/types/lib/high-contrast.d.ts +25 -0
- package/dist/types/lib/image-index.d.ts +2 -0
- package/dist/types/lib/link-component.d.ts +26 -21
- package/dist/types/lib/use-prefers-reduced-motion.d.ts +9 -0
- package/package.json +11 -3
- package/src/components/COMPONENT_LOOKUP.md +18 -16
- package/src/preset-standalone.css +42 -0
- package/src/preset.css +20 -1
- package/src/styles/semantic.css +57 -0
- package/templates/AGENTS.md +5 -1
- package/templates/CLAUDE.md +3 -1
- package/tokens.json +49 -0
- package/dist/lib/link-component.js +0 -6
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,178 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## [0.21.0] - 2026-10-15
|
|
15
|
+
|
|
16
|
+
### ✨ Added
|
|
17
|
+
|
|
18
|
+
- **横スクロールの行 `ScrollRow` を追加**([#320](https://github.com/flashpark/cake-design-system/issues/320)): カード・絵柄・タグ等を横 1 列に並べてスクロールさせる行。`Container` の直下に置くと、gutter 分だけ外へはみ出して Container の外縁(SP では画面端)までスクロールし、1 枚目の左端が見出しとそろう。スナップ後・最後の要素の右にも同じ幅の余白が残る(`scroll-padding`)。画面ごとに `-mx-4 px-4 scroll-px-4` を手で当てる必要が無く、md 以上の 24px・`gutter="tight"` にも追従する。`bleed={false}` で Container の内側に収める(Card など余白を持つ親の中ではこちら) / `snap` で子要素の左端にスナップ。`ref` で行の要素を受け取れる(React 19)。子のフォーカスリングが切れないよう上下に 4px の余白を持つ(負のマージンで打ち消すので高さは変わらない)
|
|
19
|
+
- **`Container` が gutter の幅を CSS 変数 `--Container-Gutter` で子孫に渡す**(default: 16px / md 以上 24px、tight: 12px / 16px、none: 0)。見た目は変わらない。自前で横スクロール行を組むときは `-mx-[var(--Container-Gutter)] px-[var(--Container-Gutter)] scroll-px-[var(--Container-Gutter)]` を使う(composition 契約に追記)
|
|
20
|
+
- **高コントラスト(OS の「コントラストを上げる」/ `data-contrast="more"`)で、入力・選択の操作部品を 3:1 以上にする(opt-in・既定の見た目は不変)**: 次のどちらかのときだけ、既定では 3:1 に届かない枠・溝・輪郭・フォーカスリングが濃くなる([#301](https://github.com/flashpark/cake-design-system/issues/301)・姉妹 DS ksk #645 の逆輸入)。
|
|
21
|
+
- OS の設定 `@media (prefers-contrast: more)`(ユーザーが OS で有効にする)
|
|
22
|
+
- アプリが `<html data-contrast="more">`(`document.documentElement`)を付ける(常時 opt-in。`<html class="dark" data-contrast="more">` のように dark と併用できる)。**React の `#root` などアプリ内の要素に付けると、body 直下へ Portal される Dialog / Sheet / Popover / Combobox の一覧などには効かない**(一部の要素に付ける部分適用は、その要素の内側に描かれるものだけ)
|
|
23
|
+
- 対象と切り替え先: Checkbox / CheckboxGroup / CheckboxCard / RadioGroup タイル / SearchBar / NumberInput(md)の枠と ReviewForm の入力用の星(未選択)は `--Border-Control`(light は Gray-600 で 4.52:1 / dark は White-alpha-500 で 5.32:1)、Slider の溝は `--Surface-Control-Track`(同値)、Combobox / MultiSelect のトリガーと NumberInput(sm)は**地を変えずに内側 1px の輪郭**(`--Border-Control`)、リングだけでフォーカスを示す部品(Switch / SearchBar・ImageUploader の内側リング / ListItem / ImageCarousel・ProductCarousel / ProductOption)は不透明な `--Focus-Ring-Control`(緑。3.44:1 / dark 6.10:1)
|
|
24
|
+
- 枠だけで境界を示す操作部品も同じ `--Border-Control` に切り替わる: ImageUploader の追加ボタン / ReviewForm の写真追加ボタン / ProductOption の画像アップロードボタン(破線)、Toggle・ToggleGroup(outline)、Calendar の月・年ドロップダウン(shadcn 由来の `--input` を使っていた枠)、丸いアイコンボタン(ProductCard のお気に入り / ProductListItem のブックマーク / Header の showLabel アクション / SectionHeader の前へ・次へ / ImageCarousel・ContentCarousel の矢印)
|
|
25
|
+
- フォーカスリングも対象: 枠幅 0 の要素では緑の枠が出ずリングだけが手がかりになるため、`FOCUS_RING`(Button の枠なしの variant / Combobox / MultiSelect / NumberInput(sm) / DataTable の並べ替え / AdminSideNav / ContentCard / FileInput の解除ボタン)と、shadcn 由来の `ring-ring/50` を使っていた Toggle / ToggleGroup / NavigationMenu / ScrollArea / Accordion / Calendar / Badge のリングも、高コントラストのときだけ不透明な `--Focus-Ring-Control` にする(既定は従来と同じ 50% 透過)
|
|
26
|
+
- Combobox / MultiSelect は、エラー(`aria-invalid`)のとき高コントラストの灰色の輪郭を出さず(透明)、赤の内側リング(4.6:1 以上)がそのまま見える
|
|
27
|
+
- **既定の見た目は変わらない**: 新ロール 3 つ(`--Border-Control` / `--Surface-Control-Track` / `--Focus-Ring-Control`)は上記の条件のときだけ宣言し、`:root` / `.dark` では宣言しない。部品は `border-[var(--Border-Control,var(--Border-Medium-Emphasis))]` のようにフォールバック付きで参照するため、未宣言のとき(= 既定)は従来と同じ変数を**その要素で**解決する(消費側がラッパー要素単位で `--Border-Medium-Emphasis` 等を上書きしていても従来どおり追従する)
|
|
28
|
+
- 導入: DS を更新するだけでは何も変わらない。OS 設定を使うユーザーには自動で効く。アプリ側で常時有効にしたい(設定画面の切り替え等)ときは root に `data-contrast="more"` を付ける。`@cakejp/design-system/preset-standalone`(Tailwind を通さない consumer)にも同じ宣言を入れてある
|
|
29
|
+
- 注意(Slider): 高コントラストでは溝がブランドのオレンジと同程度の明るさのグレーになるため、選択範囲との区別は色相が中心になる(つまみの枠は従来どおり)
|
|
30
|
+
- **`FOCUS_RING_ONLY` を root export**: 枠は変えずリングだけでフォーカスを示す部品(Switch / ListItem / カルーセル等)が使う定数。`FOCUS_RING_INSET` と同じく、既定は従来の緑 50% リングのまま、高コントラストのときだけ不透明な `--Focus-Ring-Control` に切り替わる。自作の部品でリングだけのフォーカスにするときは `ring-[var(--Focus-High-Emphasis)]/50` を直書きせず、これを使う
|
|
31
|
+
- **`tokens.json` に `color.semanticContrastMore`**: 高コントラスト時の新ロールの値(light / dark)。AI 向けの参照用で、`__tests__/contrast-more-tokens.test.ts` が `semantic.css` と `preset-standalone.css` との一致を固定している
|
|
32
|
+
- **`DialogContent` / `SheetContent` に幅の段 `size` を追加**(opt-in): 画面ごとに `className="sm:max-w-[…]"` を当てて幅を作っていた箇所を、段で選べるようにする。**`size` を渡さない限り className は導入前と同一で、既定の見た目は変わらない**。
|
|
33
|
+
- `DialogContent`: `sm`(400px)/ `md`(512px)/ `lg`(640px)/ `xl`(800px)。`size` 未指定は従来の `sm:max-w-lg` のまま(下記の注意)
|
|
34
|
+
- `SheetContent`: `sm`(384px・未指定と同じ)/ `md`(576px)/ `lg`(768px)。`side="left"` / `"right"` のときだけ効き、`"top"` / `"bottom"` は全幅なので無視する
|
|
35
|
+
- 段は `sm` 以上の画面で効く。SP は段に関係なく従来どおり(`Dialog` は画面端から 16px を残す幅 / `Sheet` は画面の 3/4)
|
|
36
|
+
- 消費側の `className`(`sm:max-w-*`)は `size` より優先される。既に `className` で幅を上書きしている画面はそのまま動く
|
|
37
|
+
- `ResponsiveDialogContent` も `size` を受ける。PC の `Dialog` にだけ渡り、SP の `Drawer`(全幅のボトムシート)には渡らない
|
|
38
|
+
- `AlertDialogContent` の `size`(`default` / `sm`)は別物で変更なし(確認文面向けの 2 段。広い段は足さない)。型の無い JSX で取り違えて `DialogContent` / `SheetContent` に `size="default"` を渡しても、幅の上限は消えず未指定と同じ扱いになる
|
|
39
|
+
|
|
40
|
+
**導入上の注意**: `Dialog` の `size` 未指定の実幅は 512px ではなく **960px**。従来の `sm:max-w-lg` は Tailwind 既定では 512px だが、DS の `preset` が `--container-lg` をコンテナクエリの切替段(960px)に再定義しているため、preset を読み込む consumer では 960px になる(`max-w-md` / `max-w-xl` も同様に 768px / 1280px)。この変更では既定を変えていないので、幅を決めたい画面は `size` を明示する。段の値はこの再定義に影響されないよう px の任意値で書いている。
|
|
41
|
+
|
|
42
|
+
- **`Button` に処理中表示 `loading` / `loadingLabel` を追加**: `loading` を付けると、ラベルを透明にしてスピナーを中央に重ねる。ラベルは DOM に残すのでボタンの幅は変わらない(アイコン付きでも同じ)。`aria-busy="true"` と `aria-disabled="true"` を付け、クリック・Enter / Space・フォーム送信(入力欄での Enter による暗黙送信を含む)を止める。native の `disabled` は付けないため、押した直後に処理中になってもフォーカスはボタンに残る(従来の「`disabled` + `Spinner`」ではフォーカスが外れ、キーボード・スクリーンリーダー利用者が操作位置を見失っていた)。色は variant のまま、スピナーは `prefers-reduced-motion` で回転を止める。Windows のハイコントラスト(forced-colors)でもラベルを消してスピナーだけを出す。`loadingLabel` は読み上げ名に足す文言(既定「処理中」)で、`aria-busy` を読まない読み上げソフトでも処理中が伝わる(`aria-label` 指定時は `loadingLabel` が文字列のときだけ aria-label に連結、`aria-labelledby` 指定時は参照に追加。同じ `aria-labelledby` を複数のボタンで共有して loading にする場合は各ボタンに `id` を付ける。付けないと文言の要素の id が重複するため、開発時は `console.warn` で知らせる)。**`loading` を指定しない Button の出力・見た目は変わらない**。`loading` はクリック抑止に関数を使うため Client Component の状態から渡す。止めるのは click 系だけで、`onPointerDown` / `onKeyDown` 等は loading 中も呼ばれる(pointerdown で開くメニューの起点にするときは利用側で止める)。`asChild` 併用時はスピナーを出さず、`aria-busy`・`aria-disabled`・`tabIndex=-1`・クリック抑止だけを子へ渡す
|
|
43
|
+
- **`ConfirmDialogProvider` + `useConfirm` を追加(`window.confirm()` の置き換え)**: アプリのルートに `<ConfirmDialogProvider>` を 1 つ置き、`const ok = await confirm({ title, description, confirmLabel, cancelLabel, tone })` で確定 `true` / キャンセル・Esc `false` を受け取る。中身は `AlertDialog`(キャンセルは既定の tertiary、`tone="destructive"` で確定ボタンが destructive)。同時に呼ばれたら 1 件ずつ順に表示し、閉じた後は呼び出し元へフォーカスを戻す(閉じるアニメーション中に次の確認が来ても元の呼び出し元へ戻る。メニュー項目から呼んだときはメニューを開いたトリガーへ戻る)。Provider が unmount されたとき(`<Activity>` で隠したときを含む)の未解決と unmount 後の呼び出しは `false`。Provider の外で `useConfirm` を使うと例外を投げる(設定漏れを無言のキャンセルにしないため)。Next.js App Router では Server Component の layout にそのまま置ける(Provider 自体が client 境界)
|
|
44
|
+
- **`Chip` に `removeLabel` を追加**: 削除ボタンの読み上げ名を指定できる(既定は従来どおり「削除」)。削除可能な Chip が並ぶ場面で「洋菓子を削除」のように対象が分かる名前を渡すため。`MultiSelect` の選択済み Chip はこれで「{項目のラベル}を削除」になる
|
|
45
|
+
- **`linkComponent` をナビ・カード・リスト系の部品へ横展開**: `Footer` / `MenuDrawer` / `SubNav` / `Pagination` / `ContentCard`([#236](https://github.com/flashpark/cake-design-system/issues/236))に続き、素の `<a>` を描いていた次の部品へ `linkComponent`(`next/link` 等の差し込み口。型は `LinkComponent`)を追加。Next.js の consumer で、サイドナビ・タブバー・商品導線だけフルページ遷移になっていた箇所をクライアント遷移にできる。KSK の項目ごとの `render` スロットではなく、既存の `linkComponent` を広げた(機構を二重にしないため)。
|
|
46
|
+
- **ナビ**: `AdminSideNav`(PC レールの項目・サブメニューのポップアップ・SP ドロワーの項目とサブ項目)/ `SideNav` / `BottomTabBar` / `Header`(`navItems` の `href`、「その他」メニュー内、`actions` の `href`。`logo` は ReactNode を描くだけで `<a>` を足さないため対象外)/ `AdminShell`(サイドナビとパンくず)/ `MypageShell`(ヘッダー・サイドメニュー・パンくず・`BottomTabBar` へ素通し)/ `BreadcrumbLink`(既存の `asChild` と併用した場合は `asChild` が優先)
|
|
47
|
+
- **コンテンツ**: `ProductCard`(商品リンクとショップ名リンク)/ `ProductListItem` / `ShopCard` / `ProductCarousel`(セクション画像・もっと見る・各カード。`products[].linkComponent` があれば商品側を優先)/ `ProductDetailBar` / `ProductDetailSidebar` / `ListItem` / `SectionHeader`(タイトル行と「もっと見る」)/ `BannerCarousel` / `ImageCarousel` / `CategoryScroll` / `CategoryShortcuts` / `NotificationList` / `AnniversaryCard` / `DataTableLinkCell` / `Chip`(`href` 指定時。`removable` のときは本体のリンク)
|
|
48
|
+
- **未指定なら DOM は従来どおり**(`<a>` のまま。属性・className・順序も同じ。対応前の main の `renderToStaticMarkup` と文字列で一致することをテストで固定)。`href` の無い項目は従来どおり `<button>` / `<div>`。意図した差分は下の Fixed の 2 件(`Header` の `aria-current`、`BottomTabBar` / `CategoryShortcuts` の `onClick`。後者は DOM に出ない)のみ。`aria-current="page"`・`onClick`(`SideNav` の `storyId` 遷移の差し替え、`ProductCard` のショップ名の `stopPropagation`、`ProductDetailBar` の `onTabClick` など)は `linkComponent` 経由でも保たれる。外部リンク(`DataTableLinkCell` の `external`)は `linkComponent` を通さず素の `<a target="_blank">`
|
|
49
|
+
- **導入上の注意**: `AdminSideNav` / `Header` / `AdminShell` / `MypageShell` / `ListItem` / `ImageCarousel` は Client Component(`MypageShell` は内部で `Header` へ渡す)。Next.js App Router では Server Component から `linkComponent` を渡せず `Functions cannot be passed directly to Client Components` で落ちるため、呼び出し側のファイルを `"use client"` にする。また、内部で host 要素(`<a>` / `<button>`)にイベントハンドラを直接付ける部品は、`"use client"` を持たなくても Server Component から描けず(`Event handlers cannot be passed to Client Component props` で落ちる。`linkComponent` の有無によらない)、同じく呼び出し側を `"use client"` にする。無条件: `SideNav`(全項目の `onClick`)/ `ProductDetailBar`(全タブの `onClick`)/ `MypageShell`(内部で `SideNav` を描く)。条件付き: `ProductCard` / `ProductCarousel`(`shopHref` 指定時のショップ名リンク、`showCartButton` 指定時のカートボタン)/ `ProductDetailSidebar`(`sizeOptions` 指定時)/ `Chip`(`removable` 指定時)。それ以外の追加部品(および条件付きの部品の条件外)は Server Component のまま使える。`AdminSideNav` / `Header` のポップアップ内のリンクは Radix の `asChild` 越しに描かれるため、`ref` と任意の属性を `<a>` まで転送する実装を渡すこと(`next/link` は転送する)
|
|
50
|
+
- 対象外: ページ内アンカー専用の `SectionNav` / `SkipLink`、常に外部へ出る `ShareButtons` と `Footer` の SNS・信頼バッジ
|
|
51
|
+
- `PaginationPrevious` / `PaginationNext` / `BreadcrumbLink` の `linkComponent` を含め、`__tests__/link-component-rollout.test.tsx`で、未指定 DOM の不変・素通し `<a>` との同一・内部リンクだけの差し替え・再描画での DOM 保持・ハンドラと `aria-current` の保持・Radix メニュー内の `ref` 転送とフォーカス移動を検査
|
|
52
|
+
- **`LinkComponent` 型をルート(`@cakejp/design-system`)から型 export**: consumer が `next/link` 等のラッパーを `LinkComponent` で型付けして `linkComponent` に差し込める(`import type { LinkComponent } from "@cakejp/design-system"`)。`check:consumer-types` の consumer 視点の型検査に追加
|
|
53
|
+
- **`Button` に `variant="outline"` を追加**: 白地(`--Surface-Primary`)+ 1px の黒系の枠(`--Border-High-Emphasis`)+ `--Text-High-Emphasis` 文字。hover / active は `ghost` と同じ薄い下地(`--Hover-Text-Button` / `--Active-Text-Button`)、disabled は枠と文字を薄くする。ブランド色を使わない準主役の前進アクション(「一覧を見る」等の移動ボタン、一覧・カードで1件ごとに繰り返す操作、ブックマーク等の保存トグルのボタン本体)に使う。セマンティックトークンだけで組んであり dark でもそのまま使える。loading 中の forced-colors の背景も対応済み。既存の variant の見た目は、下の Changed の `link` を除いて変わらない
|
|
54
|
+
- **ブランド色の使いどころのルール `brandColorUsage` を追加**(`contracts/composition.json`。`contracts/rules.json` に R57、`guidelines/foundations/color.md` に「Brand color usage」節): ブランド色が付いた部品が画面に多いと目立ちすぎるため、使ってよい場所(1ビューポートに1つの主 CTA / 価格の最強調 / ロゴ / 入力部品のオン状態 / 進捗・処理中の表示 / 未読ドット・件数バッジ / ヘッダーの「会員登録・ログイン」)と、使わない場所(それ以外のヘッダー・グローバルナビの操作 / 一覧・カードで繰り返す操作 / 保存トグルのボタン本体 / 「もっと見る」等の移動 / ナビの選択中表示 / 評価の星 / 装飾目的の情報ラベル)、それぞれの代わりの variant・トークンを定めた。ブランド色の色相に依存しない書き方(役割で判断する)。選択中の Chip は下の Changed で対応済み。`ctaHierarchy` にも outline を加え、link の意匠を更新した。R57 は正規表現では検出できないガイドライン型(lint では検出しない)
|
|
55
|
+
|
|
56
|
+
### 🎨 Changed
|
|
57
|
+
|
|
58
|
+
- **`Button variant="link"` をブランド色から、グレーの常時下線に変更**(消費側に見た目の影響あり): 文字色が `--Brand-Cake-Orange` から `--Text-Medium-Emphasis` に、下線は hover のときだけから常時(`underline-offset-4`)になり、hover で `--Text-High-Emphasis` に濃くなる(disabled は従来どおり `--Text-Disable`)。loading 中は下線も消す。補助リンク(「もっと見る」等)にブランド色を使わないため。移行: ブランド色のリンクが必要なら `className` で上書きせず、ルール(`brandColorUsage`)に沿って使い分ける。見た目を変えたくない箇所は `className="text-[var(--Brand-Cake-Orange)] no-underline hover:underline"` で従来の見た目に戻せるが、推奨しない
|
|
59
|
+
- **補助リンク「もっと見る」を同じ意匠(グレー + 常時下線)に揃えた**: `SectionHeader` の「もっと見る」(`moreHref` / `onMoreClick`。`ProductCarousel` / `CategoryScroll` / `BannerCarousel` も内部で使うので同時に変わる)と、`ReviewCard` の本文の「もっと見る」。文字色が `--Text-Accent-Primary` から `--Text-Medium-Emphasis` になり、下線が付く(hover で `--Text-High-Emphasis`)。DOM の構造は変わらず、クラス名だけが変わる
|
|
60
|
+
- **`ProductCard` の `showCartButton` のカートボタンを、ブランド色のベタ塗りから `Button` の outline 相当に変更**: 白地 + 黒系の 1px 枠 + `--Text-High-Emphasis` 文字(高さは従来どおり 36px、`buttonVariants` の `outline` / `sm` を使うので、キーボードフォーカスのリングと forced-colors の outline も付く)。商品カードごとに繰り返す操作がブランド色で並ぶのを避けるため。`ProductCarousel` の `showCartButton` も同じ。消費側が `ProductCard` のカートボタンを CSS で上書きしていると効き方が変わりうる。`ProductListItem` のカートボタンなど、同種の繰り返す操作でブランド色が残る部品は別途(`brandColorUsage` の notAllowed に沿って順次)
|
|
61
|
+
- **`Chip` の選択中(`selected`)の見た目を、薄いブランド色地から「グレー地 + 黒系の内側 1px の枠」に変更**(消費側に見た目の影響あり): 新しい variant `selected`(`chipVariants`)を追加し、`Chip` の `selected` が `accent` ではなくこれを使う。地は `--Surface-Tertiary`、文字は `--Text-High-Emphasis`、枠は `--Border-High-Emphasis`(`border` ではなく内側リング `inset-ring` で描くので、未選択→選択で大きさは変わらない)、hover は `--Hover-Tertiary-Button`。count バッジの選択中も、ブランド色ベタ+白文字から `--Surface-Primary` 地 + `--Text-High-Emphasis` に変え、hover の反転は無くした。forced-colors の選択中(Highlight の塗り)は従来どおり。`variant="accent"` は削除せず、明示指定の互換のために残す(選択中の表示には使わない)。`StatusCountTabs` など `Chip selected` を使う部品は追従して変わる。**`RadioGroup variant="chip"` のタイルは入力部品のオン状態なので変えていない**(薄いブランド色地のまま)ため、Chip の selected とは見た目が分かれる。移行: 選択中をブランド色のままにしたい箇所は `<Chip variant="accent">` を明示する(`selected` prop を使わない)
|
|
62
|
+
- **`RatingStars`(表示用の評価)の星と数値を、ブランド色から `--Text-High-Emphasis`(黒系)に変更**: 入力用の星(`ReviewForm` の選択済み)は変えない。`ProductCard` の評価表示もこれに追従する
|
|
63
|
+
|
|
64
|
+
### 🐛 Fixed
|
|
65
|
+
|
|
66
|
+
- **`ContentCarousel` の `peek` が Container の余白と二重になり、スワイプ後は画面端に貼り付いていた**([#320](https://github.com/flashpark/cake-design-system/issues/320)): `Container` の中に置くと 1 枚目の左端が見出しより 16px 内側(幅 375px で x=32、見出しは x=16)にずれていた。また `scroll-padding` が無く、スワイプ・ドット・自動再生で移動した後や表示直後のスナップで、スライドが画面端(x=0)に寄っていた
|
|
67
|
+
- Container の直下では gutter 分だけ外へはみ出して画面端までスクロールし、1 枚目の左端が見出しとそろう(md 以上は 24px)。スナップ後・最後のスライドの右にも同じ幅の余白が残る。Card など余白を持つ親の中に peek で置かない
|
|
68
|
+
- Container の外(全幅)に置いたときは従来どおり端の余白 16px・カード幅は全幅 − 76px・次のスライドが 48px 見える。スライドの間隔をスライド内の右余白(`pr-3`)から `gap-3` に変えたため、最後のスライドの右の余白だけ 12px → 16px になる
|
|
69
|
+
- **注意**: Container の中で ContentCarousel に `className="-mx-4"` 等を当てて回避していた画面は、二重にはみ出してページが横に伸びるので、その回避を外す
|
|
70
|
+
- PC(コンテナ幅 960px 以上)は peek しないので変わらない
|
|
71
|
+
- **`ImageCarousel` の `peek` も同じく、Container の余白と二重になり、移動後に画面端へ貼り付いていた**([#320](https://github.com/flashpark/cake-design-system/issues/320)): `ContentCarousel` と同じ直し方(Container の中では gutter 分はみ出して 1 枚目を見出しにそろえる・`scroll-padding`・Container の外では端の余白 16px/スライド幅は全幅 − 76px)。ドット・矢印・自動再生の移動先も 1 枚目からの距離で計算する
|
|
72
|
+
- `peek` と `centeredSlides` の併用時、タブレット(コンテナ幅 768〜959px)は centeredSlides の表示(Container からはみ出さず中央に 1 枚・幅は左右の余白の内側いっぱい)になる。修正前は peek の幅のまま左に寄っていた
|
|
73
|
+
- **注意**: Container の中で ImageCarousel に `className="-mx-4"` 等を当てて回避していた画面は、その回避を外す
|
|
74
|
+
- 矢印・ドット・自動再生の移動先の計算は peek 以外にも効く。`centeredSlides`(タブレット)は、移動先のスライドを最初から中央に置く。修正前は左の余白分ずれた位置へスクロールし、スナップで中央へ寄せ直していた
|
|
75
|
+
- peek の SP では、スクロール領域が画面端まで広がるため、キーボードで当てたときのフォーカスリングの左右が画面の外に出る(上下は見える)
|
|
76
|
+
- **`ImageCarousel` の複数枚表示(`pcSlidesPerView=3`)で、最初から 3 枚目が現在位置(ドットの強調)になり、最初の「次へ」で末尾まで飛んでいた**: 現在位置を、見えているスライドの検出(最後に見えたものが勝つ)から、スクロール位置にいちばん近いスライドに変えた(`ContentCarousel` と同じ)
|
|
77
|
+
- **`ContentCarousel` / `ImageCarousel` の PC の複数枚表示(`itemsPerView` / `pcSlidesPerView` が 2 以上)で、末尾まで進むと「次へ」・自動再生がそこで止まり続けていた**: 最後のスライドを先頭にそろえるほどスクロールできないため、移動先が同じ位置に戻されていた。末尾までスクロールしきっていたら先頭へ戻る
|
|
78
|
+
- **両カルーセルとも、画面の回転や親の幅の変化でスライドの位置が変わったときも、現在位置(ドットの強調)を測り直す**
|
|
79
|
+
- **`AdminSideNav` の SP ドロワーでリンクを押してもドロワーが閉じなかった問題を修正**: ドロワー内のリンク(項目・サブ項目)を押すと `onOpenChange(false)` が呼ばれ、`AdminShell` ではドロワーが閉じる。素の `<a>` ではページの再読み込みで閉じていたが、`linkComponent`(next/link 等)でクライアント遷移すると開いたまま新しいページに重なっていた。見た目は変わらない
|
|
80
|
+
- **`Header` の通常表示のナビ項目に `aria-current="page"` を付ける**: `navItems` の `isActive` なリンクに現在地が伝わっていなかった(「その他」メニュー内のリンクにだけ付いていた)。属性が 1 つ増えるだけで見た目は変わらない。`getByRole` の `current` 指定などでナビを検査しているテストは、現在地の項目が増える点に注意
|
|
81
|
+
- **`BottomTabBar` / `CategoryShortcuts` / `Header`(通常表示のナビ項目)/ `Chip` が `href` 付きの項目で `onClick` を呼ばなかった問題を修正**: `href` の有無によらず項目の `onClick` が呼ばれる(計測・フィルター切替などの副作用用。遷移は止めない)。`href` の無い項目(`<button>`)は従来どおり。`Chip` は `href` 付きのとき `onClick` に加えて `aria-*` / `data-*` なども `<a>` に渡す(`type` / `disabled` / `form*` / `name` / `value` など button 専用の属性は渡さない)
|
|
82
|
+
- **ポップアップが幅 390px の画面で右へはみ出していた問題を修正**: `DropdownMenu`(サブメニュー含む)/ `Select`(`position="popper"` のとき)/ `Popover` / `HoverCard` / `Menubar` / `ContextMenu` の中身の最大幅を、Radix が出す「画面内に使える幅」(available-width)までにした。長い項目の一覧が 1 行の長さまで伸び(実測 654〜684px)、`className="w-[480px]"` などの広い幅もそのまま右へはみ出していた。収まる一覧・既定の幅(`Popover` 288px / `HoverCard` 256px など)には効かないため、**既定の見た目は変わらない**。`Popover` を使う `Combobox` / `MultiSelect` / `DatePicker` もそのまま追従する
|
|
83
|
+
- **`ContextMenu` を画面の右端・下端の近くで開くと画面外へはみ出していた問題を修正**: Content に付いていた `position: fixed`(1307018「右クリック時の画面シフトを修正」で追加)のせいで Radix の配置用ラッパーが 0×0 になり、衝突回避(反転・ずらし)が効いていなかった(幅 390px で x=302 から開くと右端 +40px、下端近くでは下へはみ出し)。`fixed` を外し、端の近くでは左へ反転・上へずらして画面内に収める。余裕のある位置では従来どおり右クリックした点の右下に開く。**項目の幅による見た目の変化**: 最小幅 128px に収まる項目(「コピー」等)だけのメニューは不変。収まらない長い項目は折り返さず 1 行で表示され、メニューが広がる(例: 「リンクのアドレスをコピーする」で 128px → 約 207px。`DropdownMenu` と同じ挙動。旧挙動は `fixed` の副作用で常に 128px に押し込まれ、2 行に折り返していた)。スクロールバーを表示した chromium(ページ未スクロール / 600px スクロール、`scrollbar-gutter` あり / なし)で、`fixed` の有無にかかわらず右クリック時の画面のずれ・メニュー位置の差が無いことを確認した
|
|
84
|
+
- **`Pagination` のページ番号が桁数の多いときに枠からはみ出していた問題を修正**: SP(36px)では 4 桁、PC(40px)では 5 桁で文字が枠を越えていた。ページ番号(`size="icon"`)だけ幅を中身に合わせて伸ばす。3 桁以下は不変(実測で差なし。36 / 40px の正方形)、4 桁以上は文字幅に合わせて広がる(SP の 4 桁で約 38〜40px、5 桁で約 47〜50px。幅はフォント次第)
|
|
85
|
+
- **`Tabs` に `orientation="vertical"` を渡しても横並びのままだった問題を修正**: 矢印キーだけが上下になり、見た目はタブが横に並んでパネルが下に来ていた。縦向きのときだけ、タブの列を左(幅は `Tabs` の半分まで、長いラベルは折り返す)、パネルを右に置く。underbar は右端の線、segment は地の色で選択中を示す(scrollable は文字下の線のまま)。**横向き(既定)の見た目は変わらない**
|
|
86
|
+
- **動きを減らす設定(`prefers-reduced-motion: reduce`)で動きが止まらなかった問題を修正**:
|
|
87
|
+
- 無限に繰り返すアニメーション(`Spinner` の回転 / `Skeleton` の明滅 / `CouponCard` 獲得中・`Toaster` loading の回転アイコン)を止める。`Spinner` は上辺だけ色付きの欠けた輪と `role="status"` で処理中が分かる
|
|
88
|
+
- メニュー・ポップオーバー等の開閉アニメーション(tw-animate-css の `animate-in` / `animate-out`)が 150ms 再生されていた。`preset` が再生時間を `--Motion-Duration-*` と同じ 0.01ms に落とす。0.20.0 の注記「`prefers-reduced-motion` では従来どおり停止」は `Dialog` など一部にしか当たっていなかったが、本修正で全部品に当たる
|
|
89
|
+
- `ImageCarousel` / `ContentCarousel` の `autoPlay` を自動再生しない。矢印・ドットでの移動もスムーズスクロールしない
|
|
90
|
+
- 通常の設定の見た目・動きは変わらない
|
|
91
|
+
- **Windows のハイコントラスト(forced-colors)で、選択中の項目が見分けられなかった問題を修正**: 背景が Canvas、枠・文字が CanvasText に置き換わり影も消えるため、薄い色地・影・透明な枠で選択を表す部品は、選択中と非選択が同じ見た目になっていた。選択中だけ OS の選択色(`Highlight` / `HighlightText`)で示す。対象は `Tabs`(underbar / scrollable / segment)、`Chip`(`selected`)とそれを使う `StatusCountTabs`、`RadioGroup variant="chip"`、`Toggle`・`ToggleGroup`、`Progress`・`Slider`(帯は `Highlight`、レールは輪郭線)、`DeliveryCalendar` の選択日。`forced-colors` 以外では効かないため**通常表示は変わらない**
|
|
92
|
+
- **`DeliveryCalendar` の選択日が読み上げで分からなかった問題を修正**: 日付の button に `aria-pressed`(選択日は `true`、ほかは `false`)を付けた
|
|
93
|
+
- **`CakeFormField` の `error` がコントロールの「エラー状態」として伝わらなかった問題を修正**: これまで `error` を出してもコントロール側に `aria-invalid` が付かず、読み上げではエラー状態が分からなかった。Input / Textarea / Select / Combobox / MultiSelect / DatePicker / DateTimePicker / NumberInput / Switch / label なしの Checkbox に、`error` があるとき自動で `aria-invalid="true"` が付く(`error` が無ければ属性自体を付けない。利用側が `aria-invalid` を明示したらそちらが優先)。**`aria-invalid` を手で付けていなかった画面では、エラー時に Input / Select などの枠が赤くなる**(エラー状態でだけ出る表示で、通常時の見た目は変わらない)(KSK #640)
|
|
94
|
+
- **`aria-describedby` を連結に変更**: 利用側が `aria-describedby` を渡すと `CakeFormField` の説明・エラー文の id が置き換わって読み上げから落ちていた。今後は FormField 由来(説明 → エラー)と利用側の指定を空白区切りで連結する(重複 id は除く)。以前の「明示指定が優先」は `id` / `aria-label` / `aria-labelledby` / `aria-invalid` に限る
|
|
95
|
+
- **`Combobox` / `MultiSelect` のエラー時の赤枠が見えなかった問題を修正**: トリガーが枠幅 0 の Button のため、`aria-invalid` で枠の色を変えても見えなかった。赤 1px(`Border-Caution`)を内側リングで描く(高さ・レイアウトは変わらない。キーボードフォーカス時はフォーカスリングと同時に出る)。内側リングは box-shadow で forced-colors(Windows のハイコントラスト)では消えるため、エラー時だけ輪郭線(outline)で境界を出す(forced-colors 以外では効かない)
|
|
96
|
+
- **`DatePicker` / `DateTimePicker` を `CakeFormField` と自動接続**: `id` / `aria-invalid` / `aria-describedby` を受け取り、FormField 配下では id を手書きしなくても label の `htmlFor`・エラー文・エラー状態がつながる。エラー時の枠は Input と同じ `Border-Caution`。**FormField 配下の読み上げ名は「ラベル + 表示中の日付 / placeholder」**(例「お届け希望日 8月1日(土)」。これまでは「8月1日(土)」だけで何の日付か分からなかった。Select 等と同じく FormField のラベルを `aria-labelledby` で指す)。FormField の外の名前は変わらない。DateTimePicker の時・分 Select にも同じエラー状態が届き、名前は「ラベル + 時 / 分」。FormField 配下で id が重複していた問題も直した(時・分の id は FormField 配下のときだけ別に採番し、外では付けない)
|
|
97
|
+
- **操作後にフォーカスが失われる問題を修正**: `MultiSelect` で選択済み Chip を削除すると次の Chip の削除ボタン(無ければ直前の Chip、残らなければトリガー)へ、`DatePicker` の `clearable` の × で値を消すと trigger へフォーカスを移す。`NumberInput` は上限・下限に達したボタンを native の `disabled` ではなく `aria-disabled` にし、キーボードで連打してもフォーカスがボタンに残る(部品全体の `disabled` は従来どおり native)
|
|
98
|
+
- **`NumberInput` の `error` で入力欄に `aria-invalid` を付ける**(見た目の赤枠だけでなく読み上げでもエラー状態が伝わる)
|
|
99
|
+
- **`NumberInput` を `CakeFormField` と接続**: FormField 配下では入力欄が id(label の `htmlFor` と一致)・説明とエラー文(`aria-describedby`)・エラー状態(FormField の `error` で赤枠と `aria-invalid`)を受け取る。`label` を指定しなければ名前も FormField のラベルになる(入力欄・グループ = ラベル、増減ボタン =「ラベル 減らす / 増やす」。これまでは FormField が「販売価格」でも「数量を入力」と読まれていた)。明示した `inputId` / `label` / `error` が優先。FormField の外の DOM は変わらない
|
|
100
|
+
- **`MultiSelect` の選択済み Chip の削除ボタン名を「{項目のラベル}を削除」に**: すべて「削除」でどの項目か分からなかった
|
|
101
|
+
- **`CheckboxCardItem` の読み上げ名を修正**: カードの内容がそのまま名前になり「ライトプラン 20%OFF 月額 ¥500 展開内容」のように長く、選択の前後で名前が変わっていた。名前はラベル(+ バッジ)だけにし、説明と選択中の展開内容は説明(`aria-describedby`)に分ける(KSK #640 / stract-ui #227)
|
|
102
|
+
- **範囲 `Slider` の Home / End を修正**: 2 つ目のつまみで Home を押すと先頭のつまみが動いていた。フォーカス中のつまみを、そのつまみが動ける範囲の端(隣のつまみ、無ければ min / max)へ動かす(KSK #640 / stract-ui #226)
|
|
103
|
+
- **値を渡さない `<Slider />` が壊れたつまみを描いていた問題を修正**: `value` / `defaultValue` が無いとき、つまみを 2 つ描き、2 つ目は値(`aria-valuenow`)を持たない非表示の要素として DOM に残っていた。Radix の実際の値(`[min]`)に合わせて 1 つだけ描く(見た目は変わらない)
|
|
104
|
+
- **`CheckboxGroupItem` のフォーカス表示を DS 共通の `FOCUS_RING`(緑)に統一**: オレンジの細いリングで選択状態の色と紛らわしかった(rules.json A005)
|
|
105
|
+
- **Windows のハイコントラスト(forced-colors)で、キーボードフォーカスの位置が見えなかった問題を修正(WCAG 2.4.7)**: DS のフォーカス表示は `outline-none` + `ring`(box-shadow)で描いていて、forced-colors ではブラウザが box-shadow を描かず outline も無いため、Tab で動かしても現在地がどこにも出なかった(Chromium の forced-colors エミュレーションで Button が `outline-style: none` のままなことを実測)。`forced-colors:` でだけ実線 2px の輪郭線(`Highlight`。ブラウザ標準のフォーカスリングと同じ色)を出す。`FOCUS_RING` / `FOCUS_RING_WITHIN` / `FOCUS_RING_INSET` が含むので、それらを使う Button / Input / Textarea / Select / Checkbox / CheckboxGroup / CheckboxCard / RadioGroup(タイル・chip)/ Slider / NumberInput / SearchBar / FileInput / DataTable の並び替え見出し / Combobox / MultiSelect / DatePicker / Pagination / Chip / ContentCard / ImageUploader ほか全部が直る。リングを自前で書いていた `Switch` / `Toggle` / `ToggleGroup` / `Accordion` / `ListItem` / `ImageCarousel` / `ProductCarousel` / `ProductOption`(セレクト・画像アップロード)/ `SkipLink` / `ScrollArea` / `NavigationMenu` / `Chip`(削除可能の本体)/ `ChatComposer`(枠)/ `DataTableInputCell`(セル)/ `Calendar` の年月ドロップダウンは、`FORCED_COLORS_FOCUS` 系を足した(`FOCUS_RING_ONLY` を使う部品は定数が含む)。**`forced-colors` 以外では何も効かないため通常表示は変わらない**(outline-style も従来どおり。実ブラウザのテストで固定)。`FORCED_COLORS_FOCUS` / `FORCED_COLORS_FOCUS_WITHIN` / `FORCED_COLORS_FOCUS_INSET` は consumer が自前の `focus-visible:ring-*` に足せるよう root から公開した
|
|
106
|
+
- **Windows のハイコントラスト(forced-colors)で、メニュー項目の選択位置が分からなかった問題を修正**: `DropdownMenu` / `ContextMenu` / `Menubar` / `Select` の項目は `focus:bg-accent`(薄い地)で選択位置を示すが forced-colors では地が Canvas に置き換わる。さらに `outline-hidden` は forced-colors で常時 2px の輪郭線を出すため、全項目に枠が付いて選択位置は黒と濃い紫の差しかなかった(実測)。項目を `outline-none` にし、フォーカス中の項目を `Highlight` の地 + `HighlightText` で塗る(アイコン・ショートカット・destructive も同じ。OS 標準のメニューと同じ見え方)。`Command` も選択中の項目を同様に塗り、検索欄はフォーカス時に内側の輪郭線を出す。通常表示は変わらない
|
|
107
|
+
- **`TabsContent`(キーボードでフォーカスできるパネル)に、通常表示でもフォーカス表示が無かった問題を修正(WCAG 2.4.7)**: Radix の `TabsContent` は `tabindex=0` で、以前は `outline-none` のみ(リングも輪郭線も無し)のため、Tab で届いても現在地が分からなかった。キーボードでフォーカスしたとき(`focus-visible`)だけ DS 共通の `FOCUS_RING`(緑のリング。forced-colors では輪郭線)を出す。**静止時・マウスのクリックの見た目は変わらない**。キーボードでパネルに届いたときだけ緑のリングが出る
|
|
108
|
+
- **フォーカス表示が `overflow` のある祖先に切り取られて見えなかった問題を修正**: `TabsTrigger`(TabsList の `overflow-x-auto` が外側の輪郭線を全辺切り取っていた。main でも同じ)、`ToggleGroupItem`(ToggleGroup の `overflow-x-auto` が左右を切り取る)、`overflow-hidden` の角丸グループ(カード内に並べた行)に入れた `ListItem`(リング・輪郭線の左右が切れる)を、**内側に描く**ようにした(リンクの `ListItem` は、フォーカスを受ける `<a>` が不透明な行に覆われるので、リング・輪郭線は行側に描く)。静止時の見た目は変わらない。**キーボードでフォーカスしたときの表示が外側から内側(枠の内側のリング・輪郭線)になり、切れずに見えるようになる**。`SearchBar` の検索ボタンは、高さを親の枠(border 1px)の内側いっぱい(`h-full`)にした(枠と同じ高さだったため、上下 1px が親の `overflow-hidden` に切られ、内側のリング・輪郭線も 1px 切れていた。切れていた分は元から見えないので静止時の見た目は変わらない)。`Command` の検索欄は forced-colors の輪郭線を、`input`(h-10)ではなく枠(h-9)に付けた(`input` に付けると枠からはみ出して Command 本体の `overflow-hidden` に上辺が切られていた)
|
|
109
|
+
- メニュー項目の定数 `FORCED_COLORS_MENU_ITEM` / `FORCED_COLORS_COMMAND_ITEM` も root から公開した(consumer が独自のメニュー・コマンドで使える)
|
|
110
|
+
|
|
111
|
+
3 部品が、どこにも定義の無い CSS 変数を参照していて、背景が描かれていなかった。タイプミス・存在しないトークンは Tailwind の任意値(`bg-[var(--X)]`)ではビルドも型検査も通り、宣言が黙って無効になるだけで気付けなかった。**見た目が変わる**: 描かれていなかった背景が、コードの意図どおり描かれるようになる。公開 API の変更はなし。
|
|
112
|
+
|
|
113
|
+
- **`AdminSideNav` の SP ドロワーの背面スクリムが描かれていなかった問題を修正**: `bg-[var(--Primitive-Black-alpha-1000)]/40` の `--Primitive-Black-alpha-1000` は未定義だった。`Dialog` / `AlertDialog` / `Sheet` / `Drawer` と同じ標準のスクリム `--Overlay-Medium` に直し、ドロワーの後ろに Sheet と同じスクリムが掛かる。ライトは黒 60%(`rgba(0, 0, 0, 0.6)`)、ダークは白 20%(`rgba(255, 255, 255, 0.2)`)。コードが当初意図した黒 40% より、ライトはやや濃い
|
|
114
|
+
- **`ImageUploader` の番号バッジが白文字だけで読めなかった問題を修正**: 同じく未定義の `--Primitive-Black-alpha-1000`(60%)だった。黒 60% の `--Primitive-Gray-alpha-600`(`#00000099`)に直し、サムネイルの左上に黒 60% の地が付く。テーマで切り替えず、ライト・ダークとも同じ
|
|
115
|
+
- **`MissingComponent`(「DS未実装」の目印)のラベルの地が描かれていなかった問題を修正**: 未定義の `--Primitive-Red-500` だった。必須バッジなどと同じ `--Surface-Caution`(`rgb(236, 0, 0)`)に直し、赤地に白文字で表示される。ライト・ダークとも同じ
|
|
116
|
+
|
|
117
|
+
### 🛠 Tooling
|
|
118
|
+
|
|
119
|
+
- **CI のジョブに `timeout-minutes` を付け、ハングしたテストを打ち切って 1 回だけ再実行する**: 2026-10-13 の PR #314 の run 38417241202 で、Interaction テストが「全件 passed のまま応答が止まり」45 分以上動き続けた(通常は約 2 分。手で取り消した)。ジョブに制限が無く、Actions の既定(360 分)まで時間を使い続ける状態だった。同じ run のジョブログには、最後のテスト出力の約 2 秒後に runner の警告「You are running out of disk space … Free space left: 0 MB」が出ている(ディスクを埋めていたのは Chromium の共有メモリで、下の「原因を特定して直した」で対策)。2 回目のハング(run 38431848172)も同じ警告が出ており、打ち切り → 再実行で通過した。
|
|
120
|
+
- `ci.yml` の `check` 30 分 / `interaction-webkit` 25 分 / `vrt` 25 分(それまで 30 分)、`publish.yml` 15 分、`deploy-storybook.yml` 15 分、`deprecate.yml` 5 分。値は 2026-10-13 の成功 run の所要時間(`check` 370〜561 秒 / `interaction-webkit` 218〜262 秒 / `vrt` 125〜141 秒 / `deploy-storybook` 73〜107 秒 / `publish` 98〜105 秒 / `deprecate` 14 秒)の約 3 倍。`ci.yml` の 3 ジョブは、決定的にハングして「2 回続けて打ち切り → `::error::` + 終了コード 124」になる場合(テストのステップの開始 + 約 20.3 分)でも、その前にジョブ上限で切れない値にした(`interaction-webkit` と `vrt` は当初 20 / 15 分で、レビューの実測で足りないと分かり 25 分)。`vrt-update.yml` と `visual-review-label.yml` は既に付いていたので据え置き(`vrt-update.yml` の撮り直しは成功 run が無く実測できていない)
|
|
121
|
+
- `scripts/ci-retry-infra-flake.sh` に、テスト 1 回あたりの制限時間を追加(既定 600 秒。環境変数 `CAKE_CI_ATTEMPT_TIMEOUT_SECONDS` で変更、`0` で制限なし。`CAKE_CI_KILL_AFTER_SECONDS` は TERM で止まらないときの KILL までの猶予で既定 10 秒)。GNU coreutils の `timeout`(Mac の Homebrew では `gtimeout`。どちらも無い環境では制限なしで動き、stderr に知らせる)で打ち切る。npm が TERM で先に終わると `timeout` もすぐ 124 で終わって `-k` の KILL が送られず、TERM を処理できない vitest 本体が出力のパイプを握ったまま残って `tee` が終わらない(実測)ため、`timeout` の終了後にそのプロセスグループへ自分で KILL を送って片付ける
|
|
122
|
+
- 打ち切ったとき、`Tests` 行の `failed` / `AssertionError` / `Vite unexpectedly reloaded a test` が無ければ「ハング」として 1 回だけ再実行し、`::warning title=ハングで打ち切って再実行します::` を残す。2 回続けて打ち切られたら `::error::` を出して終了コード 124 で失敗。既存の接続の一時的な失敗の再実行条件(接続の文言あり・Vite 再最適化は再実行しない・アサーション失敗は再実行しない)は変えていない
|
|
123
|
+
- `__tests__/ci-retry-infra-flake.test.ts` に、ハング→再実行して成功 / 2 回続けて打ち切り→失敗 / TERM を無視して止まる npm を KILL で止めて再実行 / npm は TERM で終わるが TERM を無視する子が出力のパイプを握り続ける形でも待たされない / 打ち切り時に AssertionError・`Tests` 行の failed・Vite 再最適化があれば再実行しない / 制限時間内の 137 はハングとして扱わない / 制限時間の環境変数の誤り / `timeout` が無い環境、を追加。ハングのテストは `timeout`(または `gtimeout`)が無いローカルでは飛ばし、CI(`CI=true`)では無いこと自体を失敗にする
|
|
124
|
+
- 失敗・取り消し(ジョブの timeout を含む)のときだけ、ディスク使用量(`df -h` / `df -i` と、作業ディレクトリ・`~/.cache`・`~/.npm`・`/tmp` の上位)を出す診断ステップを `ci.yml` の各ジョブの最後に追加(`scripts/ci-diagnose-disk.sh`。常に終了コード 0 で、結果は変えない)。きっかけの run 38417241202 の check ジョブは、最後のテスト出力の約 2 秒後に runner の警告「You are running out of disk space … Free space left: 0 MB」が出ており、何がディスクを埋めたかを次に起きたとき追えるようにする
|
|
125
|
+
- 手順は `CLAUDE_DEV.md`「CI で interaction が … 落ちたとき」の末尾に追記(ハングの警告が出たら、まずジョブログで `running out of disk space` を探す)
|
|
126
|
+
- **画像比較(VRT)を新設**(`vitest.vrt.config.ts` / `__tests__/vrt/` / CI の `vrt` ジョブ): `tags: ["vrt"]` を付けたストーリー(主要部品の代表 30 件。`Button` の全 variant と disabled、`Input` / `Select` / `Checkbox` / `RadioGroup` / `Switch` / `Slider` / `Tabs` / `Badge` / `Card` / `Alert` / `Chip` / `Tag` / `PriceDisplay` / `ProductCard`、開いた `Dialog` / `DropdownMenu`、表示中のトースト)を light / dark の 2 テーマで撮り、`__tests__/vrt/baselines/` の基準画像(60 枚)と比べる。`@storybook/addon-vitest` + vitest browser の `toMatchScreenshot` で、テーマはブラウザの `prefers-color-scheme` で切り替える。画面 1024×640・Date 固定・外部画像はチェック柄に差し替え・動きを減らす設定でアニメーションの終了を待って撮る。重なりのあるストーリーは画面全体、それ以外はストーリーの枠だけを撮る。色の許容差は 0(トークン 1 段分の色変更も検出する)。揺れるストーリーだけ `parameters.vrt`(`allowedMismatchedPixels` 0〜50 / `threshold` 0〜0.02、`reason` 必須。全体・メタへの指定は失敗)で個別に許容できる
|
|
127
|
+
- 基準画像は Playwright 公式コンテナ(`mcr.microsoft.com/playwright:v1.58.2-noble`・digest 固定・linux/amd64)の中でしか作らない(設定がコンテナの外では失敗する)。ローカルは `npm run test:vrt:docker`(撮り直しは `-- --update`)
|
|
128
|
+
- 見た目を意図して変えた PR は、手動 workflow `vrt-update.yml`(`gh workflow run vrt-update.yml -f ref=<ブランチ>`)で基準画像を撮り直して PR のブランチへコミットする。main・タグ・SHA は拒否(既定ブランチ名が取れないときも拒否)、`persist-credentials: false`、`npm ci --ignore-scripts`、actions は SHA 固定。撮影は読み取り権限だけのジョブで行い、書き込み権限のジョブはリポジトリのコードを実行せず、名前・中身を検査した PNG だけを置いて push する
|
|
129
|
+
- 対応するストーリーが無くなった基準画像(孤児)は `npm run check`(`scripts/check-vrt-baselines.mjs`)が失敗にする
|
|
130
|
+
- `DropdownMenu` とトーストの開いた状態は、play で開く VRT 専用のストーリー(`tags: ["vrt", "!test", "!autodocs"]`。interaction / a11y のテストからは外す)を足した。既存ストーリーには `tags` を足しただけで中身は変えていない
|
|
131
|
+
- 参照元: KSK #641(baseconnect DS の `tooling/vrt`・stract-ui #211)。KSK の「静的 Storybook + 自前の比較スクリプト」ではなく、cake の既存の vitest browser 構成に合わせた
|
|
132
|
+
- **`lint:contrast` に高コントラストの 2 モードを追加**: 属性(`[data-contrast="more"]`)と OS 設定(`@media (prefers-contrast: more)`)を別々の層・モードとして、**許容リストを使わず**全ペアが 3:1 以上であることを要求する(既定モードの #301 の例外はそのまま。枠で境界を示す操作部品 6 件とフォーカスリング 6 件の計 12 件を追加登録)。片方の宣言漏れがもう片方の値に隠れて通らない。`BLOCK_TARGETS`(4 行)・`modes`(2 要素)・各ペアの `highContrast`(切り替え先の新ロール)で定義し、新ロールの宣言漏れは例外やスタックではなく `❌ <モード>:<テーマ>:<id>` の形で失敗する
|
|
133
|
+
- **新ロールの契約テスト `contrast-more-tokens.test.ts`**: 新ロールが高コントラストの 4 ブロックでだけ宣言されていること(`:root` / `.dark` に無い)、`src` 内の参照がフォールバック付きの許可した形だけであること、`tokens.json` と `preset-standalone.css` が `semantic.css` と一致すること、リングのフォールバックが従来の `ring-[var(--Focus-High-Emphasis)]/50` と同じ `color-mix` であることを固定する。リングだけの 50% 直書き(`ring-[var(--Focus-High-Emphasis)]/50`)は枠の指定がないとテストが落ちる
|
|
134
|
+
- **実ブラウザのストーリー検査 `StyleGuide/HighContrast`(`interaction`)**: 既定・`data-contrast="more"`・dark・`.dark` と `data-contrast` が別要素の組み合わせで、枠・溝・輪郭・フォーカスリングの計算値が期待どおり切り替わる(既定は従来の変数と同じ値のまま)ことを確認する。`@media (prefers-contrast: more)` の経路は `__tests__/browser/contrast-more.test.tsx`(`npm run test:forced-colors`。CDP で OS の設定をエミュレート。`preset-standalone.css` も検査)で確認する
|
|
135
|
+
- **forced-colors のフォーカス表示テストを追加**: 実ブラウザ(`npm run test:forced-colors`)で各部品へ実際に Tab で到達し、フォーカスを描く要素の outline が none でない(幅 > 0)ことを 48 ケース(部品・状態)+ メニュー 5 種で確認する。メニュー項目は選択位置が Highlight で塗られ、ほかの項目に常時の輪郭線が出ないことを見る。通常表示は outline-style が従来どおりであることも同じケース表で確認する(修正前のコードで forced-colors の 44 ケースが落ちることを確認)。node 側の `__tests__/forced-colors-focus-source.test.ts` は、リング定数が forced-colors 用のクラスを含むこと、`outline-none` + `ring` で自前のフォーカス表示を書いたファイルに forced-colors 用のクラスがあること、`outline-hidden` を常時(バリアントなし)で付けていないことを `npm test` で止める
|
|
136
|
+
- **見た目に効く変更を含む PR に `needs-visual-review` ラベルと変更箇所のコメントを自動で付ける**(`.github/workflows/visual-review-label.yml` / `scripts/detect-visual-changes.mjs`): 画像比較(VRT)が撮るのは `tags: ["vrt"]` の主要部品の代表ストーリーだけで、それ以外の部品・状態の枠線の色・フォーカスリング・影の微差は CI をすり抜けるため、マージ前に Storybook で目視確認するきっかけにする。枠線 / フォーカスリング / 影 / 色(`--Surface-*` `--Text-*` 等、`bg-accent` `bg-border` など shadcn 系の意味色、`text-red-500` など色パレット)/ 角丸(`--radius` 含む)/ 余白 / **variant 切替**(`variant="secondary"` → `"tertiary"`、`defaultVariants`、`<Card surface=…>` など、クラス名が変わらずに見た目が変わるもの)を、src の差分行と `tokens.json`(color・shadow・radius・spacing の構造比較)から判定し、見た目の変更が無くなればラベルとコメントを自動で解除する(外すのは workflow が付けたときだけ)。比較の起点は event の `base.sha` ではなく最新の base ブランチ先頭との merge-base(PR が main を取り込んでも main 側の変更を拾わない)。クラス名が同じままのタグ名の変更・再インデント・props の追加や折り返しは拾わず(クラスが別の要素へ移った・入れ替わった変更は拾う)、`preset.css` の `--breakpoint-*` / `--container-*`(consumer の `md:` / `lg:` の切り替え位置や `max-w-*` の実寸)の定義変更は「レイアウトの基準」として拾う。ラベルを外すのは「検出中」の bot コメントがあるときだけで、いったん解除した PR に後から手で付けたラベルも外さない。`pull_request` トリガのみ(fork と Dependabot はスキップ)、権限は最小。必須 check ではなくマージは止めない。運用は `CLAUDE_DEV.md`「見た目の目視確認ラベル」(姉妹 DS ksk-design-system #643 の移植)
|
|
137
|
+
- **配布する AI 向けルール文書の参照・数値整合を `consumer-ref-integrity.test.ts` で検査**: ルート `CLAUDE.md` の必読表のパスが実在して `files` で配布されること、`templates/CLAUDE.md` と `templates/AGENTS.md` の必読表が揃っていること、`@cakejp/design-system/<subpath>` と `npx cakejp-ds <コマンド>` の案内が実体と合うこと、文書中のコンポーネント件数・角丸の許可セットと px 値・ルール ID・JSON パス参照(`` `tokens.json` の `radius.*` `` 等)が `meta.counts` / `rules.json` / `tokens.json` / `preset.css` と一致することを固定した。読み取りは `scripts/ai-rules-docs.mjs`(単体テスト `__tests__/ai-rules-docs.test.ts`)
|
|
138
|
+
- **表示設定・寸法の実ブラウザテストを新設**(`npm run test:forced-colors` / `vitest.forced-colors.config.ts`): Storybook を介さず部品を直接描画し、CDP で forced-colors / prefers-reduced-motion、`page.viewport()` で画面幅を切り替えて検査する(play 関数からは CDP を呼べないため別設定)。テストは `__tests__/browser/**`(node 環境の `npm test` からは除外)。上記の修正を固定し、修正前のコードで 33 件が落ちることを確認した。CI の `check` ジョブに 1 ステップ追加
|
|
139
|
+
- **未定義 CSS 変数の参照検査 `npm run lint:css-vars` を追加(`npm run check` に含む)**: `src/**/*.{css,ts,tsx}`(ストーリーを含む)の `var(--X)` と Tailwind v4 の括弧記法 `bg-(--X)` が、`src` 内のどこかで定義されているかを `file:line` 付きで検査する。
|
|
140
|
+
- フォールバック付き `var(--X, 値)` も、`--X` がどこにも定義されていなければ失敗する(フォールバックがタイプミスを隠すため)
|
|
141
|
+
- 定義は「無条件」(`:root` / `@theme` 直下など)と「条件付き」(`@media` / `@supports` / `@container` / `@starting-style` / `@variant` / `@utility` の中、`.dark` など)に分ける。条件付きの定義しか無い変数を、その条件の外でフォールバック無しで参照すると失敗する(通常時は未定義のまま描かれないため)。`var(--Border-Control, var(--Border-Medium-Emphasis))` のようにフォールバック付きなら通る。定義と同じ条件(またはその内側)にある参照も通る(`.dark { --D: #000; --A: var(--D) }`、`dark:[--X:red] dark:bg-[var(--X)]` など)。「内側」の判定は、迷うときは含まれない(= フォールバックを要求する)側に倒す(子孫・子 `>` の先だけが内側で、兄弟結合子 `~` `+`・`.dark.foo` のような複合・`:not()` などの中に現れるだけのものは含まれない。`dark:` バリアントは `.dark` / `:root.dark` / `html.dark` の定義だけを参照できる)
|
|
142
|
+
- Tailwind v3 の記法 `bg-[--X]` は v4 では `var()` に展開されず無効になるため、定義の有無に関係なく失敗する(`bg-(--X)` か `bg-[var(--X)]` に直す)。不透明度の変数指定 `bg-[var(--A)]/(--X)` の `(--X)` も検査する
|
|
143
|
+
- `src/preset-standalone.css`(手保守の展開コピー)は共有の定義プールに入れず、単独で自分の参照が自分の中で定義されていることを別に検査する
|
|
144
|
+
- Radix が実行時に注入する `--radix-*` 15 種は完全一致の許可リストで通す(前方一致は不可。参照が消えた項目も失敗する)
|
|
145
|
+
- 参照元: KSK #639(baseconnect #137)
|
|
146
|
+
- **`lint:contrast` に非テキストの 3:1 検査(WCAG 1.4.11)を追加**: 入力欄・エラー・フォーカスの枠、チェックボックス・ラジオ・スイッチ・スライダーの枠/地/つまみ、入力用の星、リングだけのフォーカスを、部品が実際に使うトークンの組で light / dark の両方検査する。3:1 未満のものは、**色は変えずに**許容リストへ登録して回帰だけ止めている(既定を濃くするかは [#301](https://github.com/flashpark/cake-design-system/issues/301) で判断)。
|
|
147
|
+
- 既定枠 `Border-Medium-Emphasis`: Checkbox / CheckboxGroup / CheckboxCard / RadioGroup タイル / SearchBar / NumberInput(size=md)/ ReviewForm の星(light 1.41 / dark 1.66)
|
|
148
|
+
- 枠なしの塗りだけ: Slider の溝・NumberInput(size=sm)の丸型(light 1.12 / dark 1.66)、Combobox / MultiSelect のトリガー(1.00)
|
|
149
|
+
- 50% のリングだけで枠が変わらない: Switch / SearchBar・ImageUploader の内側リング / ListItem / ImageCarousel・ProductCarousel / ProductOption の画像アップロードボタン(light 1.82 / dark 2.17)
|
|
150
|
+
- **検査ペアと部品のソースを照合するテストを追加**: 各ペアが、その状態を表す className の部分文字列(`match`)で部品のソースとつながっていることを確認し、部品側のトークン変更に検査が置き去りにされないようにした。50% のリングだけでフォーカスを示す部品が `focus-ring-*` のペアから漏れていないかも src 全体の走査で確認する。CSS 変数は層(base / dark)ごとに集め、`BLOCK_TARGETS` に登録していないブロックは置く位置によらず失敗する。高コントラスト用のモードは、発火条件(属性 / `@media`)ごとに `BLOCK_TARGETS` 4 行 + `modes` 2 要素で足せる(条件を 1 つの層に混ぜる・`@media` を通常のブロックより前に置く・`layers` の順がソース順と食い違う・層名の打ち間違いは失敗する)。`check-contrast.mjs` は知らない引数・値のない `--today` を終了コード 2 で拒否する。
|
|
151
|
+
- **許容リストに期限を導入**: 非テキストの例外は `issue` と `reviewBy` が必須。`reviewBy`(初回は 2027-01-11)を過ぎると失敗し、30 日前から警告する。基準を満たしたのに残っている例外(不要になった例外)も失敗にする。旧形式の文字ペアの例外 5 件は互換のまま期限を付けず(`reviewBy` は任意)、追跡は [#308](https://github.com/flashpark/cake-design-system/issues/308)。部品・トークンの色や公開 API の変更はなし。
|
|
152
|
+
- **interaction テストを WebKit(Safari 系)でも実行できるようにした**: 実行ブラウザを環境変数 `CAKE_BROWSER`(`chromium` が既定 / `webkit`)で切り替える(`vitest.storybook.config.ts` / `vitest.a11y.config.ts`。それ以外の値は設定の読み込みで失敗する)。`npm run test:interaction:webkit` / `npm run test:a11y:webkit` を追加。初回のみ `npx playwright install webkit`
|
|
153
|
+
- CI に `interaction-webkit` ジョブを追加(`check` と並列。Playwright WebKit で interaction だけを回す)。a11y(axe)は DOM 構造の検査でエンジン差が出にくく、全件で時間が倍になるため CI には入れない(ローカルで `test:a11y:webkit`)
|
|
154
|
+
- play 関数の非同期待ち(`waitFor` / `findBy*`)の既定タイムアウトを 1 秒 → 5 秒にした(`.storybook/preview.ts` の `beforeAll` で `asyncUtilTimeout` を設定)。CI の Linux WebKit で AlertDialog の退場待ちが 1 秒を超え、`confirm-dialog.stories.tsx` が偽陽性で落ちたため。待ちは条件を満たした時点で終わるので速い環境の所要時間は変わらず、伸びるのは本当に失敗するテストの失敗までの時間だけ
|
|
155
|
+
- WebKit で見つかった差を直した: `Button` の loading ストーリーが `forced-color-adjust` の宣言を CSSOM から読んでいたが、WebKit はこのプロパティを持たず宣言ごと捨てるため、対応しているエンジンでだけ確かめる(`CSS.supports`)。部品の挙動は変えていない
|
|
156
|
+
- CI の `paths-ignore` を追加: `docs/**` と `CHANGELOG.md` / `PUBLISHING.md` / `RELEASE.md` だけの変更では CI を起動しない(CLAUDE.md / AGENTS.md / CLAUDE_DEV.md / README.md / templates / guidelines / `.claude` などは check と単体テストが中身を検査するので対象外。CLAUDE_DEV.md は `consumer-ref-integrity` が件数・角丸・ルール ID を検査する)
|
|
157
|
+
- CI の interaction が「Failed to fetch dynamically imported module」「Cannot connect to the iframe」で落ちた件を調べた。Vite の依存再最適化が原因なら vitest が `Vite unexpectedly reloaded a test` を出すが、落ちた run のログには無く、冷間キャッシュ・CPU 負荷下のローカル再現でも再最適化は起きなかった(依存の事前スキャンは Storybook の builder が story と preview を entries に入れて自動で行う)。そのため `optimizeDeps.include` の手書き一覧は置かず、切り分け手順を CLAUDE_DEV.md に書いた
|
|
158
|
+
- CI の interaction(`check` / `interaction-webkit`)・a11y・forced-colors を `scripts/ci-retry-infra-flake.sh` 経由で実行するようにした。テストの失敗が無いのに `Failed to fetch dynamically imported module` / `Cannot connect to the iframe`(WebKit では `Importing a module script failed`)だけで落ちたときに限り 1 回再実行し、`::warning::` で残す(アサーションの失敗と、Vite の依存再最適化=`Vite unexpectedly reloaded a test` は再実行しない。頻発したら原因調査に戻る)。条件は `__tests__/ci-retry-infra-flake.test.ts` で固定
|
|
159
|
+
- **CI の interaction がハング・「Failed to fetch dynamically imported module」「Cannot connect to the iframe」で落ちていた原因を特定して直した**(`vitest.storybook.config.ts` / `vitest.a11y.config.ts` / `scripts/lib/browser-tests.mjs` / `__tests__/browser-setup/collect-garbage.ts`): 2026-10-13 の `check` ジョブ 70 本のうち 10 本で、interaction の 1 回目が開始 70〜86 秒後に落ちるか止まっていた(うち 3 本は同じ時刻に runner の「running out of disk space」警告)。原因は Chromium の共有メモリ: テストファイルごとに作る iframe で 2MB の共有メモリを数十本(1 ファイル約 150〜190MB)確保し、GC まで解放しない。Playwright の既定 `--disable-dev-shm-usage` でこれが `/tmp`(ディスク)に先取りで確保され、interaction(186 ファイル)で最大 3374MB、a11y(125 ファイル)で 2456MB まで積み上がって runner のディスクの空きを使い切っていた(Chromium が確保に失敗して読み込みが落ちるか、描画プロセスが落ちて vitest が待ち続ける)。
|
|
160
|
+
- interaction は、`'interaction'` の文字列を含まないストーリーファイルを読み込まない(186 → 18 ファイル。`vitest.vrt.config.ts` と同じ exclude 方式)。interaction の所要時間も短くなる。**ストーリーの `tags` には `'interaction'` を直接書く**(別ファイルの定数・スプレッドで書くと、`__tests__/browser-tests.test.ts` が CSF の静的解析で失敗にする)。
|
|
161
|
+
- interaction と a11y は、Chromium を `--js-flags=--expose-gc` 付きで起動し、各テストファイルの開始時に `gc()` を呼ぶ setup を足した(WebKit は起動フラグを足さず、`gc()` も呼ばない)。`/tmp` の最大は interaction で約 50〜80MB、a11y で 158MB になった。Chromium なのに `gc()` が無い(起動フラグが外れた)ときは setup が失敗してテストが落ちる。CI の所要時間は interaction が 71〜105 秒 → 50 秒、a11y が 55〜93 秒 → 151 秒(`gc()` の分。check ジョブ全体は 635 秒)。a11y の `gc()` は予防(a11y は 70 本で異常 0 件だが、同じ積み上がりがある)。`--disable-dev-shm-usage` は外さない(共有メモリを `/dev/shm` に移すと 3GB 級が runner の RAM を圧迫し、`/dev/shm` が尽きると SIGBUS で落ちうる)。
|
|
162
|
+
- `/tmp` を 1.5GB に制限した docker(1 並列)で、修正前は 3 回中 3 回ハング、修正後は 12 回連続で完走(手順は `CLAUDE_DEV.md`「CI で interaction が … 落ちたとき」)。配線は `__tests__/browser-tests.test.ts` で固定。
|
|
163
|
+
|
|
164
|
+
### 📝 Docs
|
|
165
|
+
|
|
166
|
+
- **`ResponsiveDialog` の契約の記述を実装に合わせた**: SP で切り替わるのは Sheet ではなく Drawer(下部のボトムシート)。`contracts/components.json` と `contracts/screen-patterns.json` の「モバイル=Sheet」を直した(挙動の変更なし)
|
|
167
|
+
- **`templates/AGENTS.md`(Codex 向け)の必読表に `contracts/screen-patterns.json` と `contracts/composition.json` を追加**: `templates/CLAUDE.md` には載っていたが Codex 側には無く、consumer の Codex だけ画面パターン・ページ骨格の判断基準を読まされていなかった。npm の配布物(`templates/`)の変更なので、consumer が `npm update` すると反映される
|
|
168
|
+
- **文書からコンポーネント件数を外し、件数の正本(`contracts/components.json` の `meta.counts`)を参照する書き方にした**: `templates/*.md` は「125」、ルート `AGENTS.md` は「113」(内訳 47/42/24)、`CLAUDE_DEV.md` は 46/35/23、`ds-judgment` は「106」、`README.md` は「104 個」と層別の表(46/35/23)、`MIGRATION.md` は 46/35/23 と、実数(126 = 51/51/24)からそれぞれズレていた。ルート `CLAUDE.md` と `src/components/pages/README.md` の「EC 19画面・管理 30画面」も、`pages/admin/` のストーリーが 31 本あり数え方が揃っていなかったため件数を外した。consumer に配る文書(`templates/*.md`・ルート `CLAUDE.md`)には「件数は `meta.counts`」と添えた。`README.md` と `MIGRATION.md` は npm に載るため、次回リリースで反映される
|
|
169
|
+
- `ds-judgment` Skill(`.claude/` と `.agents/` のミラー)の「コンポーネント増減時の同期義務」から、#168 で廃止済みの `mcp-server/data/*.json`(手動コピー)の手順を外し、MCP は `contracts/*.json` を直読みする旨に直した
|
|
170
|
+
- ルート `AGENTS.md`(Codex 向け・開発者用)の「重要な制約(AI生成コードの典型的な誤り)」は、`CLAUDE.md` の一覧の写しをやめ、正本(`CLAUDE.md` の「AI 生成コードの典型的な誤り」の節と `contracts/rules.json` の `aiPatterns`)への参照にした。写しは `CLAUDE.md` より 8 項目少なく、`input type="date"` の案内も古い(Popover と Calendar を組み合わせる)ままだった。セッション開始時の読み込みリストにも `CLAUDE.md` を足した。`AGENTS.md` が独自の一覧を持たないこと・参照先の節が実在することは `consumer-ref-integrity.test.ts` で固定
|
|
171
|
+
- `src/components/pages/README.md` の「`cake/_mypage-shell.tsx`」は実体が `src/components/ec/mypage-shell.tsx` のため直した
|
|
172
|
+
- **AI 向けルールに「確認は `useConfirm`」「処理中のボタンは `loading`」を追記**: consumer に配る AI 向けルール(`templates/CLAUDE.md` / `templates/AGENTS.md` の「書く前に必ず確認するパターン」)、`CLAUDE.md` の「AI 生成コードの典型的な誤り」、`contracts/rules.json` の `aiPatterns`(AI8 `window.confirm` / AI9 処理中ボタンの自作)、`contracts/screen-patterns.json` の dialog パターンに追加。`guidelines/components/button.md` の処理中の例も `disabled` + `Spinner` から `loading` に差し替え
|
|
173
|
+
- **`AlertDialog` の説明表の誤りを修正**: 「ESCキー: 閉じない」と書いていたが、実際は Esc で閉じる(キャンセル扱い)
|
|
174
|
+
- **ストーリーの未定義トークン参照を修正**: `Pages/Cake/Dialogs` の削除確認 2 件は存在しない `--Primitive-Red-600/700` で地が描かれていなかったため `AlertDialogAction variant="destructive"` に、`Pages/Cake/MyPage` の注文ステータスバー(緑)は `--Surface-Success-Light` を `--Primitive-Forest-50`(`Badge success-subtle` と同じ地)に、`StyleGuide/ProhibitedPatterns` の警告バッジは `--Surface-Warning-Light` を `--Surface-Warning` に、`Foundations/Button` の Inverse 系は未定義の `--Brand-Cake-Magenta`(hex フォールバックで描画)を「暗背景」を表す `--Primitive-Gray-900` に直した。配布物(`dist`)には含まれない
|
|
175
|
+
- **`Primitives/AdminSideNav` の interaction テスト(InteractionFlyout)が CI で稀に落ちる問題を修正**: フライアウトの開閉は約 180ms のフェードイン(opacity 0 から始まる)で、`toBeVisible()` は opacity 0 を非表示とみなすため、開いた直後に判定すると落ちることがあった。2 箇所を `waitFor` で包んだ。部品の挙動は変わらない
|
|
176
|
+
|
|
177
|
+
### 🛡 Internal
|
|
178
|
+
|
|
179
|
+
- **`npm run lint`(eslint)のエラー 9 件を解消し、CI の実行対象に追加**: CI が lint を実行していなかったため `react-hooks/static-components`(render 中にコンポーネントを作る形)などが main に溜まっていた。`Footer` / `MenuDrawer` / `Pagination` / `ContentCard` / `SubNav` は、リンク実装を `resolveLinkComponent()`(関数呼び出し)で選ぶ形をやめ、`linkComponent ?? "a"` と渡された参照を選ぶだけの式に変更(内部 helper の `resolveLinkComponent` は廃止。公開 API ではない)。`linkComponent` の有無・指定時の DOM と再描画時の DOM 保持は変わらず、`__tests__/link-component.test.tsx` に `MenuDrawer` / `ContentCard` の差し替えと「未指定と素通し `<a>` で DOM が同一」「再描画でリンクの DOM が作り直されない」の検査を追加。あわせて `ImageGallery` から `reconcileImageIndex` を `src/lib/image-index.ts` へ移し(component ファイルの非 component export による react-refresh 違反の解消。root export ではなかったため公開 API は変わらない)、`admin-side-nav.stories.tsx` の未使用変数を除去。公開 API・既定の見た目・DOM の変更はなし
|
|
180
|
+
- **CI に `npm run lint -- --max-warnings 0` を追加**: `check` ジョブの先頭で eslint を実行し、error だけでなく warning の増加も PR 時点で止める(現状 warning 0 件)。`linkComponent` を他の部品へ広げるときの書き方(lint を通る形)は `src/lib/link-component.ts` のファイル内コメントに記載(公開型の JSDoc には出さない)
|
|
181
|
+
- `checkbox-card.tsx` に `"use client"` を追加(読み上げ名の分離で選択状態を内部 state で追うため)。Server Component から `CheckboxCardGroup` / `CheckboxCardItem` を描画する使い方はそのまま動く
|
|
182
|
+
- `Chip`(removable)の削除ボタンに `data-slot="chip-remove"` を追加(`MultiSelect` が削除後のフォーカスの移し先を探す目印。見た目は変わらない)
|
|
183
|
+
|
|
12
184
|
## [0.20.1] - 2026-09-03
|
|
13
185
|
|
|
14
186
|
### 🐛 Fixed
|
package/CLAUDE.md
CHANGED
|
@@ -18,12 +18,12 @@ PdM や社長が AI(Claude 等)で HTML モックを作る際、このパッ
|
|
|
18
18
|
| ファイル | 内容 | いつ読むか |
|
|
19
19
|
|---------|------|----------|
|
|
20
20
|
| **contracts/rules.json** | 禁止パターン・アクセシビリティ要件・ライティングルール | **コード生成前に必ず** |
|
|
21
|
-
| **contracts/components.json** | 全コンポーネントの定義(variants・rules・accessibility
|
|
21
|
+
| **contracts/components.json** | 全コンポーネントの定義(variants・rules・accessibility。件数は `meta.counts`) | コンポーネント利用・画面作成時 |
|
|
22
22
|
| **contracts/screen-patterns.json** | 画面パターン判断基準(CRUD・編集/作成/削除UIの選択) | 管理画面・編集/作成/削除UIを作る時 |
|
|
23
23
|
| **contracts/composition.json** | ページ骨格・余白リズム・視覚階層の組み方 | レイアウト・画面構成を組む時 |
|
|
24
24
|
| **tokens.json** | カラー・タイポグラフィ・スペーシング・影・角丸・モーション・重なり順 | トークン値を参照する時 |
|
|
25
25
|
| **CLAUDE_PRODUCTION.md** | 本番実装参照ルール・Figmaチェックリスト・本番サイト対応表 | 本番再現・新規画面作成時 |
|
|
26
|
-
| **src/components/pages/** | フルページ参照実装(EC
|
|
26
|
+
| **src/components/pages/** | フルページ参照実装(EC・管理画面、Storybook CSF 形式)。**npm 非同梱 — DS リポジトリ(private)を clone して参照** | 既存画面の改修・Next.js 移行で画面を実装する時。使い方は同ディレクトリの README.md |
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -105,7 +105,7 @@ PdM や社長が AI(Claude 等)で HTML モックを作る際、このパッ
|
|
|
105
105
|
| 浮遊レイヤーの地(メニュー・ポップオーバー・ダイアログ・シート) | `var(--Surface-Elevated)` |
|
|
106
106
|
| 成功 | `var(--color-green-500)` |
|
|
107
107
|
|
|
108
|
-
詳細は `tokens.json`
|
|
108
|
+
詳細は `tokens.json` を参照。高コントラスト(OS の「コントラストを上げる」か、`<html data-contrast="more">`。`#root` など Portal の外側の要素に付けると body 直下に描かれる Dialog / Popover / 選択肢の一覧には効かない)のときの枠・溝・フォーカスリングは DS が自動で切り替えるので、`--Border-Control` 等を自分で宣言・上書きしない。
|
|
109
109
|
|
|
110
110
|
---
|
|
111
111
|
|
|
@@ -127,3 +127,5 @@ PdM や社長が AI(Claude 等)で HTML モックを作る際、このパッ
|
|
|
127
127
|
- **大見出し**: 通常ページの主見出しは `typo-heading-3xl`(28px)を上限にする。`typo-heading-4xl`(32px)/ `typo-heading-5xl`(40px)は**LP・マーケティング系ヒーローの PC 表示限定**で、SP は `typo-heading-3xl` から段階を上げる。`SectionHeader` では `size="3xl"` に `desktopSize="4xl"` または `desktopSize="5xl"` を加える。手書きの `text-[32px]` / `text-[40px]` 等は禁止
|
|
128
128
|
- **画像・メディア上の操作ボタン**: `rgba(...)` の半透過下地を手組みしない — `--Surface-Overlay-Light`/`--Surface-Overlay-Dark` + `Button variant="overlay"` を使う
|
|
129
129
|
- **SectionHeader が担う「パターン」の手書き**: 禁止 — 次の2パターンは `SectionHeader` を使う。①「タイトル + もっと見る/すべて見るアクション」の並び、②中央寄せの大見出し(ランディング/ガイド系。`align="center"`、eyebrow に Badge 等)。**通常の文書見出し(`<h1>`〜`<h6>` 相当の素の semantic heading)まで SectionHeader に置き換える意味ではない** — 見出し単体なら `typo-heading-*` を付けた素の heading 要素でよい。正典は `contracts/components.json` の SectionHeader `rules`
|
|
130
|
+
- **window.confirm()**: 使用禁止 — `useConfirm` を使う。アプリのルートに `ConfirmDialogProvider` を 1 つ置き、`const ok = await confirm({ title, description, confirmLabel, tone })` で受け取る(中身は `AlertDialog`。削除等は `tone="destructive"` と動詞の `confirmLabel`)
|
|
131
|
+
- **処理中のボタン**: `disabled` + 自作スピナー(`Spinner` / `Loader2` + `animate-spin`)で組まない — `Button` の `loading` を使う(`<Button loading>保存</Button>`)。幅を保ち、フォーカスを保ったままクリック・送信を止め、読み上げ名に `loadingLabel`(既定「処理中」)を足す
|
package/MIGRATION.md
CHANGED
|
@@ -218,9 +218,9 @@ import { ProductCard } from '@/components/ec/product-card'
|
|
|
218
218
|
|
|
219
219
|
```
|
|
220
220
|
src/components/
|
|
221
|
-
├── foundations/ shadcn ベース汎用 UI
|
|
222
|
-
├── primitives/ 業界汎用パターン(
|
|
223
|
-
└── ec/ Cake.jp / EC
|
|
221
|
+
├── foundations/ shadcn ベース汎用 UI
|
|
222
|
+
├── primitives/ 業界汎用パターン(jobboard 等他事業でも再利用可)
|
|
223
|
+
└── ec/ Cake.jp / EC 事業特化
|
|
224
224
|
```
|
|
225
225
|
|
|
226
226
|
### 移行進捗の自己診断
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @cakejp/design-system
|
|
2
2
|
|
|
3
|
-
Cake.jp デザインシステム —
|
|
3
|
+
Cake.jp デザインシステム — React コンポーネント・カラートークン・タイポグラフィ。
|
|
4
4
|
|
|
5
5
|
## インストール
|
|
6
6
|
|
|
@@ -10,13 +10,21 @@ npm install @cakejp/design-system
|
|
|
10
10
|
|
|
11
11
|
## 使い方
|
|
12
12
|
|
|
13
|
+
<!-- consumer-example:tsx:start -->
|
|
13
14
|
```tsx
|
|
14
|
-
import { Button,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<
|
|
15
|
+
import { Button, Input, Label } from "@cakejp/design-system"
|
|
16
|
+
|
|
17
|
+
export function Example() {
|
|
18
|
+
return (
|
|
19
|
+
<form>
|
|
20
|
+
<Label htmlFor="recipient">お届け先のお名前</Label>
|
|
21
|
+
<Input id="recipient" name="recipient" defaultValue="山田 太郎" />
|
|
22
|
+
<Button type="submit">保存する</Button>
|
|
23
|
+
</form>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
19
26
|
```
|
|
27
|
+
<!-- consumer-example:tsx:end -->
|
|
20
28
|
|
|
21
29
|
### CSS のセットアップ
|
|
22
30
|
|
|
@@ -101,11 +109,13 @@ CommonJS へ変換)を果たせば代替可。
|
|
|
101
109
|
|
|
102
110
|
3-tier アーキテクチャ:
|
|
103
111
|
|
|
104
|
-
| レイヤー | 内容 |
|
|
105
|
-
|
|
106
|
-
| `foundations/` | shadcn ベース汎用 UI(Button, Input, Dialog 等) |
|
|
107
|
-
| `primitives/` | 業界汎用パターン(Header, SideNav, PriceDisplay 等) |
|
|
108
|
-
| `ec/` | Cake.jp / EC 事業特化(ProductCard, CouponCard 等) |
|
|
112
|
+
| レイヤー | 内容 |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `foundations/` | shadcn ベース汎用 UI(Button, Input, Dialog 等) |
|
|
115
|
+
| `primitives/` | 業界汎用パターン(Header, SideNav, PriceDisplay 等) |
|
|
116
|
+
| `ec/` | Cake.jp / EC 事業特化(ProductCard, CouponCard 等) |
|
|
117
|
+
|
|
118
|
+
コンポーネントの一覧と件数は `contracts/components.json`(件数は `meta.counts`)と `src/components/COMPONENT_LOOKUP.md` が正本です。
|
|
109
119
|
|
|
110
120
|
依存方向: `ec/` → `primitives/` → `foundations/`(逆方向 import 禁止、CI で検証)
|
|
111
121
|
|
|
@@ -175,3 +185,13 @@ npm run test:compat # 後方互換テスト
|
|
|
175
185
|
## ライセンス
|
|
176
186
|
|
|
177
187
|
UNLICENSED(社内利用)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
## DS開発者向けの配布物・SSR検査
|
|
191
|
+
|
|
192
|
+
`npm run check:consumer-types` は配布READMEの上記例と既存の公開型・RSC境界を検査します。
|
|
193
|
+
`npm run build:lib && npm run check:hydration` は配布物のNode SSR→Chromium hydrationと日付操作を検査します。初回は `npx playwright install chromium` が必要です。
|
|
194
|
+
|
|
195
|
+
DatePicker / DateTimePickerはJST運用を前提とし、ライブラリ内でタイムゾーン変換しません。SSRサーバーは `TZ=Asia/Tokyo`、ブラウザもJSTで同じ初期値を使用してください。日時はオフセット付きISO文字列(例 `2026-01-02T00:30:00+09:00`)を双方で同じ `Date` に復元します。オフセットは同じ瞬間を保証しますが、表示に使う実行環境のTZまでは変更しません。
|
|
196
|
+
|
|
197
|
+
UTCサーバーとJSTブラウザで日付をまたぐ値を描画する構成は、この日付部品のSSR対応範囲外です。検査ではその組合せの不一致を境界事例として検出します。日付だけの値も `new Date("YYYY-MM-DD")` はUTC解釈になるため、JSTへ揃えた環境で年・月・日から作るなど、双方で同じ解釈にしてください。SSRを無効化したり警告を抑止して整合性検査を通すことはしません。
|