kaze-design-system 0.3.3 → 0.4.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/README.md CHANGED
@@ -1,55 +1,40 @@
1
- # @kaze-ds/react
1
+ # kaze-design-system
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/kaze-design-system)](https://www.npmjs.com/package/kaze-design-system)
3
4
  [![GitHub](https://img.shields.io/github/license/yuki930/kaze-design-system)](https://github.com/yuki930/kaze-design-system/blob/main/LICENSE)
4
5
 
5
- Zinc ベースのミニマルデザインシステム。日本語組版に最適化。
6
+ Zinc ベースのミニマルデザインシステム。日本語組版に最適化。React 19 + TypeScript、62 コンポーネント、ライト/ダーク両対応。
6
7
 
7
- **GitHub**: https://github.com/yuki930/kaze-design-system
8
+ - **Docs**: https://kaze-design-system.vercel.app/docs/components
9
+ - **npm**: https://www.npmjs.com/package/kaze-design-system
10
+ - **GitHub**: https://github.com/yuki930/kaze-design-system
8
11
 
9
12
  > **ESM only** — このパッケージは ES Modules のみを提供します。
10
13
  > `"type": "module"` が設定された環境、または ESM 対応バンドラー(Vite, Next.js, webpack 5+)で使用してください。
11
14
 
12
- ## インストール
13
-
14
- ```bash
15
- npm install @kaze-ds/react
16
- ```
15
+ ## For AI assistants (Claude / Cursor / ChatGPT)
17
16
 
18
- ### ローカル開発(npm link)
17
+ AI コーディングアシスタントは以下のファイルからライブラリの全コンポーネント API を 1 リクエストで取得できます:
19
18
 
20
- 公開前のライブラリをローカルの別プロジェクトで使う場合:
19
+ - **Short index**: https://kaze-design-system.vercel.app/llms.txt
20
+ - **Full API reference**: https://kaze-design-system.vercel.app/llms-full.txt
21
21
 
22
- ```bash
23
- # 1. ライブラリをビルド & リンク
24
- cd kaze-design-system
25
- npm run build:lib
26
- npm link
27
-
28
- # 2. 利用側プロジェクトでリンク
29
- cd ../my-app
30
- npm link @kaze-ds/react
31
- ```
22
+ `llms-full.txt` には 62 コンポーネントの `Props` / `Usage` / カテゴリが機械可読形式で含まれており、Storybook を参照しなくても正確なコード提案が可能です。[llmstxt.org](https://llmstxt.org) 準拠。
32
23
 
33
- ### ローカル開発(npm pack)
24
+ ## インストール
34
25
 
35
26
  ```bash
36
- # 1. ライブラリをビルド & パック
37
- cd kaze-design-system
38
- npm run build:lib
39
- npm pack
40
- # → kaze-ds-react-0.1.0.tgz が生成される
41
-
42
- # 2. 利用側プロジェクトでインストール
43
- cd ../my-app
44
- npm install ../kaze-design-system/kaze-ds-react-0.1.0.tgz
27
+ npm install kaze-design-system
45
28
  ```
46
29
 
30
+ Peer dependencies: `react@^19`, `react-dom@^19`, `lucide-react`
31
+
47
32
  ## CSS の読み込み
48
33
 
49
34
  ### まとめて読み込む(推奨)
50
35
 
51
36
  ```ts
52
- import "@kaze-ds/react/css/all";
37
+ import "kaze-design-system/css/all";
53
38
  ```
54
39
 
55
40
  `css/all` は tokens / reset / components / utilities を `@layer` 付きでまとめたエントリポイントです。
@@ -58,10 +43,10 @@ CSS カスケードレイヤーにより詳細度が管理されるため、上
58
43
  ### 個別読み込み
59
44
 
60
45
  ```ts
61
- import "@kaze-ds/react/css/tokens";
62
- import "@kaze-ds/react/css/reset";
63
- import "@kaze-ds/react/css/components";
64
- import "@kaze-ds/react/css/utilities";
46
+ import "kaze-design-system/css/tokens";
47
+ import "kaze-design-system/css/reset";
48
+ import "kaze-design-system/css/components";
49
+ import "kaze-design-system/css/utilities";
65
50
  ```
66
51
 
67
52
  ### Next.js App Router
@@ -70,14 +55,13 @@ import "@kaze-ds/react/css/utilities";
70
55
 
71
56
  ```tsx
72
57
  // app/layout.tsx
73
- import "@kaze-ds/react/css/all";
58
+ import "kaze-design-system/css/all";
74
59
  ```
75
60
 
76
61
  ## 基本的な使い方
77
62
 
78
63
  ```tsx
79
- import { Button, Card, CardHeader, CardTitle, CardBody } from "@kaze-ds/react";
80
- import { ThemeProvider } from "@kaze-ds/react/hooks";
64
+ import { Button, Card, CardHeader, CardTitle, CardBody, ThemeProvider } from "kaze-design-system";
81
65
 
82
66
  function App() {
83
67
  return (
@@ -95,23 +79,34 @@ function App() {
95
79
  }
96
80
  ```
97
81
 
98
- ## コンポーネント一覧(59 コンポーネント)
82
+ ## コンポーネント一覧(62 コンポーネント)
99
83
 
100
84
  | カテゴリ | コンポーネント |
101
85
  |---|---|
102
- | **フォーム** | Button, FAB, Input, NumberField, Select, Checkbox, Radio, Textarea, Switch, FormField |
103
- | **データ表示** | Card, Badge, Table, Metric, Avatar, BarList, Tracker, Watermark |
86
+ | **フォーム** | Button, FAB, Input, NumberField, Select, Checkbox, Radio, Textarea, Switch, FormField, FilterPill |
87
+ | **データ表示** | Card, Badge, StatusBadge, Table, Metric, Avatar, BarList, Tracker, Watermark |
104
88
  | **チャート** | BarChart, DonutChart, Sparkline |
105
89
  | **フィードバック** | Alert, Progress, Meter, Skeleton, EmptyState, Toast |
106
90
  | **ナビゲーション** | Tabs, Sidebar, TopBar, Breadcrumb, Pagination, Stepper |
107
- | **オーバーレイ** | Dialog, Tooltip, Dropdown, CommandPalette |
91
+ | **オーバーレイ** | Dialog, Tooltip, HelpButton, Dropdown, CommandPalette |
108
92
  | **レイアウト** | AppLayout, Divider, Grid, Search, Logo, Icon, Heading, Text |
109
93
  | **リスト** | List, DescriptionList, Timeline |
110
94
  | **マーケティング** | Navbar, Hero, Section, SplitSection, FeatureGrid, Stats, Pricing, Testimonial, FAQ, CTABanner, LPFooter |
111
95
 
96
+ ## Hooks
97
+
98
+ ```tsx
99
+ import { ThemeProvider, useTheme, useFocusTrap } from "kaze-design-system";
100
+ import { useLegendToggle } from "kaze-design-system/hooks";
101
+ ```
102
+
103
+ - `useTheme` — ライト/ダークの切り替え
104
+ - `useFocusTrap` — モーダル向けフォーカストラップ
105
+ - `useLegendToggle` — Recharts の凡例クリックで系列 show/hide を切り替え
106
+
112
107
  ## デザイントークン
113
108
 
114
- CSS カスタムプロパティベース:
109
+ CSS カスタムプロパティベース:
115
110
 
116
111
  - カラー: `--color-*`(warm zinc パレット)
117
112
  - スペーシング: `--space-*`
@@ -130,10 +125,15 @@ CSS カスタムプロパティベース:
130
125
  npm run dev # Next.js 開発サーバー(サンプル集 & ドキュメント)
131
126
  npm run build # Next.js 本番ビルド
132
127
  npm run build:lib # ライブラリビルド(dist/ に出力)
128
+ npm run docs:llms # llms.txt / llms-full.txt を再生成
133
129
  npm run storybook # Storybook 起動
134
130
  npm run typecheck # TypeScript 型チェック
135
131
  ```
136
132
 
133
+ ### リリース
134
+
135
+ main への push 時に GitHub Actions が自動で `npm version patch` → build → `npm publish` を実行します。ライブラリ本体(`src/components/**`, `src/hooks/**`, CSS ファイル等)への変更がある場合のみトリガーされます。
136
+
137
137
  ## コントリビュート
138
138
 
139
139
  バグ報告・機能リクエストは [Issues](https://github.com/yuki930/kaze-design-system/issues) へお願いします。
package/components.css CHANGED
@@ -4068,3 +4068,129 @@
4068
4068
  .help-popover__body p:last-child {
4069
4069
  margin-bottom: 0;
4070
4070
  }
4071
+
4072
+ /* ================================================================
4073
+ Disclosure
4074
+ ================================================================ */
4075
+
4076
+ .disclosure {
4077
+ display: block;
4078
+ width: 100%;
4079
+ }
4080
+
4081
+ .disclosure--bordered {
4082
+ border: 1px solid var(--color-border);
4083
+ border-radius: var(--radius-md);
4084
+ background: var(--color-surface, var(--color-bg));
4085
+ }
4086
+
4087
+ .disclosure__trigger {
4088
+ display: flex;
4089
+ align-items: center;
4090
+ gap: var(--space-2);
4091
+ width: 100%;
4092
+ padding: var(--space-2) var(--space-3);
4093
+ background: transparent;
4094
+ border: 0;
4095
+ border-radius: var(--radius-sm);
4096
+ cursor: pointer;
4097
+ text-align: left;
4098
+ font-family: inherit;
4099
+ font-size: var(--font-size-base);
4100
+ font-weight: var(--font-weight-medium);
4101
+ color: var(--color-fg);
4102
+ transition: background-color var(--duration-fast) var(--ease-out),
4103
+ color var(--duration-fast) var(--ease-out);
4104
+ }
4105
+
4106
+ .disclosure--sm .disclosure__trigger {
4107
+ padding: var(--space-1) var(--space-2);
4108
+ font-size: var(--font-size-sm);
4109
+ }
4110
+
4111
+ .disclosure--lg .disclosure__trigger {
4112
+ padding: var(--space-3) var(--space-4);
4113
+ font-size: var(--font-size-lg);
4114
+ }
4115
+
4116
+ .disclosure--bordered .disclosure__trigger {
4117
+ border-radius: 0;
4118
+ }
4119
+
4120
+ .disclosure__trigger:hover:not(:disabled) {
4121
+ background: var(--color-bg-subtle, rgba(0, 0, 0, 0.04));
4122
+ }
4123
+
4124
+ .disclosure__trigger:focus-visible {
4125
+ outline: 2px solid var(--color-focus, var(--color-primary));
4126
+ outline-offset: -2px;
4127
+ }
4128
+
4129
+ .disclosure__trigger:disabled {
4130
+ cursor: not-allowed;
4131
+ opacity: 0.5;
4132
+ }
4133
+
4134
+ .disclosure--ghost .disclosure__trigger {
4135
+ padding-left: 0;
4136
+ padding-right: 0;
4137
+ }
4138
+
4139
+ .disclosure--ghost .disclosure__trigger:hover:not(:disabled) {
4140
+ background: transparent;
4141
+ color: var(--color-fg-secondary);
4142
+ }
4143
+
4144
+ .disclosure__title {
4145
+ flex: 1 1 auto;
4146
+ min-width: 0;
4147
+ }
4148
+
4149
+ .disclosure__icon {
4150
+ display: inline-flex;
4151
+ align-items: center;
4152
+ justify-content: center;
4153
+ flex: 0 0 auto;
4154
+ color: var(--color-fg-tertiary);
4155
+ }
4156
+
4157
+ .disclosure__icon--end {
4158
+ margin-left: auto;
4159
+ }
4160
+
4161
+ .disclosure__icon--rotate .disclosure__icon-svg {
4162
+ transition: transform var(--duration-fast) var(--ease-out);
4163
+ }
4164
+
4165
+ .disclosure--open .disclosure__icon--rotate .disclosure__icon-svg {
4166
+ transform: rotate(90deg);
4167
+ }
4168
+
4169
+ .disclosure__content {
4170
+ padding: 0 var(--space-3) var(--space-3) var(--space-3);
4171
+ color: var(--color-fg-secondary);
4172
+ font-size: var(--font-size-sm);
4173
+ line-height: var(--line-height-relaxed);
4174
+ }
4175
+
4176
+ .disclosure--sm .disclosure__content {
4177
+ padding: 0 var(--space-2) var(--space-2) var(--space-2);
4178
+ }
4179
+
4180
+ .disclosure--lg .disclosure__content {
4181
+ padding: 0 var(--space-4) var(--space-4) var(--space-4);
4182
+ }
4183
+
4184
+ .disclosure--ghost .disclosure__content {
4185
+ padding-left: 0;
4186
+ padding-right: 0;
4187
+ }
4188
+
4189
+ .disclosure--bordered .disclosure__content {
4190
+ border-top: 1px solid var(--color-border);
4191
+ padding-top: var(--space-3);
4192
+ }
4193
+
4194
+ .disclosure__content-inner {
4195
+ color: inherit;
4196
+ }
@@ -0,0 +1,131 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import { forwardRef, useState, useCallback, useId, useMemo } from "react";
4
+ import { ChevronRight, Plus } from "lucide-react";
5
+ import { cn } from "../../lib/utils.js";
6
+ function renderIcon(icon) {
7
+ if (icon === "chevron" || icon == null) {
8
+ return /* @__PURE__ */ jsx(ChevronRight, { size: 16, className: "disclosure__icon-svg" });
9
+ }
10
+ if (icon === "plus") {
11
+ return /* @__PURE__ */ jsx(Plus, { size: 16, className: "disclosure__icon-svg" });
12
+ }
13
+ return icon;
14
+ }
15
+ const Disclosure = forwardRef(
16
+ ({
17
+ title,
18
+ children,
19
+ defaultOpen = false,
20
+ open: controlledOpen,
21
+ onOpenChange,
22
+ icon = "chevron",
23
+ iconPosition = "left",
24
+ size = "md",
25
+ variant = "default",
26
+ className,
27
+ triggerClassName,
28
+ contentClassName,
29
+ disabled = false
30
+ }, ref) => {
31
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
32
+ const isControlled = controlledOpen !== void 0;
33
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
34
+ const setOpen = useCallback(
35
+ (next) => {
36
+ if (!isControlled) setUncontrolledOpen(next);
37
+ onOpenChange?.(next);
38
+ },
39
+ [isControlled, onOpenChange]
40
+ );
41
+ const toggle = useCallback(() => {
42
+ if (disabled) return;
43
+ setOpen(!isOpen);
44
+ }, [disabled, isOpen, setOpen]);
45
+ const onKeyDown = useCallback(
46
+ (e) => {
47
+ if (e.key === "Escape" && isOpen) {
48
+ e.preventDefault();
49
+ setOpen(false);
50
+ }
51
+ },
52
+ [isOpen, setOpen]
53
+ );
54
+ const contentId = useId();
55
+ const isBuiltInIcon = icon === "chevron" || icon === "plus";
56
+ const markerNode = useMemo(() => renderIcon(icon), [icon]);
57
+ return /* @__PURE__ */ jsxs(
58
+ "div",
59
+ {
60
+ ref,
61
+ className: cn(
62
+ "disclosure",
63
+ `disclosure--${size}`,
64
+ `disclosure--${variant}`,
65
+ isOpen && "disclosure--open",
66
+ disabled && "disclosure--disabled",
67
+ className
68
+ ),
69
+ "data-state": isOpen ? "open" : "closed",
70
+ children: [
71
+ /* @__PURE__ */ jsxs(
72
+ "button",
73
+ {
74
+ type: "button",
75
+ className: cn(
76
+ "disclosure__trigger",
77
+ `disclosure__trigger--icon-${iconPosition}`,
78
+ triggerClassName
79
+ ),
80
+ "aria-expanded": isOpen,
81
+ "aria-controls": contentId,
82
+ disabled,
83
+ onClick: toggle,
84
+ onKeyDown,
85
+ children: [
86
+ iconPosition === "left" && /* @__PURE__ */ jsx(
87
+ "span",
88
+ {
89
+ className: cn(
90
+ "disclosure__icon",
91
+ isBuiltInIcon && "disclosure__icon--rotate"
92
+ ),
93
+ "aria-hidden": "true",
94
+ children: markerNode
95
+ }
96
+ ),
97
+ /* @__PURE__ */ jsx("span", { className: "disclosure__title", children: title }),
98
+ iconPosition === "right" && /* @__PURE__ */ jsx(
99
+ "span",
100
+ {
101
+ className: cn(
102
+ "disclosure__icon",
103
+ "disclosure__icon--end",
104
+ isBuiltInIcon && "disclosure__icon--rotate"
105
+ ),
106
+ "aria-hidden": "true",
107
+ children: markerNode
108
+ }
109
+ )
110
+ ]
111
+ }
112
+ ),
113
+ /* @__PURE__ */ jsx(
114
+ "div",
115
+ {
116
+ id: contentId,
117
+ role: "region",
118
+ className: cn("disclosure__content", contentClassName),
119
+ hidden: !isOpen,
120
+ children: /* @__PURE__ */ jsx("div", { className: "disclosure__content-inner", children })
121
+ }
122
+ )
123
+ ]
124
+ }
125
+ );
126
+ }
127
+ );
128
+ Disclosure.displayName = "Disclosure";
129
+ export {
130
+ Disclosure
131
+ };
@@ -23,16 +23,18 @@ function useLegendToggle() {
23
23
  cursor: "pointer"
24
24
  },
25
25
  onClick: (e) => {
26
- if (e?.dataKey != null) toggle(String(e.dataKey));
26
+ const dataKey = e?.dataKey;
27
+ if (dataKey != null) toggle(String(dataKey));
27
28
  },
28
29
  formatter: (value, entry) => {
29
- const key = entry?.dataKey != null ? String(entry.dataKey) : "";
30
+ const e = entry;
31
+ const key = e?.dataKey != null ? String(e.dataKey) : "";
30
32
  const hidden = hiddenSeries.has(key);
31
33
  return /* @__PURE__ */ jsx(
32
34
  "span",
33
35
  {
34
36
  style: {
35
- color: hidden ? "var(--color-fg-tertiary, #a1a1aa)" : entry?.color,
37
+ color: hidden ? "var(--color-fg-tertiary, #a1a1aa)" : e?.color,
36
38
  transition: "color 0.15s ease"
37
39
  },
38
40
  children: value
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import { Checkbox } from "./components/Checkbox/Checkbox.js";
14
14
  import { CommandPalette } from "./components/CommandPalette/CommandPalette.js";
15
15
  import { DescriptionItem, DescriptionList } from "./components/DescriptionList/DescriptionList.js";
16
16
  import { Dialog, DialogBody, DialogFooter, DialogHeader, DialogTitle } from "./components/Dialog/Dialog.js";
17
+ import { Disclosure } from "./components/Disclosure/Disclosure.js";
17
18
  import { Divider } from "./components/Divider/Divider.js";
18
19
  import { DonutChart } from "./components/DonutChart/DonutChart.js";
19
20
  import { Dropdown, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger } from "./components/Dropdown/Dropdown.js";
@@ -87,6 +88,7 @@ export {
87
88
  DialogFooter,
88
89
  DialogHeader,
89
90
  DialogTitle,
91
+ Disclosure,
90
92
  Divider,
91
93
  DonutChart,
92
94
  Dropdown,
@@ -0,0 +1,38 @@
1
+ import { type ReactNode } from "react";
2
+ export type DisclosureIcon = "chevron" | "plus" | ReactNode;
3
+ export type DisclosureIconPosition = "left" | "right";
4
+ export type DisclosureSize = "sm" | "md" | "lg";
5
+ export type DisclosureVariant = "default" | "ghost" | "bordered";
6
+ export interface DisclosureProps {
7
+ /** Always-visible label on the trigger row */
8
+ title: ReactNode;
9
+ /** Content shown when the disclosure is expanded */
10
+ children: ReactNode;
11
+ /** Initial expanded state (uncontrolled) */
12
+ defaultOpen?: boolean;
13
+ /** Controlled expanded state */
14
+ open?: boolean;
15
+ /** Called when the expanded state changes */
16
+ onOpenChange?: (open: boolean) => void;
17
+ /**
18
+ * Marker icon. Use `"chevron"` (default) or `"plus"` for the built-in
19
+ * icons, or pass any ReactNode for a custom marker. Custom markers are
20
+ * not auto-rotated.
21
+ */
22
+ icon?: DisclosureIcon;
23
+ /** Which side the marker appears on */
24
+ iconPosition?: DisclosureIconPosition;
25
+ /** Trigger row density */
26
+ size?: DisclosureSize;
27
+ /** Visual treatment */
28
+ variant?: DisclosureVariant;
29
+ /** Additional class on the root wrapper */
30
+ className?: string;
31
+ /** Additional class on the trigger button */
32
+ triggerClassName?: string;
33
+ /** Additional class on the content region */
34
+ contentClassName?: string;
35
+ /** Disables the trigger */
36
+ disabled?: boolean;
37
+ }
38
+ export declare const Disclosure: import("react").ForwardRefExoticComponent<DisclosureProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ export { Disclosure } from "./Disclosure";
2
+ export type { DisclosureProps, DisclosureIcon, DisclosureIconPosition, DisclosureSize, DisclosureVariant, } from "./Disclosure";
@@ -10,6 +10,8 @@ export { StatusBadge } from "./StatusBadge";
10
10
  export type { StatusBadgeProps, StatusBadgeStatus } from "./StatusBadge";
11
11
  export { HelpButton } from "./HelpButton";
12
12
  export type { HelpButtonProps, HelpButtonPosition, HelpButtonSize, } from "./HelpButton";
13
+ export { Disclosure } from "./Disclosure";
14
+ export type { DisclosureProps, DisclosureIcon, DisclosureIconPosition, DisclosureSize, DisclosureVariant, } from "./Disclosure";
13
15
  export { FilterPill } from "./FilterPill";
14
16
  export type { FilterPillProps } from "./FilterPill";
15
17
  export { Input } from "./Input";
@@ -1,10 +1,15 @@
1
1
  import { type CSSProperties } from "react";
2
- interface RechartsLegendClickEvent {
3
- dataKey?: string | number;
4
- value?: string;
5
- color?: string;
6
- [key: string]: unknown;
7
- }
2
+ /**
3
+ * Public shape of `legendProps`. The `onClick` and `formatter` signatures
4
+ * intentionally use `unknown` (rather than a hand-rolled Recharts shim)
5
+ * so the object is structurally assignable to Recharts' own
6
+ * `<Legend>` props without needing a peer-dep on `recharts`.
7
+ *
8
+ * See kaze-design-system#27 — earlier versions used a narrow custom
9
+ * `RechartsLegendClickEvent` type which failed to unify with Recharts'
10
+ * `LegendProps['onClick']`, forcing downstream users to wrap with
11
+ * `as any`.
12
+ */
8
13
  export interface UseLegendToggleResult {
9
14
  /** Whether a given dataKey is currently hidden */
10
15
  isHidden: (dataKey: string) => boolean;
@@ -15,11 +20,8 @@ export interface UseLegendToggleResult {
15
20
  /** Props to spread onto a Recharts `<Legend />` */
16
21
  legendProps: {
17
22
  wrapperStyle: CSSProperties;
18
- onClick: (e: RechartsLegendClickEvent) => void;
19
- formatter: (value: string, entry: {
20
- dataKey?: string | number;
21
- color?: string;
22
- }) => React.ReactNode;
23
+ onClick: (e: unknown) => void;
24
+ formatter: (value: string, entry: unknown) => React.ReactNode;
23
25
  };
24
26
  }
25
27
  /**
@@ -35,4 +37,3 @@ export interface UseLegendToggleResult {
35
37
  * );
36
38
  */
37
39
  export declare function useLegendToggle(): UseLegendToggleResult;
38
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaze-design-system",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",