@cakejp/design-system 0.12.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/CLAUDE.md +12 -5
  3. package/MIGRATION.md +45 -0
  4. package/UPDATING.md +13 -0
  5. package/bin/check-duplicates.mjs +133 -9
  6. package/bin/exports-parser.mjs +54 -0
  7. package/bin/init.js +3 -0
  8. package/contracts/components.json +504 -209
  9. package/contracts/composition.json +11 -8
  10. package/contracts/rules.json +354 -113
  11. package/contracts/screen-patterns.json +1 -1
  12. package/dist/index.css +1 -1
  13. package/dist/index.js +4285 -3422
  14. package/dist/types/components/ec/admin-shell.d.ts +30 -2
  15. package/dist/types/components/ec/product-detail-sidebar.d.ts +1 -1
  16. package/dist/types/components/foundations/card.d.ts +27 -3
  17. package/dist/types/components/foundations/field.d.ts +26 -3
  18. package/dist/types/components/foundations/input.d.ts +3 -1
  19. package/dist/types/components/foundations/social-icon.d.ts +33 -0
  20. package/dist/types/components/foundations/textarea.d.ts +3 -1
  21. package/dist/types/components/primitives/chat-composer.d.ts +87 -0
  22. package/dist/types/components/primitives/combobox.d.ts +24 -0
  23. package/dist/types/components/primitives/content-carousel.d.ts +7 -1
  24. package/dist/types/components/primitives/date-picker.d.ts +15 -3
  25. package/dist/types/components/primitives/funnel-shell.d.ts +2 -0
  26. package/dist/types/components/primitives/image-input.d.ts +119 -0
  27. package/dist/types/components/primitives/multi-select.d.ts +24 -0
  28. package/dist/types/components/primitives/notification-badge.d.ts +1 -1
  29. package/dist/types/components/primitives/number-input.d.ts +84 -0
  30. package/dist/types/components/primitives/section-header.d.ts +9 -2
  31. package/dist/types/components/primitives/section.d.ts +35 -2
  32. package/dist/types/components/primitives/social-login-button.d.ts +3 -1
  33. package/dist/types/components/primitives/timeline.d.ts +23 -0
  34. package/dist/types/components/primitives/workspace-shell.d.ts +2 -0
  35. package/dist/types/index.d.ts +25 -7
  36. package/dist/types/lib/pagination-range.d.ts +16 -0
  37. package/dist/types/lib/use-value-length.d.ts +31 -0
  38. package/eslint/deprecated.js +44 -0
  39. package/package.json +8 -3
  40. package/scripts/codemod/README.md +14 -0
  41. package/scripts/codemod/template.mjs +62 -0
  42. package/src/components/COMPONENT_LOOKUP.md +166 -0
  43. package/src/preset-standalone.css +16 -0
  44. package/src/preset.css +17 -0
  45. package/src/styles/typography.css +7 -0
  46. package/templates/AGENTS.md +4 -0
  47. package/templates/CLAUDE.md +4 -0
  48. package/tokens.json +933 -87
  49. package/dist/types/components/primitives/quantity-selector.d.ts +0 -50
@@ -1,5 +1,6 @@
1
1
  import * as React from "react";
2
2
  export type SectionHeaderSize = "3xl" | "2xl" | "xl" | "lg" | "md" | "sm";
3
+ export type SectionHeaderDesktopSize = "5xl" | "4xl";
3
4
  export interface SectionHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
4
5
  /** セクションタイトル */
5
6
  title: string;
@@ -21,8 +22,13 @@ export interface SectionHeaderProps extends React.HTMLAttributes<HTMLDivElement>
21
22
  prevDisabled?: boolean;
22
23
  /** カルーセル用: 次へボタン無効化 */
23
24
  nextDisabled?: boolean;
24
- /** タイトルのサイズ(Figma 準拠: 3xl=28px / 2xl=24px / xl=21px / lg=18px / md=16px / sm=14px) */
25
+ /** SPを含む基本サイズ(3xl=通常ページの主見出し。2xl以下=セクション見出し) */
25
26
  size?: SectionHeaderSize;
