kaze-design-system 0.3.3 → 0.4.1
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 +84 -44
- package/components.css +126 -0
- package/dist/components/Disclosure/Disclosure.js +131 -0
- package/dist/hooks/useLegendToggle.js +5 -3
- package/dist/index.js +2 -0
- package/dist/types/components/Disclosure/Disclosure.d.ts +38 -0
- package/dist/types/components/Disclosure/index.d.ts +2 -0
- package/dist/types/components/index.d.ts +2 -0
- package/dist/types/hooks/useLegendToggle.d.ts +13 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,55 +1,78 @@
|
|
|
1
|
-
#
|
|
1
|
+
# kaze-design-system
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/kaze-design-system)
|
|
3
4
|
[](https://github.com/yuki930/kaze-design-system/blob/main/LICENSE)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
**Kaze (風)** は、管理画面・ダッシュボード・金融系アプリのための React デザインシステムです。**白と温かみのあるグレーを基調にした静かな配色**と、日本語組版への丁寧な最適化(PALT・和欧混植・読みやすい行間)、そしてコピペで完結する 63 のコンポーネントを 1 パッケージにまとめています。派手な色や装飾ではなく「読みやすさ」「情報密度」「長時間見続けても疲れないこと」を設計の中心に置いています。
|
|
6
7
|
|
|
7
|
-
**
|
|
8
|
+
- 🎨 **63 コンポーネント** — フォーム、テーブル、チャート、ダッシュボード UI、ランディングページ、マーケティングパーツまで
|
|
9
|
+
- 🌏 **日本語組版に最適化** — PALT グローバル適用、和欧混植、括弧ツメ、適切な line-height
|
|
10
|
+
- 🌓 **ライト / ダーク両対応** — `data-theme` 属性で切替、`prefers-color-scheme` 連動
|
|
11
|
+
- 🎯 **素の CSS + カスケードレイヤー** — `@layer tokens, reset, components, utilities` でカスケード管理、Tailwind/CSS-in-JS 不要
|
|
12
|
+
- 📦 **ESM only + Tree-shakeable** — React 19 + TypeScript、peer deps は `react`, `react-dom`, `lucide-react` のみ
|
|
13
|
+
- 🤖 **AI フレンドリー** — [`/llms.txt`](https://kaze-design-system.vercel.app/llms.txt) で全コンポーネント API を 1 ファイル配信
|
|
14
|
+
|
|
15
|
+
## 🚀 Links
|
|
16
|
+
|
|
17
|
+
| | |
|
|
18
|
+
|---|---|
|
|
19
|
+
| **ライブプレビュー (ショーケース)** | https://kaze-design-system.vercel.app |
|
|
20
|
+
| **コンポーネントドキュメント** | https://kaze-design-system.vercel.app/docs/components |
|
|
21
|
+
| **サンプルページギャラリー** | https://kaze-design-system.vercel.app/gallery |
|
|
22
|
+
| **npm パッケージ** | https://www.npmjs.com/package/kaze-design-system |
|
|
23
|
+
| **GitHub** | https://github.com/yuki930/kaze-design-system |
|
|
24
|
+
|
|
25
|
+
## 🖼 Live Examples
|
|
26
|
+
|
|
27
|
+
実際のアプリケーション/ページ単位のサンプル実装。Vercel にデプロイされています:
|
|
28
|
+
|
|
29
|
+
### ダッシュボード / 管理画面
|
|
30
|
+
- [**分析ダッシュボード**](https://kaze-design-system.vercel.app/dashboard) — メトリック、チャート、テーブル組み合わせ
|
|
31
|
+
- [**Analytics**](https://kaze-design-system.vercel.app/analytics) — KPI 一覧、BarList、Tracker
|
|
32
|
+
- [**SaaS Stats**](https://kaze-design-system.vercel.app/saas-stats) — SaaS 系ダッシュボード
|
|
33
|
+
- [**EC ダッシュボード**](https://kaze-design-system.vercel.app/ec-dashboard) — EC 管理画面
|
|
34
|
+
- [**設定画面**](https://kaze-design-system.vercel.app/settings) — フォーム・FormField 活用例
|
|
35
|
+
|
|
36
|
+
### ランディング・マーケティング
|
|
37
|
+
- [**LP (SaaS)**](https://kaze-design-system.vercel.app/lp) — Hero, Features, Pricing, Testimonial, FAQ, CTA
|
|
38
|
+
- [**LP 2**](https://kaze-design-system.vercel.app/lp2) — 異なる雰囲気の LP
|
|
39
|
+
- [**Pricing**](https://kaze-design-system.vercel.app/pricing) — 料金プラン
|
|
40
|
+
- [**Blog**](https://kaze-design-system.vercel.app/blog) — 記事一覧・記事詳細
|
|
41
|
+
- [**Jobs**](https://kaze-design-system.vercel.app/jobs) — 求人ページ
|
|
42
|
+
|
|
43
|
+
### アプリケーション
|
|
44
|
+
- [**Login**](https://kaze-design-system.vercel.app/login) — 認証画面
|
|
45
|
+
- [**Todo**](https://kaze-design-system.vercel.app/todo) — シンプルな Todo アプリ
|
|
46
|
+
- [**Shopping**](https://kaze-design-system.vercel.app/shopping) — EC 商品一覧
|
|
47
|
+
- [**Article**](https://kaze-design-system.vercel.app/article) — 記事ページ
|
|
48
|
+
- [**Help**](https://kaze-design-system.vercel.app/help) — ヘルプセンター
|
|
8
49
|
|
|
9
50
|
> **ESM only** — このパッケージは ES Modules のみを提供します。
|
|
10
51
|
> `"type": "module"` が設定された環境、または ESM 対応バンドラー(Vite, Next.js, webpack 5+)で使用してください。
|
|
11
52
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm install @kaze-ds/react
|
|
16
|
-
```
|
|
53
|
+
## For AI assistants (Claude / Cursor / ChatGPT)
|
|
17
54
|
|
|
18
|
-
|
|
55
|
+
AI コーディングアシスタントは以下のファイルからライブラリの全コンポーネント API を 1 リクエストで取得できます:
|
|
19
56
|
|
|
20
|
-
|
|
57
|
+
- **Short index**: https://kaze-design-system.vercel.app/llms.txt
|
|
58
|
+
- **Full API reference**: https://kaze-design-system.vercel.app/llms-full.txt
|
|
21
59
|
|
|
22
|
-
|
|
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
|
-
```
|
|
60
|
+
`llms-full.txt` には 62 コンポーネントの `Props` / `Usage` / カテゴリが機械可読形式で含まれており、Storybook を参照しなくても正確なコード提案が可能です。[llmstxt.org](https://llmstxt.org) 準拠。
|
|
32
61
|
|
|
33
|
-
|
|
62
|
+
## インストール
|
|
34
63
|
|
|
35
64
|
```bash
|
|
36
|
-
|
|
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
|
|
65
|
+
npm install kaze-design-system
|
|
45
66
|
```
|
|
46
67
|
|
|
68
|
+
Peer dependencies: `react@^19`, `react-dom@^19`, `lucide-react`
|
|
69
|
+
|
|
47
70
|
## CSS の読み込み
|
|
48
71
|
|
|
49
72
|
### まとめて読み込む(推奨)
|
|
50
73
|
|
|
51
74
|
```ts
|
|
52
|
-
import "
|
|
75
|
+
import "kaze-design-system/css/all";
|
|
53
76
|
```
|
|
54
77
|
|
|
55
78
|
`css/all` は tokens / reset / components / utilities を `@layer` 付きでまとめたエントリポイントです。
|
|
@@ -58,10 +81,10 @@ CSS カスケードレイヤーにより詳細度が管理されるため、上
|
|
|
58
81
|
### 個別読み込み
|
|
59
82
|
|
|
60
83
|
```ts
|
|
61
|
-
import "
|
|
62
|
-
import "
|
|
63
|
-
import "
|
|
64
|
-
import "
|
|
84
|
+
import "kaze-design-system/css/tokens";
|
|
85
|
+
import "kaze-design-system/css/reset";
|
|
86
|
+
import "kaze-design-system/css/components";
|
|
87
|
+
import "kaze-design-system/css/utilities";
|
|
65
88
|
```
|
|
66
89
|
|
|
67
90
|
### Next.js App Router
|
|
@@ -70,14 +93,13 @@ import "@kaze-ds/react/css/utilities";
|
|
|
70
93
|
|
|
71
94
|
```tsx
|
|
72
95
|
// app/layout.tsx
|
|
73
|
-
import "
|
|
96
|
+
import "kaze-design-system/css/all";
|
|
74
97
|
```
|
|
75
98
|
|
|
76
99
|
## 基本的な使い方
|
|
77
100
|
|
|
78
101
|
```tsx
|
|
79
|
-
import { Button, Card, CardHeader, CardTitle, CardBody } from "
|
|
80
|
-
import { ThemeProvider } from "@kaze-ds/react/hooks";
|
|
102
|
+
import { Button, Card, CardHeader, CardTitle, CardBody, ThemeProvider } from "kaze-design-system";
|
|
81
103
|
|
|
82
104
|
function App() {
|
|
83
105
|
return (
|
|
@@ -95,23 +117,36 @@ function App() {
|
|
|
95
117
|
}
|
|
96
118
|
```
|
|
97
119
|
|
|
98
|
-
## コンポーネント一覧(
|
|
120
|
+
## コンポーネント一覧(63 コンポーネント)
|
|
99
121
|
|
|
100
122
|
| カテゴリ | コンポーネント |
|
|
101
123
|
|---|---|
|
|
102
|
-
| **フォーム** | Button, FAB, Input, NumberField, Select, Checkbox, Radio, Textarea, Switch, FormField |
|
|
103
|
-
| **データ表示** | Card, Badge, Table, Metric, Avatar, BarList, Tracker, Watermark |
|
|
124
|
+
| **フォーム** | Button, FAB, Input, NumberField, Select, Checkbox, Radio, Textarea, Switch, FormField, FilterPill |
|
|
125
|
+
| **データ表示** | Card, Badge, StatusBadge, Table, Metric, Avatar, BarList, Tracker, Watermark |
|
|
104
126
|
| **チャート** | BarChart, DonutChart, Sparkline |
|
|
105
127
|
| **フィードバック** | Alert, Progress, Meter, Skeleton, EmptyState, Toast |
|
|
106
|
-
| **ナビゲーション** | Tabs, Sidebar, TopBar, Breadcrumb, Pagination, Stepper |
|
|
107
|
-
| **オーバーレイ** | Dialog, Tooltip, Dropdown, CommandPalette |
|
|
128
|
+
| **ナビゲーション** | Tabs, Sidebar, TopBar, Breadcrumb, Pagination, Stepper, Disclosure |
|
|
129
|
+
| **オーバーレイ** | Dialog, Tooltip, HelpButton, Dropdown, CommandPalette |
|
|
108
130
|
| **レイアウト** | AppLayout, Divider, Grid, Search, Logo, Icon, Heading, Text |
|
|
109
131
|
| **リスト** | List, DescriptionList, Timeline |
|
|
110
132
|
| **マーケティング** | Navbar, Hero, Section, SplitSection, FeatureGrid, Stats, Pricing, Testimonial, FAQ, CTABanner, LPFooter |
|
|
111
133
|
|
|
134
|
+
詳細は [kaze-design-system.vercel.app/docs/components](https://kaze-design-system.vercel.app/docs/components) を参照してください。
|
|
135
|
+
|
|
136
|
+
## Hooks
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { ThemeProvider, useTheme, useFocusTrap } from "kaze-design-system";
|
|
140
|
+
import { useLegendToggle } from "kaze-design-system/hooks";
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- `useTheme` — ライト/ダークの切り替え
|
|
144
|
+
- `useFocusTrap` — モーダル向けフォーカストラップ
|
|
145
|
+
- `useLegendToggle` — Recharts の凡例クリックで系列 show/hide を切り替え
|
|
146
|
+
|
|
112
147
|
## デザイントークン
|
|
113
148
|
|
|
114
|
-
CSS
|
|
149
|
+
CSS カスタムプロパティベース:
|
|
115
150
|
|
|
116
151
|
- カラー: `--color-*`(warm zinc パレット)
|
|
117
152
|
- スペーシング: `--space-*`
|
|
@@ -130,10 +165,15 @@ CSS カスタムプロパティベース:
|
|
|
130
165
|
npm run dev # Next.js 開発サーバー(サンプル集 & ドキュメント)
|
|
131
166
|
npm run build # Next.js 本番ビルド
|
|
132
167
|
npm run build:lib # ライブラリビルド(dist/ に出力)
|
|
168
|
+
npm run docs:llms # llms.txt / llms-full.txt を再生成
|
|
133
169
|
npm run storybook # Storybook 起動
|
|
134
170
|
npm run typecheck # TypeScript 型チェック
|
|
135
171
|
```
|
|
136
172
|
|
|
173
|
+
### リリース
|
|
174
|
+
|
|
175
|
+
main への push 時に GitHub Actions が自動で `npm version patch` → build → `npm publish` を実行します。ライブラリ本体(`src/components/**`, `src/hooks/**`, CSS ファイル等)への変更がある場合のみトリガーされます。
|
|
176
|
+
|
|
137
177
|
## コントリビュート
|
|
138
178
|
|
|
139
179
|
バグ報告・機能リクエストは [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
|
-
|
|
26
|
+
const dataKey = e?.dataKey;
|
|
27
|
+
if (dataKey != null) toggle(String(dataKey));
|
|
27
28
|
},
|
|
28
29
|
formatter: (value, entry) => {
|
|
29
|
-
const
|
|
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)" :
|
|
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>>;
|
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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:
|
|
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
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/yuki930/kaze-design-system/issues"
|
|
14
14
|
},
|
|
15
|
-
"description": "
|
|
15
|
+
"description": "Minimal React design system for dashboards and Japanese UI — quiet neutral grays, 63 components, light/dark themes, typography tuned for CJK text",
|
|
16
16
|
"keywords": [
|
|
17
17
|
"design-system",
|
|
18
18
|
"react",
|