@cakejp/design-system 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/CLAUDE.md +6 -2
- package/bin/check-duplicates.mjs +133 -9
- package/bin/exports-parser.mjs +54 -0
- package/bin/init.js +3 -0
- package/contracts/components.json +229 -25
- package/contracts/composition.json +10 -7
- package/contracts/rules.json +6 -4
- package/dist/index.css +1 -1
- package/dist/index.js +2951 -2204
- package/dist/types/components/ec/admin-shell.d.ts +30 -2
- package/dist/types/components/foundations/card.d.ts +27 -3
- package/dist/types/components/foundations/field.d.ts +26 -3
- package/dist/types/components/foundations/input.d.ts +3 -1
- package/dist/types/components/foundations/textarea.d.ts +3 -1
- package/dist/types/components/primitives/chat-composer.d.ts +87 -0
- package/dist/types/components/primitives/content-carousel.d.ts +7 -1
- package/dist/types/components/primitives/date-picker.d.ts +15 -3
- package/dist/types/components/primitives/funnel-shell.d.ts +2 -0
- package/dist/types/components/primitives/image-input.d.ts +119 -0
- package/dist/types/components/primitives/section-header.d.ts +9 -2
- package/dist/types/components/primitives/section.d.ts +35 -2
- package/dist/types/components/primitives/timeline.d.ts +23 -0
- package/dist/types/components/primitives/workspace-shell.d.ts +2 -0
- package/dist/types/index.d.ts +17 -5
- package/dist/types/lib/pagination-range.d.ts +16 -0
- package/dist/types/lib/use-value-length.d.ts +31 -0
- package/package.json +2 -1
- package/src/preset-standalone.css +16 -0
- package/src/preset.css +17 -0
- package/src/styles/typography.css +7 -0
- package/templates/AGENTS.md +2 -0
- package/templates/CLAUDE.md +2 -0
- package/tokens.json +9 -2
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
* 本番の shop_layout.ctp を参考に、Header + SideNav + Main Content の構造を再現。
|
|
5
5
|
* 汎用の枠は primitives(AdminSideNav / AdminHeader)に切り出し、
|
|
6
6
|
* Cake.jp 管理メニュー等のドメイン既定値はこの ec レイヤーで束ねる。
|
|
7
|
+
*
|
|
8
|
+
* ## サイドナビの構造(採用前に確認すること)
|
|
9
|
+
*
|
|
10
|
+
* - **PC**: 左端固定の **72px アイコンレール**(アイコン + 短いラベル、サブメニューは hover ポップアップ)。
|
|
11
|
+
* 幅が無いため、バッジ・見出し・説明文からなる**ブランドブロックをレール上部に置くことはできない**。
|
|
12
|
+
* 他ブランドの管理画面でブランドを出したい場合は `brand`(ヘッダー左側)を使う。
|
|
13
|
+
* - **SP**: ドロワー。上部見出しは `sidebarHeader`(未指定なら `shopName`)で差し替えられる。
|
|
14
|
+
*
|
|
15
|
+
* 「幅の広いブランド付きサイドバー」を前提にした画面は、この骨格とは別パターンなので
|
|
16
|
+
* そのまま置き換えられない(DS に issue を立てること)。
|
|
17
|
+
*
|
|
18
|
+
* ## 配下 Card のサーフェス
|
|
19
|
+
*
|
|
20
|
+
* 地が Surface-Secondary なので、シェルが配下 `Card` の既定サーフェスを白にする文脈
|
|
21
|
+
* (`--card-surface`)を宣言する。`Card` は `surface` 未指定のまま地から浮く(#150)。
|
|
22
|
+
*
|
|
7
23
|
* 参照元:
|
|
8
24
|
* - admin-test-htdocs/app/views/layouts/shop_layout.ctp
|
|
9
25
|
* - admin-test-htdocs/app/views/elements/shop_layout/header.ctp
|
|
@@ -28,8 +44,20 @@ export interface AdminShellProps {
|
|
|
28
44
|
label: string;
|
|
29
45
|
href?: string;
|
|
30
46
|
}[];
|
|
31
|
-
/**
|
|
47
|
+
/** ショップ名。ヘッダーの `{shopName}管理` と SP ドロワー見出しの既定値になる */
|
|
32
48
|
shopName?: string;
|
|
49
|
+
/**
|
|
50
|
+
* ヘッダー左側のブランド表示を差し替える(既定=`{shopName}管理` の文字列)。
|
|
51
|
+
* ロゴ画像・バッジ付きブランドブロック等、文字列で表せない表現に使う。
|
|
52
|
+
* ※ PC の左サイドナビは 72px のアイコンレールでブランドブロックを置く領域が無いため、
|
|
53
|
+
* 他ブランドの管理画面はここ(ヘッダー)でブランドを表現する。
|
|
54
|
+
*/
|
|
55
|
+
brand?: React.ReactNode;
|
|
56
|
+
/**
|
|
57
|
+
* SP ドロワー上部の見出しを差し替える(既定=`shopName` の文字列)。
|
|
58
|
+
* バッジ+見出し+説明のようなブランドブロックを置ける。
|
|
59
|
+
*/
|
|
60
|
+
sidebarHeader?: React.ReactNode;
|
|
33
61
|
/** サイドナビ項目(既定=Cake.jp 管理メニュー。利用側で差し替え可) */
|
|
34
62
|
navItems?: AdminNavItem[];
|
|
35
63
|
/** ヘッダー右側のアクション slot(既定=通知ベル+プロフィール) */
|
|
@@ -52,4 +80,4 @@ export interface AdminShellProps {
|
|
|
52
80
|
*/
|
|
53
81
|
skipLink?: false;
|
|
54
82
|
}
|
|
55
|
-
export declare function AdminShell({ children, activeNav, title, breadcrumbs, shopName, navItems, headerActions, onBack, backLabel, mainId, skipLink, }: AdminShellProps): import("react/jsx-runtime").JSX.Element;
|
|
83
|
+
export declare function AdminShell({ children, activeNav, title, breadcrumbs, shopName, brand, sidebarHeader, navItems, headerActions, onBack, backLabel, mainId, skipLink, }: AdminShellProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,9 +2,33 @@ import * as React from "react";
|
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
/**
|
|
4
4
|
* Card の背景サーフェス。
|
|
5
|
-
* - `default`:
|
|
6
|
-
* - `
|
|
7
|
-
*
|
|
5
|
+
* - `default`: `--card-surface`(親から伝播したサーフェス文脈)→ 無ければ `--card`
|
|
6
|
+
* (= Surface-Secondary)。通常の白/明るい地の上ではこれまで通り `bg-card` と同値。
|
|
7
|
+
* - `primary`: `Surface-Primary`(白)。文脈に関係なく白で固定したいときに明示指定する。
|
|
8
|
+
*
|
|
9
|
+
* ## サーフェス文脈の伝播(#150)
|
|
10
|
+
*
|
|
11
|
+
* `Section background="subtle" | "accent-subtle"` は配下に `--card-surface: var(--Surface-Primary)`
|
|
12
|
+
* を流す。そのため**グレー地の Section に置いた Card は `surface` 未指定でも自動で白**になり、
|
|
13
|
+
* 「あとからカードを1枚足したら prop を付け忘れてグレー地に沈む」事故が構造的に起きない。
|
|
14
|
+
*
|
|
15
|
+
* 伝播は CSS カスタムプロパティのカスケードだけで成立する(React context 不使用)。
|
|
16
|
+
* したがって Card / Section は Server Component のまま使え、DS の `Section` を使わない
|
|
17
|
+
* 自前のグレー地でも同じ効果を得られる:
|
|
18
|
+
*
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // 任意の要素にサーフェス文脈を宣言する(consumer 側の escape hatch)
|
|
21
|
+
* <div className="bg-[var(--Surface-Tertiary)] [--card-surface:var(--Surface-Primary)]">
|
|
22
|
+
* <Card /> // 白になる
|
|
23
|
+
* </div>
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* dark では `Section` は伝播値を `Surface-Secondary` に据え置く(dark のカードは半透明白で
|
|
27
|
+
* 地に重なり一段明るく浮くため、白の強制は elevation の反転になる)。自前で文脈を宣言する
|
|
28
|
+
* ときも dark に配慮するなら `dark:[--card-surface:var(--Surface-Secondary)]` を併記する。
|
|
29
|
+
*
|
|
30
|
+
* 逆に文脈を無視して Surface-Secondary に固定したい 1 枚だけは
|
|
31
|
+
* `<Card className="bg-card">` で上書きする(className が最後に勝つ)。
|
|
8
32
|
*/
|
|
9
33
|
declare const cardVariants: (props?: {
|
|
10
34
|
surface?: "default" | "primary";
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
*
|
|
8
8
|
* ### インポート
|
|
9
9
|
* ```tsx
|
|
10
|
-
* import { FieldSet, FieldLegend, FieldGroup, FieldDescription, FieldError, FieldSeparator } from "../../components/foundations/field"
|
|
10
|
+
* import { Field, FieldLabel, FieldSet, FieldLegend, FieldGroup, FieldDescription, FieldError, FieldSeparator } from "../../components/foundations/field"
|
|
11
11
|
* ```
|
|
12
12
|
*
|
|
13
13
|
* ### 構成要素
|
|
14
14
|
* | 要素 | DOM | 役割 |
|
|
15
15
|
* |------|-----|------|
|
|
16
|
+
* | `Field` | `<div role="group">` | **1 フィールド分の箱**(縦リズムの最小単位)。`orientation` で vertical / horizontal / responsive |
|
|
17
|
+
* | `FieldLabel` | `<Label>` ラップ | Field 内のラベル(`htmlFor` で入力と関連付け) |
|
|
16
18
|
* | `FieldSet` | `<fieldset>` | フォーム全体 or 大セクション。legend + 複数グループを縦リズム gap-6 で並べる |
|
|
17
19
|
* | `FieldLegend` | `<legend>` | FieldSet の見出し |
|
|
18
20
|
* | `FieldGroup` | `<div role="group">` | 関連する複数フィールドを section-content リズム gap-4 で束ねる |
|
|
@@ -21,11 +23,30 @@
|
|
|
21
23
|
* | `FieldSeparator` | `<Separator>` ラップ | フィールド群の区切り。children を渡すと中央ラベル付き |
|
|
22
24
|
*
|
|
23
25
|
* ### AI 向け使用ルール
|
|
24
|
-
* -
|
|
26
|
+
* - ラベル + 入力 + エラーが一体で済むなら `FormField`(primitives)が最短。
|
|
27
|
+
* ラベル・入力・説明・エラーを個別に組み立てたいときは `Field` + `FieldLabel` を使う
|
|
28
|
+
* - `Field` は `FieldGroup` の中に置く(`orientation="responsive"` は `FieldGroup` の
|
|
29
|
+
* `@container/field-group` を基準に、狭いと縦・広いと横へ切り替わる)
|
|
25
30
|
* - 余白は composition.json の縦リズムに従う(FieldSet=gap-6 / FieldGroup=gap-4)。手で mt-/mb- を足さない
|
|
26
31
|
* - 見出しは `FieldLegend`、グループ横断の区切りは `FieldSeparator` を使う
|
|
27
32
|
*/
|
|
28
33
|
import * as React from "react";
|
|
34
|
+
import { type VariantProps } from "class-variance-authority";
|
|
35
|
+
import { Label } from "../../components/foundations/label";
|
|
36
|
+
/**
|
|
37
|
+
* Field — 1 フィールド分の箱(ラベル + 入力 + 説明/エラー)。
|
|
38
|
+
* `FieldGroup`(gap-4)の中に並べる**縦リズムの最小単位**。
|
|
39
|
+
* これが無いと「1 フィールドの内側の並べ方」が consumer 実装依存になる。
|
|
40
|
+
*/
|
|
41
|
+
declare const fieldVariants: (props?: {
|
|
42
|
+
orientation?: "horizontal" | "vertical" | "responsive";
|
|
43
|
+
} & import("class-variance-authority/types").ClassProp) => string;
|
|
44
|
+
declare function Field({ className, orientation, ...props }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>): import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
/**
|
|
46
|
+
* FieldLabel — Field 内のラベル。DS の `Label` に DS のタイポ(typo-label-md)と
|
|
47
|
+
* 無効時の色を当てたもの。`htmlFor` で入力と関連付ける。
|
|
48
|
+
*/
|
|
49
|
+
declare function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>): import("react/jsx-runtime").JSX.Element;
|
|
29
50
|
/**
|
|
30
51
|
* FieldSet — フォーム全体 or 大きなセクションの枠。
|
|
31
52
|
* `<fieldset>` の既定スタイル(ブラウザ枠線・padding)をリセットし、
|
|
@@ -55,4 +76,6 @@ declare function FieldError({ className, children, ...props }: React.ComponentPr
|
|
|
55
76
|
* 上下に余白を持たせる。children を渡すと中央にラベル(「または」等)を表示。
|
|
56
77
|
*/
|
|
57
78
|
declare function FieldSeparator({ className, children, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
|
|
58
|
-
export { FieldSet, FieldLegend, FieldGroup, FieldDescription, FieldError, FieldSeparator, };
|
|
79
|
+
export { Field, FieldLabel, FieldSet, FieldLegend, FieldGroup, FieldDescription, FieldError, FieldSeparator, };
|
|
80
|
+
export { fieldVariants };
|
|
81
|
+
export type FieldProps = React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>;
|
|
@@ -4,8 +4,10 @@ export interface InputProps extends React.ComponentProps<"input"> {
|
|
|
4
4
|
* 文字数カウンタを表示する。`maxLength` とセットで使い、入力欄の
|
|
5
5
|
* 右下に `{現在}/{max}` を表示する。上限に達すると Text-Caution 色になる。
|
|
6
6
|
* 制御(`value`)/ 非制御(`defaultValue`)どちらでも追従する。
|
|
7
|
+
* 非制御時は実際の DOM の値を数えるため、react-hook-form の `register()` の
|
|
8
|
+
* ように `ref` 経由で外部から値が入るケースでも初期表示から正しく数える。
|
|
7
9
|
*/
|
|
8
10
|
showCount?: boolean;
|
|
9
11
|
}
|
|
10
|
-
declare function Input({ className, type, showCount, maxLength, value, defaultValue, onChange, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function Input({ className, type, showCount, maxLength, value, defaultValue, onChange, ref, ...props }: InputProps): import("react/jsx-runtime").JSX.Element;
|
|
11
13
|
export { Input };
|
|
@@ -4,8 +4,10 @@ export interface TextareaProps extends React.ComponentProps<"textarea"> {
|
|
|
4
4
|
* 文字数カウンタを表示する。`maxLength` とセットで使い、入力欄の
|
|
5
5
|
* 右下に `{現在}/{max}` を表示する。上限に達すると Text-Caution 色になる。
|
|
6
6
|
* 制御(`value`)/ 非制御(`defaultValue`)どちらでも追従する。
|
|
7
|
+
* 非制御時は実際の DOM の値を数えるため、react-hook-form の `register()` の
|
|
8
|
+
* ように `ref` 経由で外部から値が入るケースでも初期表示から正しく数える。
|
|
7
9
|
*/
|
|
8
10
|
showCount?: boolean;
|
|
9
11
|
}
|
|
10
|
-
declare function Textarea({ className, showCount, maxLength, value, defaultValue, onChange, ...props }: TextareaProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function Textarea({ className, showCount, maxLength, value, defaultValue, onChange, ref, ...props }: TextareaProps): import("react/jsx-runtime").JSX.Element;
|
|
11
13
|
export { Textarea };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** 添付が受理されなかったときのコールバック引数。 */
|
|
2
|
+
export interface ChatComposerAttachmentError {
|
|
3
|
+
/** `max-files`: 件数上限超過 / `max-size`: サイズ上限超過 */
|
|
4
|
+
code: "max-files" | "max-size";
|
|
5
|
+
/** 受理されなかったファイル */
|
|
6
|
+
file: File;
|
|
7
|
+
/** 超過した上限値(max-files は件数、max-size は MB) */
|
|
8
|
+
limit: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ChatComposerProps {
|
|
11
|
+
/** 入力値(制御) */
|
|
12
|
+
value: string;
|
|
13
|
+
/** 入力変更(制御) */
|
|
14
|
+
onChange: (value: string) => void;
|
|
15
|
+
/**
|
|
16
|
+
* 送信。本文と添付ファイルを受け取る。
|
|
17
|
+
* 本文と添付がどちらも空のときは呼ばれない。
|
|
18
|
+
*/
|
|
19
|
+
onSubmit: (value: string, files: File[]) => void;
|
|
20
|
+
/**
|
|
21
|
+
* 送信キー。
|
|
22
|
+
* - `enter`(既定): Enter で送信 / Shift+Enter で改行
|
|
23
|
+
* - `mod-enter`: ⌘/Ctrl+Enter で送信 / Enter は改行
|
|
24
|
+
*
|
|
25
|
+
* どちらでも IME 変換確定の Enter では送信しない。
|
|
26
|
+
*/
|
|
27
|
+
submitKey?: "enter" | "mod-enter";
|
|
28
|
+
/**
|
|
29
|
+
* 添付ファイル(制御)。指定すると表示はこの値に従う。
|
|
30
|
+
* 未指定なら内部 state で保持する。
|
|
31
|
+
*/
|
|
32
|
+
attachments?: File[];
|
|
33
|
+
/** 添付が変わったときのコールバック */
|
|
34
|
+
onAttachmentsChange?: (files: File[]) => void;
|
|
35
|
+
/** 受け付ける MIME/拡張子(例: "image/*,.pdf") */
|
|
36
|
+
accept?: string;
|
|
37
|
+
/** 添付できる最大件数。超過分は受理せず onAttachmentError を呼ぶ。 */
|
|
38
|
+
maxFiles?: number;
|
|
39
|
+
/** 1ファイルあたりの上限サイズ(MB)。超過ファイルは受理せず onAttachmentError を呼ぶ。 */
|
|
40
|
+
maxSizeMb?: number;
|
|
41
|
+
/** 添付が受理されなかったときのコールバック */
|
|
42
|
+
onAttachmentError?: (error: ChatComposerAttachmentError) => void;
|
|
43
|
+
/** 無効化(入力・添付・送信すべて) */
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
/** 送信中。送信ボタンを無効化し二重送信を防ぐ。 */
|
|
46
|
+
isSubmitting?: boolean;
|
|
47
|
+
/** 入力欄のプレースホルダ */
|
|
48
|
+
placeholder?: string;
|
|
49
|
+
/** 入力欄の最大文字数。指定すると文字数カウンタを表示する。 */
|
|
50
|
+
maxLength?: number;
|
|
51
|
+
/** 入力欄の visually-hidden ラベル(スクリーンリーダー向け) */
|
|
52
|
+
label?: string;
|
|
53
|
+
/** 入力欄の初期表示行数 */
|
|
54
|
+
rows?: number;
|
|
55
|
+
/** 入力欄の id。未指定なら自動採番。 */
|
|
56
|
+
id?: string;
|
|
57
|
+
/** マウント時に入力欄へフォーカスする */
|
|
58
|
+
autoFocus?: boolean;
|
|
59
|
+
/** 追加クラス(ルート要素) */
|
|
60
|
+
className?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* ## ChatComposer / メッセージコンポーザ
|
|
64
|
+
*
|
|
65
|
+
* テキスト入力 + 添付 + 送信を1つの枠にまとめた汎用コンポーザ。
|
|
66
|
+
* チャット・問い合わせ・レビュー返信など「短文を繰り返し送る」UI に使う。
|
|
67
|
+
*
|
|
68
|
+
* 中身は DS の既存部品の組み合わせ(Textarea / FileInput / Chip / Button)で、
|
|
69
|
+
* 送信キーの挙動・添付の見せ方・送信ボタンの意匠を DS 側で標準化する。
|
|
70
|
+
*
|
|
71
|
+
* ### インポート
|
|
72
|
+
* ```tsx
|
|
73
|
+
* import { ChatComposer } from "../../components/primitives/chat-composer"
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* ### 送信キー
|
|
77
|
+
* 既定は Enter 送信 / Shift+Enter 改行。長文入力が主なら `submitKey="mod-enter"`。
|
|
78
|
+
* どちらでも **IME 変換中の Enter では送信しない**(日本語入力での誤送信防止)。
|
|
79
|
+
*
|
|
80
|
+
* ### AI 向け使用ルール
|
|
81
|
+
* - チャット入力欄を Textarea + Button で手組みしない。ChatComposer を使う
|
|
82
|
+
* - 添付は `attachments` / `onAttachmentsChange` で制御し、Chip の removable で表示される
|
|
83
|
+
* - 送信中は `isSubmitting` を立てる(送信ボタンが無効化され二重送信を防げる)
|
|
84
|
+
* - `<form>` は内包しない。フォーム内に置いても入れ子にならない
|
|
85
|
+
*/
|
|
86
|
+
declare function ChatComposer({ value, onChange, onSubmit, submitKey, attachments, onAttachmentsChange, accept, maxFiles, maxSizeMb, onAttachmentError, disabled, isSubmitting, placeholder, maxLength, label, rows, id, autoFocus, className, }: ChatComposerProps): import("react/jsx-runtime").JSX.Element;
|
|
87
|
+
export { ChatComposer };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
export type ContentCarouselItemsPerView = 1 | 2 | 3 | 4;
|
|
2
3
|
export interface ContentCarouselProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
3
4
|
/**
|
|
4
5
|
* スライド内容(ReactNode)のリスト。
|
|
@@ -20,6 +21,11 @@ export interface ContentCarouselProps extends Omit<React.HTMLAttributes<HTMLDivE
|
|
|
20
21
|
* 右端に次スライドが見える。PC (@[960px]:) は常に全幅。
|
|
21
22
|
*/
|
|
22
23
|
peek?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* PC(@[960px]:)で同時に見せるカード数。SP は従来どおり1枚表示。
|
|
26
|
+
* 求人カード等、EC 商品以外の複数カードを横スクロールさせる用途に使う。
|
|
27
|
+
*/
|
|
28
|
+
itemsPerView?: ContentCarouselItemsPerView;
|
|
23
29
|
/** カルーセル全体の aria-label(スクリーンリーダー向け説明) */
|
|
24
30
|
ariaLabel?: string;
|
|
25
31
|
}
|
|
@@ -48,5 +54,5 @@ export interface ContentCarouselProps extends Omit<React.HTMLAttributes<HTMLDivE
|
|
|
48
54
|
* - 画像だけのバナーは `ImageCarousel` を使う(こちらはテキスト主体向け)
|
|
49
55
|
* - 自動再生: `<ContentCarousel autoPlay={5000} />`
|
|
50
56
|
*/
|
|
51
|
-
declare function ContentCarousel({ slides, showDots, showArrows, autoPlay, peek, ariaLabel, className, ...props }: ContentCarouselProps): import("react/jsx-runtime").JSX.Element;
|
|
57
|
+
declare function ContentCarousel({ slides, showDots, showArrows, autoPlay, peek, itemsPerView, ariaLabel, className, ...props }: ContentCarouselProps): import("react/jsx-runtime").JSX.Element;
|
|
52
58
|
export { ContentCarousel };
|
|
@@ -14,12 +14,24 @@ export interface DatePickerProps {
|
|
|
14
14
|
disabledDates?: Matcher | Matcher[];
|
|
15
15
|
/** trigger を無効化する */
|
|
16
16
|
disabled?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* 選択済みの値を消すクリアボタン(×)を trigger 右端に出す。既定 false(後方互換)。
|
|
19
|
+
* `value` があり `disabled` でないときだけ描画し、押すと `onChange(undefined)` を呼ぶ。
|
|
20
|
+
* 未指定だと「カレンダーを開いて選択済みの日付を再クリック」しかクリア手段が無く、
|
|
21
|
+
* 画面から発見できないため、任意項目(null 許容)では true にする。
|
|
22
|
+
*/
|
|
23
|
+
clearable?: boolean;
|
|
24
|
+
/** クリアボタンの aria-label。既定「日付をクリア」 */
|
|
25
|
+
clearLabel?: string;
|
|
17
26
|
/** trigger の id(FormField の htmlFor と接続) */
|
|
18
27
|
id?: string;
|
|
19
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* 追加クラス。**外側のラッパー要素**に付与する(クリアボタンを trigger の
|
|
30
|
+
* 兄弟として絶対配置するため、幅・レイアウト指定はラッパーが受け取る)。
|
|
31
|
+
*/
|
|
20
32
|
className?: string;
|
|
21
33
|
}
|
|
22
|
-
declare function DatePicker({ value, onChange, placeholder, min, max, disabledDates, disabled, id, className, }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
declare function DatePicker({ value, onChange, placeholder, min, max, disabledDates, disabled, clearable, clearLabel, id, className, }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
23
35
|
export interface DateTimePickerProps extends DatePickerProps {
|
|
24
36
|
/** 分の刻み(分 Select の選択肢間隔)。既定 5 分 */
|
|
25
37
|
minuteStep?: number;
|
|
@@ -28,5 +40,5 @@ export interface DateTimePickerProps extends DatePickerProps {
|
|
|
28
40
|
/** 分 Select の aria-label。既定「分」 */
|
|
29
41
|
minuteLabel?: string;
|
|
30
42
|
}
|
|
31
|
-
declare function DateTimePicker({ value, onChange, minuteStep, hourLabel, minuteLabel, disabled, className, ...dateProps }: DateTimePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
declare function DateTimePicker({ value, onChange, minuteStep, hourLabel, minuteLabel, clearLabel, disabled, className, ...dateProps }: DateTimePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
32
44
|
export { DatePicker, DateTimePicker };
|
|
@@ -86,6 +86,8 @@ export interface FunnelShellProps {
|
|
|
86
86
|
* で表す。各ステップはドット(上)+ラベル(下)の縦積みで、コネクタ線はドット中心の
|
|
87
87
|
* 高さで隣ステップ中心まで引く。ラベルは SP でも省略しない。
|
|
88
88
|
* - `bottomAction` を渡すと本文の下余白はシェルが管理する(二重がけ/付け忘れの構造的防止)。
|
|
89
|
+
* - 地が Surface-Secondary なので、配下 `Card` の既定サーフェスを白にする文脈
|
|
90
|
+
* (`--card-surface`)をシェルが宣言する。`Card` は `surface` 未指定のまま地から浮く(#150)。
|
|
89
91
|
*
|
|
90
92
|
* 管理画面の集中編集は `WorkspaceShell`(EC 購入導線=本コンポーネント)。
|
|
91
93
|
* 判断基準は contracts/screen-patterns.json(focused-workspace)を参照。
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type VariantProps } from "class-variance-authority";
|
|
2
|
+
/** 選択されたファイルが受理されなかったときのコールバック引数。 */
|
|
3
|
+
export interface ImageInputValidationError {
|
|
4
|
+
/** `accept`: 形式不一致 / `max-size`: サイズ上限超過 */
|
|
5
|
+
code: "accept" | "max-size";
|
|
6
|
+
/** 受理されなかったファイル */
|
|
7
|
+
file: File;
|
|
8
|
+
/** 表示に使う日本語メッセージ */
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* accept(例: "image/png,image/jpeg" / "image/*")に対して File の MIME を検査する。
|
|
13
|
+
* ネイティブの accept はファイル選択ダイアログの絞り込みでしかなく強制力がないため、
|
|
14
|
+
* 選択後に必ずここで検査する。accept が空なら全許可。
|
|
15
|
+
*/
|
|
16
|
+
export declare function isAcceptedImageType(file: File, accept: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* accept を日本語エラー文言用の形式名に整形する(例: "image/png,image/jpeg" → "PNG、JPEG")。
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatAcceptedFormats(accept: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* 上限サイズ(MB)を表示用に整形する(1MB 未満は KB 表記)。
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatMaxSize(maxSizeMb: number): string;
|
|
25
|
+
/**
|
|
26
|
+
* プレビュー枠の寸法。
|
|
27
|
+
* 任意値 px は 4px グリッド上の値(156=4×39 / 380=4×95 / 568=4×142)で、
|
|
28
|
+
* 「画像入力の枠サイズ」という固有寸法のため spacing トークンの対象外。
|
|
29
|
+
* landscape は OGP 相当の 1200:630(≒1.9:1)。
|
|
30
|
+
*/
|
|
31
|
+
declare const imageInputPreviewVariants: (props?: {
|
|
32
|
+
aspect?: "square" | "landscape";
|
|
33
|
+
size?: "sm" | "lg" | "md";
|
|
34
|
+
} & import("class-variance-authority/types").ClassProp) => string;
|
|
35
|
+
export interface ImageInputProps extends VariantProps<typeof imageInputPreviewVariants> {
|
|
36
|
+
/**
|
|
37
|
+
* 現在の値。`File`=新規に選択された画像 / `string`=保存済み画像の URL / `null`=未設定。
|
|
38
|
+
* 制御コンポーネントのため必ず渡す。
|
|
39
|
+
*/
|
|
40
|
+
value: File | string | null;
|
|
41
|
+
/** 値の変更。クリア時は `null` が渡る。検証を通ったファイルだけが渡る。 */
|
|
42
|
+
onChange: (file: File | null) => void;
|
|
43
|
+
/** フォーカスが部品の外へ抜けたときに呼ぶ(React Hook Form の touched 連携用) */
|
|
44
|
+
onBlur?: () => void;
|
|
45
|
+
/** 内包する `<input type="file">` の id。Label / FormField の htmlFor と揃える。 */
|
|
46
|
+
id?: string;
|
|
47
|
+
/** input name(フォーム送信用) */
|
|
48
|
+
name?: string;
|
|
49
|
+
/** 受け付ける MIME/拡張子 */
|
|
50
|
+
accept?: string;
|
|
51
|
+
/** 1ファイルあたりの上限サイズ(MB)。超過ファイルは受理しない。 */
|
|
52
|
+
maxSizeMb?: number;
|
|
53
|
+
/** プレビューの表示方法 */
|
|
54
|
+
objectFit?: "cover" | "contain";
|
|
55
|
+
/** 無効化 */
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
/** クリアボタンを表示する。false で「画像を必ず1枚持つ」入力にできる。 */
|
|
58
|
+
clearable?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* 外部(React Hook Form 等)から与えるエラーメッセージ。
|
|
61
|
+
* 指定するとこちらが優先して表示される(内蔵検証のエラーより上位)。
|
|
62
|
+
*/
|
|
63
|
+
error?: string;
|
|
64
|
+
/**
|
|
65
|
+
* 内蔵検証で弾かれたときのコールバック。
|
|
66
|
+
* 既定ではインラインの FieldError に日本語で表示されるため、
|
|
67
|
+
* Dialog / トーストで通知したい場合のみ使う。
|
|
68
|
+
*/
|
|
69
|
+
onValidationError?: (error: ImageInputValidationError) => void;
|
|
70
|
+
/** プレビュー画像の alt */
|
|
71
|
+
alt?: string;
|
|
72
|
+
/** 未選択時にプレビュー枠へ表示する文言 */
|
|
73
|
+
placeholder?: string;
|
|
74
|
+
/** 「画像を選択」ボタンの文言 */
|
|
75
|
+
buttonLabel?: string;
|
|
76
|
+
/** 説明文などの id(内包 input の aria-describedby に連結する) */
|
|
77
|
+
"aria-describedby"?: string;
|
|
78
|
+
/** 追加クラス(ルート要素) */
|
|
79
|
+
className?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* ## ImageInput / 画像入力
|
|
83
|
+
*
|
|
84
|
+
* **1枚の画像**を選ぶフォーム部品。プレビュー + ファイル選択 + 形式/サイズ検証 + クリアを内包する。
|
|
85
|
+
* 値は `File | string | null`(`string` は保存済み画像の URL)で、そのままフォームの値として扱える。
|
|
86
|
+
*
|
|
87
|
+
* ### FileInput / ImageUploader との使い分け
|
|
88
|
+
* | 用途 | 使う部品 |
|
|
89
|
+
* |------|---------|
|
|
90
|
+
* | 画像 1 枚の入力(プレビュー付き・値をフォームに持つ) | **ImageInput**(primitives) |
|
|
91
|
+
* | 画像以外も含む汎用の添付(PDF / CSV 等・1行表示) | `FileInput`(foundations) |
|
|
92
|
+
* | 複数枚の画像を並べて管理するグリッド(追加・削除・並び順) | `ImageUploader`(primitives) |
|
|
93
|
+
*
|
|
94
|
+
* ### インポート
|
|
95
|
+
* ```tsx
|
|
96
|
+
* import { ImageInput } from "../../components/primitives/image-input"
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* ### 表示サイズ
|
|
100
|
+
* `aspect`(square / landscape)× `size`(sm / md / lg)の組み合わせで指定する。
|
|
101
|
+
* 例: 正方形サムネイル=`aspect="square" size="sm"` / OGP 相当のバナー=`aspect="landscape" size="lg"`。
|
|
102
|
+
*
|
|
103
|
+
* ### エラー表示
|
|
104
|
+
* 形式・サイズの検証エラーは**インラインの `FieldError`**(`role="alert"`)に日本語で表示し、
|
|
105
|
+
* 内包 input に `aria-invalid` / `aria-describedby` を付けて紐付ける。
|
|
106
|
+
* モーダルで通知したい場合だけ `onValidationError` を使って consumer 側で出す。
|
|
107
|
+
*
|
|
108
|
+
* ### 非同期検証
|
|
109
|
+
* 画像の寸法チェック等の非同期検証は本部品には持たせていない。
|
|
110
|
+
* `onChange` を受けた consumer 側で検証し、結果を `error` prop で戻す。
|
|
111
|
+
*
|
|
112
|
+
* ### AI 向け使用ルール
|
|
113
|
+
* - `<input type="file">` + `<img>` で画像入力を手組みしない
|
|
114
|
+
* - `value` / `onChange` の制御コンポーネント。保存済み画像は URL 文字列をそのまま渡す
|
|
115
|
+
* - ラベル・必須バッジは `FormField` でラップし、`id` を `htmlFor` と揃える
|
|
116
|
+
* - プレビューの objectURL は内部で解放される。consumer 側で createObjectURL しない
|
|
117
|
+
*/
|
|
118
|
+
declare function ImageInput({ value, onChange, onBlur, id, name, accept, maxSizeMb, aspect, size, objectFit, disabled, clearable, error, onValidationError, alt, placeholder, buttonLabel, className, "aria-describedby": ariaDescribedby, }: ImageInputProps): import("react/jsx-runtime").JSX.Element;
|
|
119
|
+
export { ImageInput, imageInputPreviewVariants };
|
|
@@ -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
|
-
/**
|
|
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
|
|
26
|
-
|
|
55
|
+
declare const sectionScrimVariants: (props?: {
|
|
56
|
+
scrim?: "none" | "light" | "dark" | "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 };
|
|
@@ -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 を参照。
|