27
+ /**
28
+ * LP・マーケティング系ヒーローのPCサイズ。
29
+ * `size="3xl" desktopSize="5xl"` のように指定し、通常ページでは使わない。
30
+ */
31
+ desktopSize?: SectionHeaderDesktopSize;
26
32
  /** 見出しのHTML要素を上書き(デフォルトは size に応じて h1〜h6 を自動選択) */
27
33
  as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span";
28
34
  /**
@@ -48,6 +54,7 @@ export interface SectionHeaderProps extends React.HTMLAttributes<HTMLDivElement>
48
54
  * ### AI 向け使用ルール
49
55
  *
50
56
  * - ページの主タイトル: `size="3xl"` or `size="2xl"`
57
+ * - LP・マーケティング系ヒーロー: `size="3xl" desktopSize="4xl"` または `desktopSize="5xl"`
51
58
  * - セクション見出し(ランキング等): `size="xl"` or `size="lg"`(デフォルト)
52
59
  * - 小見出し・グループラベル: `size="md"` or `size="sm"`
53
60
  * - `as` で見出しレベルを上書き可能(同一ページに h1 が複数必要な場合など)
@@ -55,5 +62,5 @@ export interface SectionHeaderProps extends React.HTMLAttributes<HTMLDivElement>
55
62
  * - `action` に任意の ReactNode(Button 等)を渡して右側にアクションを配置可能
56
63
  * - `align="center"` でランディング/ガイド系の中央寄せ大見出しに切替(`eyebrow` に Badge 等を載せられる)
57
64
  */
58
- declare function SectionHeader({ className, title, subtitle, moreHref, moreLabel, onMoreClick, action, onPrev, onNext, prevDisabled, nextDisabled, size, as, align, eyebrow, ...props }: SectionHeaderProps): import("react/jsx-runtime").JSX.Element;
65
+ declare function SectionHeader({ className, title, subtitle, moreHref, moreLabel, onMoreClick, action, onPrev, onNext, prevDisabled, nextDisabled, size, desktopSize, as, align, eyebrow, ...props }: SectionHeaderProps): import("react/jsx-runtime").JSX.Element;
59
66
  export { SectionHeader };
@@ -1,5 +1,12 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
+ export type SectionScrim = "none" | "dark" | "light" | "bottom-dark";
4
+ export interface SectionProps extends Omit<React.ComponentProps<"section">, "background">, VariantProps<typeof sectionVariants> {
5
+ /** 背景画像 URL。左右余白は引き続き内側の Container が所有する */
6
+ backgroundImage?: string;
7
+ /** 背景画像上の文字を読みやすくする DS 管理のオーバーレイ */
8
+ scrim?: SectionScrim;
9
+ }
3
10
  /**
4
11
  * Section — 全幅の縦リズム+(任意で)背景色付きの帯。
5
12
  *
@@ -8,6 +15,8 @@ import { type VariantProps } from "class-variance-authority";
8
15
  * 背景色は Section(全幅)が持ち、中央寄せは Container が持つ ── この分担により
9
16
  * 「背景帯は画面端まで、コンテンツは中央寄せ」が二重がけなしで成立する。
10
17
  * - 縦余白は SP/PC ペアで `--Space-Section-*` トークンを消費する(rem 直書きの撲滅)。
18
+ * - **色地の Section(`subtle` / `accent-subtle`)は配下 Card のサーフェス文脈を宣言する**
19
+ * (`--card-surface: var(--Surface-Primary)`)。詳細は下記。
11
20
  *
12
21
  * 推奨パターン:
13
22
  * ```tsx
@@ -17,10 +26,34 @@ import { type VariantProps } from "class-variance-authority";
17
26
  * </Container>
18
27
  * </Section>
19
28
  * ```
29
+ *
30
+ * ## 配下 Card へのサーフェス伝播(#150)
31
+ *
32
+ * `background="subtle"`(Surface-Tertiary)/ `"accent-subtle"` は色地なので、既定の
33
+ * `bg-card`(Surface-Secondary)のままでは Card が地に沈む。Section が
34
+ * `--card-surface: var(--Surface-Primary)` を配下に流すことで、**Section 配下の Card は
35
+ * `surface` 未指定でも白**になる(`Card surface="primary"` の明示指定は従来通り優先)。
36
+ *
37
+ * 「グレー地の上の Card は白」を**構造で**保証するのが狙いで、あとからカードを足しても
38
+ * prop の付け忘れが起きない。伝播は CSS カスタムプロパティのカスケードのみで、React context は
39
+ * 使わない(Server Component のまま使える/DS 外の要素は影響を受けない)。
40
+ *
41
+ * `background="none"` は文脈をリセットしない。色地 Section の内側に入れ子にした
42
+ * `background="none"` の Section は背景が透過して外側の色地が見えるため、
43
+ * 配下の Card も外側の文脈(白)を引き継ぐのが正しい。
44
+ *
45
+ * dark では伝播値を切り替えない(`Surface-Secondary` のまま)。dark の Surface-Secondary は
46
+ * 「地の上に重ねる半透明白」なので色地の上でも一段明るく浮き、そもそも沈まない。
47
+ * ここで `Surface-Primary`(ほぼ不透明の黒)を強制すると地より暗い「穴」になり
48
+ * elevation が反転する。※ `Card surface="primary"` の**明示指定**は light/dark とも
49
+ * Surface-Primary で固定(明示は明示のまま)。
20
50
  */
21
51
  declare const sectionVariants: (props?: {
22
52
  spacing?: "sm" | "lg" | "xl" | "md";
23
53
  background?: "none" | "accent-subtle" | "subtle";
24
54
  } & import("class-variance-authority/types").ClassProp) => string;
25
- declare function Section({ className, spacing, background, ...props }: React.ComponentProps<"section"> & VariantProps<typeof sectionVariants>): import("react/jsx-runtime").JSX.Element;
26
- export { Section, sectionVariants };
55
+ declare const sectionScrimVariants: (props?: {
56
+ scrim?: "none" | "dark" | "light" | "bottom-dark";
57
+ } & import("class-variance-authority/types").ClassProp) => string;
58
+ declare function Section({ className, spacing, background, backgroundImage, scrim, style, ...props }: SectionProps): import("react/jsx-runtime").JSX.Element;
59
+ export { Section, sectionVariants, sectionScrimVariants };
@@ -1,5 +1,6 @@
1
1
  import * as React from "react";
2
- export type SocialProvider = "line" | "amazon" | "google" | "apple";
2
+ import { type SocialPlatform } from "../../components/foundations/social-icon";
3
+ export type SocialProvider = Extract<SocialPlatform, "line" | "amazon" | "google" | "apple">;
3
4
  export interface SocialLoginButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
5
  /** ソーシャルプロバイダー */
5
6
  provider: SocialProvider;
@@ -19,6 +20,7 @@ export interface SocialLoginButtonProps extends React.ButtonHTMLAttributes<HTMLB
19
20
  * - フルサイズ: `<SocialLoginButton provider="line" />`
20
21
  * - アイコンのみ: `<SocialLoginButton provider="google" size="icon" />`
21
22
  * - LINE は緑背景、他は白背景、Apple は黒背景
23
+ * - ブランドロゴは `SocialIcon` に集約している。個別に SVG を手組みしない
22
24
  */
23
25
  declare function SocialLoginButton({ provider, size, label, className, ...props }: SocialLoginButtonProps): import("react/jsx-runtime").JSX.Element;
24
26
  export { SocialLoginButton };
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ export interface TimelineItem {
3
+ /** 省略時は1始まりの連番を表示。IconBadge 等の ReactNode も渡せる */
4
+ marker?: React.ReactNode;
5
+ /** 各項目の見出し */
6
+ title: React.ReactNode;
7
+ /** Card・本文・メタ情報等の任意コンテンツ */
8
+ children?: React.ReactNode;
9
+ }
10
+ export interface TimelineProps extends Omit<React.ComponentProps<"ol">, "children"> {
11
+ items: TimelineItem[];
12
+ /** タイムライン全体の日本語ラベル */
13
+ ariaLabel?: string;
14
+ }
15
+ /**
16
+ * 本文付きの縦タイムライン。
17
+ *
18
+ * 応募フロー・オンボーディング手順・注文/配送履歴のように、各段階へ本文を
19
+ * ぶら下げる用途で使う。現在位置を示す横型の `ProgressSteps` とは役割が異なる。
20
+ * コネクター線は DS が所有するため consumer 側で `::before` を手組みしない。
21
+ */
22
+ declare function Timeline({ items, ariaLabel, className, ...props }: TimelineProps): import("react/jsx-runtime").JSX.Element;
23
+ export { Timeline };
@@ -62,6 +62,8 @@ export interface WorkspaceShellProps {
62
62
  * 右上=`primaryAction`(ワークスペース全体の上位アクションがある場合のみ)。
63
63
  * - `sectionNav` は編集内ナビのみ。グロナビは置かない。
64
64
  * - `sectionNav` は Surface-Secondary から浮いた独立パネルとして、シェル側で角丸パネルにラップされる。
65
+ * - 地が Surface-Secondary なので、配下 `Card` の既定サーフェスを白にする文脈
66
+ * (`--card-surface`)をシェルが宣言する。`Card` は `surface` 未指定のまま地から浮く(#150)。
65
67
  * - 標準的な編集は `AdminShell`(Standard Page(Edit)/旧 Form Page)。複雑・集中編集・没入執筆のみ本コンポーネント。
66
68
  *
67
69
  * 判断基準は contracts/screen-patterns.json / guidelines/foundations/screen-patterns.md を参照。
@@ -14,6 +14,8 @@ export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader,
14
14
  export { Checkbox } from "./components/foundations/checkbox";
15
15
  export type { CheckboxProps } from "./components/foundations/checkbox";
16
16
  export { CheckboxCardGroup, CheckboxCardItem } from "./components/foundations/checkbox-card";
17
+ export { CheckboxGroup, CheckboxGroupItem } from "./components/foundations/checkbox-group";
18
+ export type { CheckboxGroupProps } from "./components/foundations/checkbox-group";
17
19
  export { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./components/foundations/collapsible";
18
20
  export { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from "./components/foundations/command";
19
21
  export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from "./components/foundations/context-menu";
@@ -21,7 +23,8 @@ export { DataTable } from "./components/foundations/data-table";
21
23
  export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from "./components/foundations/dialog";
22
24
  export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from "./components/foundations/drawer";
23
25
  export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "./components/foundations/dropdown-menu";
24
- export { FieldSet, FieldLegend, FieldGroup, FieldDescription, FieldError, FieldSeparator } from "./components/foundations/field";
26
+ export { Field, FieldLabel, FieldSet, FieldLegend, FieldGroup, FieldDescription, FieldError, FieldSeparator, fieldVariants } from "./components/foundations/field";
27
+ export type { FieldProps } from "./components/foundations/field";
25
28
  export { FileInput, formatFileNames, validateFileSize } from "./components/foundations/file-input";
26
29
  export type { FileInputProps, FileInputError } from "./components/foundations/file-input";
27
30
  export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField } from "./components/foundations/form";
@@ -33,7 +36,9 @@ export { Label } from "./components/foundations/label";
33
36
  export { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from "./components/foundations/menubar";
34
37
  export { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, navigationMenuTriggerStyle } from "./components/foundations/navigation-menu";
35
38
  export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "./components/foundations/pagination";
36
- export { Popover, PopoverContent, PopoverTrigger } from "./components/foundations/popover";
39
+ export { getPaginationRange } from "./lib/pagination-range";
40
+ export type { GetPaginationRangeOptions, PaginationRangeItem } from "./lib/pagination-range";
41
+ export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "./components/foundations/popover";
37
42
  export { Progress } from "./components/foundations/progress";
38
43
  export { ResponsiveDialog, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogFooter, ResponsiveDialogHeader, ResponsiveDialogTitle, ResponsiveDialogTrigger, useIsMobile } from "./components/foundations/responsive-dialog";
39
44
  export { RadioGroup, RadioGroupItem } from "./components/foundations/radio-group";
@@ -47,6 +52,8 @@ export { SkipLink } from "./components/foundations/skip-link";
47
52
  export type { SkipLinkProps } from "./components/foundations/skip-link";
48
53
  export { Slider } from "./components/foundations/slider";
49
54
  export { Spinner } from "./components/foundations/spinner";
55
+ export { SocialIcon } from "./components/foundations/social-icon";
56
+ export type { SocialIconProps, SocialPlatform } from "./components/foundations/social-icon";
50
57
  export { Switch } from "./components/foundations/switch";
51
58
  export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "./components/foundations/table";
52
59
  export { Tabs, TabsContent, TabsList, TabsTrigger } from "./components/foundations/tabs";
@@ -62,10 +69,14 @@ export { AdminHeader } from "./components/primitives/admin-header";
62
69
  export type { AdminHeaderProps } from "./components/primitives/admin-header";
63
70
  export { CoachMark } from "./components/primitives/coach-mark";
64
71
  export type { CoachMarkProps, CoachMarkDirection } from "./components/primitives/coach-mark";
72
+ export { Combobox } from "./components/primitives/combobox";
73
+ export type { ComboboxOption, ComboboxProps } from "./components/primitives/combobox";
65
74
  export { BannerCarousel } from "./components/primitives/banner-carousel";
66
75
  export type { BannerCarouselProps, BannerItem } from "./components/primitives/banner-carousel";
67
76
  export { ContentCarousel } from "./components/primitives/content-carousel";
68
- export type { ContentCarouselProps } from "./components/primitives/content-carousel";
77
+ export type { ContentCarouselProps, ContentCarouselItemsPerView } from "./components/primitives/content-carousel";
78
+ export { MultiSelect } from "./components/primitives/multi-select";
79
+ export type { MultiSelectOption, MultiSelectProps } from "./components/primitives/multi-select";
69
80
  export { StickyActionBar } from "./components/primitives/sticky-action-bar";
70
81
  export { BottomTabBar } from "./components/primitives/bottom-tab-bar";
71
82
  export type { BottomTabBarProps, BottomTabBarItem } from "./components/primitives/bottom-tab-bar";
@@ -75,6 +86,8 @@ export { CategoryShortcuts } from "./components/primitives/category-shortcuts";
75
86
  export type { CategoryShortcutsProps, CategoryShortcutsItem } from "./components/primitives/category-shortcuts";
76
87
  export { CategoryScroll } from "./components/primitives/category-scroll";
77
88
  export type { CategoryScrollProps, CategoryItem } from "./components/primitives/category-scroll";
89
+ export { ChatComposer } from "./components/primitives/chat-composer";
90
+ export type { ChatComposerProps, ChatComposerAttachmentError } from "./components/primitives/chat-composer";
78
91
  export { Chip, chipVariants } from "./components/primitives/chip";
79
92
  export type { ChipProps } from "./components/primitives/chip";
80
93
  export { StandardPageShell } from "./components/primitives/standard-page-shell";
@@ -107,6 +120,8 @@ export { ImageCarousel } from "./components/primitives/image-carousel";
107
120
  export type { ImageCarouselProps } from "./components/primitives/image-carousel";
108
121
  export { ImageGallery } from "./components/primitives/image-gallery";
109
122
  export type { ImageGalleryProps } from "./components/primitives/image-gallery";
123
+ export { ImageInput, imageInputPreviewVariants } from "./components/primitives/image-input";
124
+ export type { ImageInputProps, ImageInputValidationError } from "./components/primitives/image-input";
110
125
  export { ImageUploader } from "./components/primitives/image-uploader";
111
126
  export type { ImageUploaderProps, ImageUploaderImage } from "./components/primitives/image-uploader";
112
127
  export { KebabMenu } from "./components/primitives/kebab-menu";
@@ -125,16 +140,19 @@ export { PriceDisplay, priceDisplayVariants } from "./components/primitives/pric
125
140
  export type { PriceDisplayProps } from "./components/primitives/price-display";
126
141
  export { ProgressSteps } from "./components/primitives/progress-steps";
127
142
  export type { ProgressStepsProps } from "./components/primitives/progress-steps";
128
- export { QuantitySelector } from "./components/primitives/quantity-selector";
129
- export type { QuantitySelectorProps } from "./components/primitives/quantity-selector";
143
+ export { Timeline } from "./components/primitives/timeline";
144
+ export type { TimelineItem, TimelineProps } from "./components/primitives/timeline";
145
+ export { NumberInput, QuantitySelector } from "./components/primitives/number-input";
146
+ export type { NumberInputProps, QuantitySelectorProps } from "./components/primitives/number-input";
130
147
  export { SearchBar } from "./components/primitives/search-bar";
131
148
  export type { SearchBarProps } from "./components/primitives/search-bar";
132
149
  export { SearchPanel } from "./components/primitives/search-panel";
133
150
  export type { SearchPanelProps } from "./components/primitives/search-panel";
134
151
  export { Container, containerVariants } from "./components/primitives/container";
135
- export { Section, sectionVariants } from "./components/primitives/section";
152
+ export { Section, sectionVariants, sectionScrimVariants } from "./components/primitives/section";
153
+ export type { SectionProps, SectionScrim } from "./components/primitives/section";
136
154
  export { SectionHeader } from "./components/primitives/section-header";
137
- export type { SectionHeaderProps, SectionHeaderSize } from "./components/primitives/section-header";
155
+ export type { SectionHeaderDesktopSize, SectionHeaderProps, SectionHeaderSize, } from "./components/primitives/section-header";
138
156
  export { SectionNav } from "./components/primitives/section-nav";
139
157
  export type { SectionNavProps, SectionNavItem } from "./components/primitives/section-nav";
140
158
  export { ShareButtons } from "./components/primitives/share-buttons";
@@ -0,0 +1,16 @@
1
+ export type PaginationRangeItem = number | "ellipsis";
2
+ export interface GetPaginationRangeOptions {
3
+ /** 現在ページ(1始まり)。範囲外は 1〜totalPages に丸める */
4
+ currentPage: number;
5
+ /** 総ページ数。0以下は空配列を返す */
6
+ totalPages: number;
7
+ /** 現在ページの左右に常時表示するページ数 */
8
+ siblingCount?: number;
9
+ }
10
+ /**
11
+ * ページネーションに表示するページ番号と省略記号の窓を返す。
12
+ *
13
+ * 先頭・末尾ページは常に残し、現在ページの前後を siblingCount 件ずつ表示する。
14
+ * 描画は既存の PaginationItem / PaginationLink / PaginationEllipsis を使う。
15
+ */
16
+ export declare function getPaginationRange({ currentPage, totalPages, siblingCount, }: GetPaginationRangeOptions): PaginationRangeItem[];
@@ -0,0 +1,31 @@
1
+ import * as React from "react";
2
+ type CountableElement = HTMLInputElement | HTMLTextAreaElement;
3
+ /**
4
+ * `showCount` 用の文字数を求めるための内部フック。
5
+ *
6
+ * 制御(`value` 指定)のときは `value` をそのまま数える。
7
+ * 非制御のときは **内部 state ではなく実際の DOM の `value`** を数える。
8
+ * react-hook-form の `register()` は `ref` 経由で DOM に直接初期値を書き込み
9
+ * (`reset()` / `defaultValues`)、その経路では `onChange` が発火しないため、
10
+ * 内部 state だけを見ていると初期表示のカウントが 0 のままになる。
11
+ *
12
+ * 初期表示は layout effect で DOM を読み、以後の programmatic な `.value` 代入は
13
+ * 要素自身の value descriptor を監視して拾う。MutationObserver は DOM property の
14
+ * 変更を観測できず、RHF の `setValue()` は再 render を伴わない場合があるため。
15
+ * 元 descriptor(React の value tracker を含む)へ処理を委譲し、detach 時に復元する。
16
+ *
17
+ * consumer の callback ref が返す cleanup は保持し、detach 時に実行する。
18
+ * cleanup を返さない従来の callback ref は detach 時に null を渡すため、
19
+ * React 18/19 どちらの ref 契約も維持する。
20
+ */
21
+ export declare function useValueLength<T extends CountableElement>({ enabled, value, defaultValue, forwardedRef, }: {
22
+ enabled: boolean;
23
+ value: string | number | readonly string[] | undefined;
24
+ defaultValue: string | number | readonly string[] | undefined;
25
+ forwardedRef: React.Ref<T> | undefined;
26
+ }): {
27
+ ref: React.RefCallback<T>;
28
+ length: number;
29
+ syncFromDom: () => void;
30
+ };
31
+ export {};
@@ -0,0 +1,44 @@
1
+ import { readFileSync } from "node:fs"
2
+
3
+ const contractUrl = new URL("../contracts/components.json", import.meta.url)
4
+ const contracts = JSON.parse(readFileSync(contractUrl, "utf8"))
5
+ const entries = ["foundations", "primitives", "ec"].flatMap(
6
+ (tier) => contracts[tier] ?? []
7
+ )
8
+ const deprecated = new Map(
9
+ entries.flatMap((entry) =>
10
+ (entry.deprecatedAliases ?? []).map((alias) => [alias, entry.name])
11
+ )
12
+ )
13
+
14
+ const noDeprecated = {
15
+ meta: {
16
+ type: "suggestion",
17
+ docs: { description: "Cake.jp DS の非推奨 export を検出する" },
18
+ schema: [],
19
+ messages: {
20
+ deprecated: "[cakejp-ds] {{name}} は非推奨です。{{replacement}} を使ってください。",
21
+ },
22
+ },
23
+ create(context) {
24
+ return {
25
+ ImportDeclaration(node) {
26
+ if (node.source.value !== "@cakejp/design-system") return
27
+ for (const specifier of node.specifiers) {
28
+ if (specifier.type !== "ImportSpecifier") continue
29
+ const imported = specifier.imported.name
30
+ const replacement = deprecated.get(imported)
31
+ if (replacement) {
32
+ context.report({
33
+ node: specifier,
34
+ messageId: "deprecated",
35
+ data: { name: imported, replacement },
36
+ })
37
+ }
38
+ }
39
+ },
40
+ }
41
+ },
42
+ }
43
+
44
+ export default { rules: { "no-deprecated": noDeprecated } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cakejp/design-system",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "description": "Cake.jp Design System — UI コンポーネント・カラートークン・タイポグラフィ",
6
6
  "license": "UNLICENSED",
@@ -39,7 +39,9 @@
39
39
  "bin",
40
40
  "contracts",
41
41
  "dist",
42
+ "eslint",
42
43
  "scripts/codemod",
44
+ "src/components/COMPONENT_LOOKUP.md",
43
45
  "src/preset-standalone.css",
44
46
  "src/preset.css",
45
47
  "src/styles",
@@ -68,7 +70,8 @@
68
70
  "./styles": "./src/preset.css",
69
71
  "./tokens/primitive": "./src/styles/primitive.css",
70
72
  "./tokens/semantic": "./src/styles/semantic.css",
71
- "./tokens/typography": "./src/styles/typography.css"
73
+ "./tokens/typography": "./src/styles/typography.css",
74
+ "./eslint/deprecated": "./eslint/deprecated.js"
72
75
  },
73
76
  "sideEffects": [
74
77
  "*.css"
@@ -91,7 +94,8 @@
91
94
  "typecheck:stories": "tsc --noEmit -p tsconfig.stories.json",
92
95
  "generate:lint-rules": "node scripts/generate-lint-rules.mjs",
93
96
  "generate:lookup": "node scripts/generate-component-lookup.mjs",
94
- "check": "tsc --noEmit -p tsconfig.app.json && npm run typecheck:stories && bash scripts/check-deps.sh && bash scripts/check-drift.sh && bash scripts/check-docs-drift.sh && bash scripts/lint-scratch.sh && bash scripts/check-story-reuse.sh && bash scripts/check-responsive.sh && node scripts/check-border-color.mjs && bash scripts/lint-scratch.sh --components && bash scripts/check-generated-drift.sh",
97
+ "lint:contrast": "node scripts/check-contrast.mjs",
98
+ "check": "tsc --noEmit -p tsconfig.app.json && npm run typecheck:stories && bash scripts/check-deps.sh && bash scripts/check-drift.sh && bash scripts/check-docs-drift.sh && bash scripts/lint-scratch.sh && bash scripts/check-story-reuse.sh && bash scripts/check-responsive.sh && node scripts/check-border-color.mjs && npm run lint:contrast && bash scripts/lint-scratch.sh --components && bash scripts/check-generated-drift.sh",
95
99
  "test": "vitest run --config vitest.config.ts"
96
100
  },
97
101
  "dependencies": {
@@ -153,6 +157,7 @@
153
157
  "eslint-plugin-storybook": "^10.3.3",
154
158
  "globals": "^16.5.0",
155
159
  "iconsax-reactjs": "^0.0.8",
160
+ "jsdom": "^29.1.1",
156
161
  "lucide-react": "^0.577.0",
157
162
  "next-themes": "^0.4.6",
158
163
  "playwright": "^1.58.2",
@@ -0,0 +1,14 @@
1
+ # Codemod
2
+
3
+ 破壊的変更では `template.mjs` を複製し、`RENAMES`、`PROP_RENAMES`、
4
+ `WARNINGS` の3箇所を埋めて移行スクリプトを作ります。
5
+
6
+ ```bash
7
+ cp scripts/codemod/template.mjs scripts/codemod/v1-to-v2.mjs
8
+ node scripts/codemod/v1-to-v2.mjs --dry ./src
9
+ node scripts/codemod/v1-to-v2.mjs ./src
10
+ ```
11
+
12
+ 正規表現ベースのため、必ずコミット済みの利用側で `--dry` を先に実行し、
13
+ 適用後は `git diff` と ESLint の `@cakejp/design-system/eslint/deprecated`
14
+ で残件を確認してください。
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs"
3
+ import path from "node:path"
4
+
5
+ const PACKAGE_PATTERN = /@cakejp\/design-system/
6
+ const RENAMES = []
7
+ const PROP_RENAMES = []
8
+ const WARNINGS = []
9
+
10
+ const args = process.argv.slice(2)
11
+ const dry = args.includes("--dry")
12
+ const targetDir = args.find((arg) => !arg.startsWith("--")) ?? "./src"
13
+ if (!fs.existsSync(targetDir)) {
14
+ console.error(`Directory not found: ${targetDir}`)
15
+ process.exit(1)
16
+ }
17
+
18
+ function filesIn(directory) {
19
+ return fs.readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
20
+ const full = path.join(directory, entry.name)
21
+ if (entry.isDirectory()) {
22
+ return ["node_modules", "dist"].includes(entry.name) || entry.name.startsWith(".")
23
+ ? []
24
+ : filesIn(full)
25
+ }
26
+ return /\.(?:ts|tsx|js|jsx|mjs|cjs)$/.test(entry.name) ? [full] : []
27
+ })
28
+ }
29
+
30
+ let changedFiles = 0
31
+ let changedItems = 0
32
+ for (const file of filesIn(targetDir)) {
33
+ const source = fs.readFileSync(file, "utf8")
34
+ if (!PACKAGE_PATTERN.test(source)) continue
35
+ let output = source
36
+ let count = 0
37
+ for (const [before, after] of [...RENAMES].sort((a, b) => b[0].length - a[0].length)) {
38
+ const pattern = new RegExp(`\\b${before}\\b`, "g")
39
+ const matches = output.match(pattern)
40
+ if (matches) {
41
+ output = output.replace(pattern, after)
42
+ count += matches.length
43
+ }
44
+ }
45
+ for (const [component, before, after] of PROP_RENAMES) {
46
+ const pattern = new RegExp(`(<${component}[^>]*\\s)${before}=`, "g")
47
+ const matches = output.match(pattern)
48
+ if (matches) {
49
+ output = output.replace(pattern, `$1${after}=`)
50
+ count += matches.length
51
+ }
52
+ }
53
+ for (const warning of WARNINGS) {
54
+ if (warning.pattern.test(source)) console.warn(`⚠ ${file}: ${warning.message}`)
55
+ }
56
+ if (!count) continue
57
+ changedFiles++
58
+ changedItems += count
59
+ if (!dry) fs.writeFileSync(file, output)
60
+ console.log(`${dry ? "[dry]" : "✓"} ${file}: ${count}`)
61
+ }
62
+ console.log(`${changedFiles} files / ${changedItems} replacements`)