@squadbase/vantage 0.0.1 → 0.1.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.
Files changed (187) hide show
  1. package/README.md +24 -4
  2. package/dist/{chunk-ZGDU5YLH.js → chunk-5L2MH2NG.js} +16 -7
  3. package/dist/chunk-5L2MH2NG.js.map +1 -0
  4. package/dist/chunk-7IPAXPPY.js +51 -0
  5. package/dist/chunk-7IPAXPPY.js.map +1 -0
  6. package/dist/chunk-A2UUGASH.js +12 -0
  7. package/dist/chunk-A2UUGASH.js.map +1 -0
  8. package/dist/chunk-DTDVSFRY.js +29 -0
  9. package/dist/chunk-DTDVSFRY.js.map +1 -0
  10. package/dist/chunk-WQZYXXQW.js +2249 -0
  11. package/dist/chunk-WQZYXXQW.js.map +1 -0
  12. package/dist/{chunk-73J5ZD4C.js → chunk-YLAB6UQS.js} +17 -3
  13. package/dist/chunk-YLAB6UQS.js.map +1 -0
  14. package/dist/cli.js +607 -36
  15. package/dist/cli.js.map +1 -1
  16. package/dist/client/index.d.ts +2 -1
  17. package/dist/client/index.js +3 -1
  18. package/dist/client/index.js.map +1 -1
  19. package/dist/components/index.d.ts +575 -0
  20. package/dist/components/index.js +2097 -0
  21. package/dist/components/index.js.map +1 -0
  22. package/dist/{define-page-B6y9TOfZ.d.ts → define-page-BfhrK99G.d.ts} +5 -0
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/markdown/index.d.ts +9 -0
  27. package/dist/markdown/index.js +26 -0
  28. package/dist/markdown/index.js.map +1 -0
  29. package/dist/query/index.d.ts +95 -2
  30. package/dist/query/index.js +102 -1
  31. package/dist/query/index.js.map +1 -1
  32. package/dist/router/index.d.ts +86 -1
  33. package/dist/router/index.js +71 -7
  34. package/dist/router/index.js.map +1 -1
  35. package/dist/server/node.js +6 -1
  36. package/dist/server/node.js.map +1 -1
  37. package/dist/ui/index.d.ts +316 -200
  38. package/dist/ui/index.js +566 -511
  39. package/dist/ui/index.js.map +1 -1
  40. package/dist/vite/index.js +2 -2
  41. package/docs/en/agent-skills.md +89 -0
  42. package/docs/en/api-and-server.md +84 -0
  43. package/docs/en/build-and-deploy.md +280 -0
  44. package/docs/en/cli-reference.md +311 -0
  45. package/docs/en/components.md +235 -0
  46. package/docs/en/data-fetching.md +142 -0
  47. package/docs/en/environment-variables.md +69 -0
  48. package/docs/en/getting-started.md +95 -0
  49. package/docs/en/index.md +65 -0
  50. package/docs/en/markdown/markdown-renderer.md +44 -0
  51. package/docs/en/pages-and-metadata.md +59 -0
  52. package/docs/en/parts/app-shell.md +54 -0
  53. package/docs/en/parts/dashboard-card.md +64 -0
  54. package/docs/en/parts/data-table.md +86 -0
  55. package/docs/en/parts/date-range-picker.md +41 -0
  56. package/docs/en/parts/echart.md +53 -0
  57. package/docs/en/parts/filter-bar.md +66 -0
  58. package/docs/en/parts/funnel-steps.md +33 -0
  59. package/docs/en/parts/metric-value.md +23 -0
  60. package/docs/en/parts/multi-select.md +27 -0
  61. package/docs/en/parts/page-shell.md +45 -0
  62. package/docs/en/parts/placeholder.md +38 -0
  63. package/docs/en/parts/searchable-select.md +47 -0
  64. package/docs/en/parts/section-header.md +20 -0
  65. package/docs/en/parts/segmented-control.md +25 -0
  66. package/docs/en/parts/sparkline.md +47 -0
  67. package/docs/en/parts/status-badge.md +44 -0
  68. package/docs/en/parts/trend-indicator.md +26 -0
  69. package/docs/en/routing.md +177 -0
  70. package/docs/en/ui/accordion.md +36 -0
  71. package/docs/en/ui/alert.md +31 -0
  72. package/docs/en/ui/badge.md +23 -0
  73. package/docs/en/ui/breadcrumb.md +38 -0
  74. package/docs/en/ui/button.md +39 -0
  75. package/docs/en/ui/calendar.md +28 -0
  76. package/docs/en/ui/card.md +35 -0
  77. package/docs/en/ui/checkbox.md +34 -0
  78. package/docs/en/ui/cn.md +34 -0
  79. package/docs/en/ui/collapsible.md +21 -0
  80. package/docs/en/ui/command.md +37 -0
  81. package/docs/en/ui/dialog.md +52 -0
  82. package/docs/en/ui/dropdown-menu.md +50 -0
  83. package/docs/en/ui/empty.md +22 -0
  84. package/docs/en/ui/error-state.md +50 -0
  85. package/docs/en/ui/input-group.md +30 -0
  86. package/docs/en/ui/input.md +28 -0
  87. package/docs/en/ui/label.md +19 -0
  88. package/docs/en/ui/loading.md +19 -0
  89. package/docs/en/ui/popover.md +34 -0
  90. package/docs/en/ui/progress.md +28 -0
  91. package/docs/en/ui/scroll-area.md +23 -0
  92. package/docs/en/ui/select.md +63 -0
  93. package/docs/en/ui/separator.md +15 -0
  94. package/docs/en/ui/sheet.md +28 -0
  95. package/docs/en/ui/sidebar.md +92 -0
  96. package/docs/en/ui/skeleton.md +16 -0
  97. package/docs/en/ui/slider.md +21 -0
  98. package/docs/en/ui/spinner.md +14 -0
  99. package/docs/en/ui/switch.md +19 -0
  100. package/docs/en/ui/table.md +24 -0
  101. package/docs/en/ui/tabs.md +23 -0
  102. package/docs/en/ui/textarea.md +15 -0
  103. package/docs/en/ui/toggle-group.md +26 -0
  104. package/docs/en/ui/toggle.md +19 -0
  105. package/docs/en/ui/tooltip.md +22 -0
  106. package/docs/en/ui/use-is-mobile.md +18 -0
  107. package/docs/en/ui-and-theming.md +95 -0
  108. package/docs/index.json +1346 -0
  109. package/docs/ja/agent-skills.md +87 -0
  110. package/docs/ja/api-and-server.md +84 -0
  111. package/docs/ja/build-and-deploy.md +279 -0
  112. package/docs/ja/cli-reference.md +305 -0
  113. package/docs/ja/components.md +231 -0
  114. package/docs/ja/data-fetching.md +142 -0
  115. package/docs/ja/environment-variables.md +68 -0
  116. package/docs/ja/getting-started.md +95 -0
  117. package/docs/ja/index.md +65 -0
  118. package/docs/ja/markdown/markdown-renderer.md +43 -0
  119. package/docs/ja/pages-and-metadata.md +59 -0
  120. package/docs/ja/parts/app-shell.md +54 -0
  121. package/docs/ja/parts/dashboard-card.md +64 -0
  122. package/docs/ja/parts/data-table.md +85 -0
  123. package/docs/ja/parts/date-range-picker.md +41 -0
  124. package/docs/ja/parts/echart.md +52 -0
  125. package/docs/ja/parts/filter-bar.md +64 -0
  126. package/docs/ja/parts/funnel-steps.md +33 -0
  127. package/docs/ja/parts/metric-value.md +25 -0
  128. package/docs/ja/parts/multi-select.md +27 -0
  129. package/docs/ja/parts/page-shell.md +45 -0
  130. package/docs/ja/parts/placeholder.md +37 -0
  131. package/docs/ja/parts/searchable-select.md +47 -0
  132. package/docs/ja/parts/section-header.md +20 -0
  133. package/docs/ja/parts/segmented-control.md +26 -0
  134. package/docs/ja/parts/sparkline.md +47 -0
  135. package/docs/ja/parts/status-badge.md +44 -0
  136. package/docs/ja/parts/trend-indicator.md +26 -0
  137. package/docs/ja/routing.md +175 -0
  138. package/docs/ja/ui/accordion.md +37 -0
  139. package/docs/ja/ui/alert.md +31 -0
  140. package/docs/ja/ui/badge.md +23 -0
  141. package/docs/ja/ui/breadcrumb.md +38 -0
  142. package/docs/ja/ui/button.md +39 -0
  143. package/docs/ja/ui/calendar.md +28 -0
  144. package/docs/ja/ui/card.md +35 -0
  145. package/docs/ja/ui/checkbox.md +34 -0
  146. package/docs/ja/ui/cn.md +34 -0
  147. package/docs/ja/ui/collapsible.md +21 -0
  148. package/docs/ja/ui/command.md +36 -0
  149. package/docs/ja/ui/dialog.md +51 -0
  150. package/docs/ja/ui/dropdown-menu.md +50 -0
  151. package/docs/ja/ui/empty.md +22 -0
  152. package/docs/ja/ui/error-state.md +50 -0
  153. package/docs/ja/ui/input-group.md +30 -0
  154. package/docs/ja/ui/input.md +28 -0
  155. package/docs/ja/ui/label.md +19 -0
  156. package/docs/ja/ui/loading.md +19 -0
  157. package/docs/ja/ui/popover.md +34 -0
  158. package/docs/ja/ui/progress.md +28 -0
  159. package/docs/ja/ui/scroll-area.md +24 -0
  160. package/docs/ja/ui/select.md +64 -0
  161. package/docs/ja/ui/separator.md +15 -0
  162. package/docs/ja/ui/sheet.md +28 -0
  163. package/docs/ja/ui/sidebar.md +92 -0
  164. package/docs/ja/ui/skeleton.md +16 -0
  165. package/docs/ja/ui/slider.md +21 -0
  166. package/docs/ja/ui/spinner.md +14 -0
  167. package/docs/ja/ui/switch.md +19 -0
  168. package/docs/ja/ui/table.md +24 -0
  169. package/docs/ja/ui/tabs.md +24 -0
  170. package/docs/ja/ui/textarea.md +15 -0
  171. package/docs/ja/ui/toggle-group.md +27 -0
  172. package/docs/ja/ui/toggle.md +19 -0
  173. package/docs/ja/ui/tooltip.md +22 -0
  174. package/docs/ja/ui/use-is-mobile.md +18 -0
  175. package/docs/ja/ui-and-theming.md +95 -0
  176. package/package.json +29 -4
  177. package/registry/blocks/sales-overview.tsx +43 -19
  178. package/registry/ui/data-table.tsx +702 -102
  179. package/skills/vantage-add-feature/SKILL.md +153 -0
  180. package/skills/vantage-app/SKILL.md +291 -0
  181. package/skills/vantage-pitfalls/SKILL.md +139 -0
  182. package/templates/AGENTS.md +313 -0
  183. package/theme.css +178 -40
  184. package/dist/chunk-73J5ZD4C.js.map +0 -1
  185. package/dist/chunk-ATYZ45XL.js +0 -19
  186. package/dist/chunk-ATYZ45XL.js.map +0 -1
  187. package/dist/chunk-ZGDU5YLH.js.map +0 -1
@@ -0,0 +1,64 @@
1
+ # FilterBar
2
+
3
+ > フィルタ一式を 1 つの値オブジェクトで扱う行。
4
+
5
+ 複数のフィルタをまとめて扱う行です。値は `FilterValues`(`{ [key]: string | string[] }`)という
6
+ 1 つのオブジェクトで持ち、選択中の条件をチップで表示したり、一括で消したりできます。
7
+
8
+ ```tsx
9
+ import {
10
+ FilterBar,
11
+ FilterBarSelect,
12
+ FilterBarMultiSelect,
13
+ FilterBarActiveChips,
14
+ FilterBarClearButton,
15
+ FilterBarPreset,
16
+ } from "@squadbase/vantage/components";
17
+ import type { FilterConfig, FilterValues, FilterOption } from "@squadbase/vantage/components";
18
+ ```
19
+
20
+ ## FilterBarPreset
21
+
22
+ `filters` に定義を並べるだけで、セレクト・複数選択・チップ・クリアボタンまで組み上がります。
23
+
24
+ | Prop | Type | 説明 |
25
+ | --- | --- | --- |
26
+ | `filters` | `FilterConfig[]` | フィルタの定義。 |
27
+ | `value` | `FilterValues` | 現在の値。 |
28
+ | `onChange` | `(values: FilterValues) => void` | 変更時。 |
29
+ | `onClear` | `() => void` | クリアボタンを押したとき。 |
30
+
31
+ ```ts
32
+ interface FilterConfig {
33
+ key: string;
34
+ label: string;
35
+ type: "select" | "multiselect" | "date" | "daterange" | "search";
36
+ options?: FilterOption[]; // { label, value, count?, disabled? }
37
+ placeholder?: string;
38
+ defaultValue?: string | string[];
39
+ }
40
+ ```
41
+
42
+ `FilterOption` の `count` を入れると、候補の右に件数が出ます。
43
+
44
+ ## 自分で組む
45
+
46
+ ```tsx
47
+ <FilterBar value={values} onChange={setValues} onClear={() => setValues({})}>
48
+ <FilterBarSelect filterKey="region" label="地域" options={regions} />
49
+ <FilterBarMultiSelect filterKey="status" label="状態" options={statuses} />
50
+ <FilterBarClearButton />
51
+ <FilterBarActiveChips filters={filters} />
52
+ </FilterBar>
53
+ ```
54
+
55
+ ## クエリと繋ぐ
56
+
57
+ `FilterValues` をそのまま `queryKey` に入れると、条件が変わったときだけ再取得されます。
58
+
59
+ ```tsx
60
+ const { data } = useQuery({
61
+ queryKey: ["sales", values],
62
+ queryFn: () => apiFetch(`/api/sales?${new URLSearchParams(values as never)}`).then((r) => r.json()),
63
+ });
64
+ ```
@@ -0,0 +1,33 @@
1
+ # FunnelSteps
2
+
3
+ > ファネルの各段を棒で示す。転換率も出せる。
4
+
5
+ ファネルの各段を、先頭を最大幅とする棒で表します。段の間の転換率も出せます。ECharts を持ち出す
6
+ ほどではない、軽い可視化です。
7
+
8
+ ```tsx
9
+ import { FunnelSteps, funnelStepsVariants } from "@squadbase/vantage/components";
10
+ import type { FunnelStep } from "@squadbase/vantage/components";
11
+ ```
12
+
13
+ | Prop | Type | Default | 説明 |
14
+ | --- | --- | --- | --- |
15
+ | `data` | `FunnelStep[]` | | 各段。**先頭が最大幅**になる。 |
16
+ | `showConversion` | `boolean` | | 段の間に転換率を出す。 |
17
+ | `formatValue` | `(value: number) => string` | | 値の書式。既定はそのまま。 |
18
+ | `animate` | `boolean` | | マウント時に幅を伸ばすアニメーション。 |
19
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` | |
20
+ | `direction` | `"vertical" \| "horizontal"` | `"vertical"` | |
21
+
22
+ ## FunnelStep
23
+
24
+ ```ts
25
+ interface FunnelStep {
26
+ label: string;
27
+ value: number;
28
+ color?: string; // 既定はテーマの chart 色
29
+ onClick?: () => void;
30
+ }
31
+ ```
32
+
33
+ `onClick` を渡した段は押せるようになるので、その段の内訳へドリルダウンさせられます。
@@ -0,0 +1,25 @@
1
+ # MetricValue
2
+
3
+ > KPI の数値。単位は MetricUnit で。
4
+
5
+ KPI の数値を大きく見せるための、字送りを詰めた表示です。単位や補助的な文字は `MetricUnit` で
6
+ 添えます。
7
+
8
+ ```tsx
9
+ import { MetricValue, MetricUnit, metricValueVariants } from "@squadbase/vantage/components";
10
+ ```
11
+
12
+ | Prop | Type | Default | 説明 |
13
+ | --- | --- | --- | --- |
14
+ | `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` | 文字サイズ。 |
15
+ | `className` | `string` | | 足すクラス。 |
16
+
17
+ 既定で上下に余白(`my-4`)が付きます。カードの中でぴったり詰めたいときは `className="my-0"` を
18
+ 渡してください。
19
+
20
+ ```tsx
21
+ <DashboardCardPreset title="売上">
22
+ <MetricValue className="my-0">¥1,240,000</MetricValue>
23
+ <TrendIndicator value={12.4} direction="up" />
24
+ </DashboardCardPreset>
25
+ ```
@@ -0,0 +1,27 @@
1
+ # MultiSelect
2
+
3
+ > 検索できる複数選択。選択はチップで表示。
4
+
5
+ 検索欄付きの複数選択です。選んだものはトリガーにチップとして並び、`maxCount` を超えた分は
6
+ 「+N」にまとめられます。
7
+
8
+ ```tsx
9
+ import { MultiSelect } from "@squadbase/vantage/components";
10
+ import type { SelectOption, SelectOptionGroup } from "@squadbase/vantage/components";
11
+ ```
12
+
13
+ | Prop | Type | 説明 |
14
+ | --- | --- | --- |
15
+ | `options` | `SelectOption[] \| SelectOptionGroup[]` | 候補。グループ配列を渡すと見出し付きになる。 |
16
+ | `value` | `string[]` | 選択中の値。 |
17
+ | `onChange` | `(value: string[]) => void` | 変更時。 |
18
+ | `maxCount` | `number` | チップとして並べる上限。超えた分は「+N」になる。 |
19
+ | `onSearch` | `(query: string) => void` | 入力のたびに呼ばれる。サーバー側検索に使う。 |
20
+ | `isLoading` | `boolean` | 候補を取得中。 |
21
+ | `placeholder` | `string` | 未選択時のトリガー表示。 |
22
+ | `searchPlaceholder` | `string` | 検索欄のプレースホルダ。 |
23
+ | `emptyText` | `string` | 0 件のときの表示。 |
24
+ | `disabled` | `boolean` | 操作を無効にする。 |
25
+
26
+ フィルタ行の中で使うなら、[`FilterBar`](parts/filter-bar) の `FilterBarMultiSelect`
27
+ が値の受け渡しまで面倒を見てくれます。
@@ -0,0 +1,45 @@
1
+ # PageShell
2
+
3
+ > ヘッダー帯・サマリー・本文からなるページ枠。
4
+
5
+ 1 ページぶんの枠です。全幅のヘッダー帯、その中に置けるサマリーカードの行、そして本文の 3 段で
6
+ できています。各パーツは薄い `<div>` なので、必要なものだけ使えます。
7
+
8
+ ```tsx
9
+ import {
10
+ PageShell,
11
+ PageShellHeader,
12
+ PageShellHeading,
13
+ PageShellTitle,
14
+ PageShellDescription,
15
+ PageShellHeaderEnd,
16
+ PageShellMeta,
17
+ PageShellActions,
18
+ PageShellSummary,
19
+ PageShellSummaryCard,
20
+ PageShellContent,
21
+ pageShellSummaryCardVariants,
22
+ } from "@squadbase/vantage/components";
23
+ ```
24
+
25
+ ## パーツ
26
+
27
+ | パーツ | 役割 |
28
+ | --- | --- |
29
+ | `PageShell` | 全体の縦積み |
30
+ | `PageShellHeader` | 下線付きのヘッダー帯。左に見出し、右に `HeaderEnd` の 2 列 |
31
+ | `PageShellHeading` / `PageShellTitle` / `PageShellDescription` | 見出しブロック |
32
+ | `PageShellHeaderEnd` | 右端の縦積み |
33
+ | `PageShellMeta` | 「最終更新 10 分前」のような補足 |
34
+ | `PageShellActions` | ボタン行 |
35
+ | `PageShellSummary` | サマリーカードのグリッド(ヘッダー内で全幅) |
36
+ | `PageShellSummaryCard` | サマリー 1 枚。`accent` で色が付く |
37
+ | `PageShellContent` | 本文 |
38
+
39
+ `PageShellSummaryCard` の `accent` は `default` / `accent` / `amber` / `blue` / `emerald` / `red`
40
+ です。`accent` はテーマの `--chart-1` を使うので、テーマトークンを変えると一緒に変わります。
41
+
42
+ ## レイアウトと組み合わせる
43
+
44
+ ページごとに書くより、`_layout.tsx` に置いて全ページで共有する方が実際的です
45
+ ([ルーティング](routing) を参照)。
@@ -0,0 +1,37 @@
1
+ # Placeholder
2
+
3
+ > 仮データであることを示す、インラインの目印。
4
+
5
+ まだ本物のデータを繋いでいない箇所を「仮置き」として見せます。薄い色と `animate-pulse` が
6
+ **「ここは差し替える値だ」**という合図になり、実データを入れ忘れたまま共有してしまう事故を防ぎます。
7
+
8
+ ```tsx
9
+ import { Placeholder } from "@squadbase/vantage/components";
10
+ ```
11
+
12
+ | Prop | Type | 説明 |
13
+ | --- | --- | --- |
14
+ | `children` | `ReactNode` | 仮の値。文字列でも要素でもよい。 |
15
+ | `className` | `string` | 大きさ・太さなどの上書き(例: `text-2xl font-medium`)。 |
16
+
17
+ 残りの props は `<span>` にそのまま渡ります。
18
+
19
+ ## `Skeleton` との違い
20
+
21
+ | | 用途 | 要素 |
22
+ | --- | --- | --- |
23
+ | [`Skeleton`](ui/skeleton) | **読み込み中**。実データが来れば消える | ブロック `<div>` |
24
+ | `Placeholder` | **仮の値**。実装者が差し替えるまで残る | インライン `<span>` |
25
+
26
+ インライン要素なので、`<p>` や見出しの**文中に置けます**。`Skeleton` はブロック要素なので、
27
+ 文中に混ぜると行が崩れます。
28
+
29
+ ```tsx
30
+ <p>
31
+ 今月の売上は <Placeholder>¥1,240,000</Placeholder> でした。
32
+ </p>
33
+ ```
34
+
35
+ > [!TIP]
36
+ > テンプレートから作り始めたときは、`Placeholder` を検索して潰していけば「まだ繋いでいない箇所」の
37
+ > チェックリストになります。
@@ -0,0 +1,47 @@
1
+ # SearchableSelect
2
+
3
+ > 検索できる単一選択。候補が多いときに。
4
+
5
+ 検索欄の付いた単一選択です。候補が多くて [`Select`](ui/select) では探しづらいときに
6
+ 使います。`onSearch` を渡せばサーバー側検索にもできます。
7
+
8
+ ```tsx
9
+ import { SearchableSelect } from "@squadbase/vantage/components";
10
+ import type { SelectOption, SelectOptionGroup } from "@squadbase/vantage/components";
11
+ ```
12
+
13
+ | Prop | Type | 説明 |
14
+ | --- | --- | --- |
15
+ | `options` | `SelectOption[] \| SelectOptionGroup[]` | 候補。グループ配列を渡すと見出し付きになる。 |
16
+ | `value` | `string` | 選択中の値。 |
17
+ | `onChange` | `(value: string \| undefined) => void` | 変更時。 |
18
+ | `onSearch` | `(query: string) => void` | 入力のたびに呼ばれる。サーバー側検索に使う。 |
19
+ | `clearable` | `boolean` | 選択解除できるようにする。 |
20
+ | `isLoading` | `boolean` | 候補を取得中。 |
21
+ | `placeholder` | `string` | 未選択時のトリガー表示。 |
22
+ | `searchPlaceholder` | `string` | 検索欄のプレースホルダ。 |
23
+ | `emptyText` | `string` | 0 件のときの表示。 |
24
+ | `disabled` | `boolean` | 操作を無効にする。 |
25
+
26
+ ## サーバー側で検索する
27
+
28
+ `onSearch` を渡して `options` を差し替えます。絞り込みはサーバーの仕事になるので、返ってきた
29
+ 候補をそのまま渡してください。
30
+
31
+ ```tsx
32
+ const [query, setQuery] = useState("");
33
+ const { data, isFetching } = useQuery({
34
+ queryKey: ["customers", query],
35
+ queryFn: () => apiFetch(`/api/customers?q=${query}`).then((r) => r.json()),
36
+ });
37
+
38
+ <SearchableSelect
39
+ options={data ?? []}
40
+ onSearch={setQuery}
41
+ isLoading={isFetching}
42
+ value={value}
43
+ onChange={setValue}
44
+ />;
45
+ ```
46
+
47
+ 複数選べるようにしたいときは [`MultiSelect`](parts/multi-select) を使います。
@@ -0,0 +1,20 @@
1
+ # SectionHeader
2
+
3
+ > セクションの見出しとアクション。
4
+
5
+ ページの中でセクションを区切る見出しです。見出しレベルは `as` で選べます。
6
+
7
+ ```tsx
8
+ import { SectionHeader } from "@squadbase/vantage/components";
9
+ ```
10
+
11
+ | Prop | Type | Default | 説明 |
12
+ | --- | --- | --- | --- |
13
+ | `title` | `string` | | 見出し。 |
14
+ | `description` | `string` | | 見出しの下の補足文。 |
15
+ | `actions` | `ReactNode` | | 右端に置く要素。 |
16
+ | `as` | `"h1" \| "h2" \| "h3" \| "h4"` | `"h2"` | 見出しレベル。文字サイズも一緒に変わる。 |
17
+ | `className` | `string` | | 足すクラス。 |
18
+
19
+ ページ全体の見出しには [`PageShell`](parts/page-shell) のヘッダー帯を使ってください。
20
+ `SectionHeader` はその中のセクション向けです。
@@ -0,0 +1,26 @@
1
+ # SegmentedControl
2
+
3
+ > 単一選択のセグメント。ToggleGroup の配列を隠す。
4
+
5
+ 2〜4 個の選択肢を横一列で切り替えます。中身は [`ToggleGroup`](ui/toggle-group) ですが、
6
+ **単一選択なので `value` は文字列 1 つ**です — Base UI の配列 API を扱う手間はここで吸収されて
7
+ います。
8
+
9
+ ```tsx
10
+ import { SegmentedControl } from "@squadbase/vantage/components";
11
+ import type { SegmentOption } from "@squadbase/vantage/components";
12
+ ```
13
+
14
+ | Prop | Type | Default | 説明 |
15
+ | --- | --- | --- | --- |
16
+ | `options` | `SegmentOption[]` | | `{ label, value, icon?, disabled? }` の配列。 |
17
+ | `value` | `string` | | 選択中の値(**文字列 1 つ**)。 |
18
+ | `onChange` | `(value: string) => void` | | 変更時。 |
19
+ | `size` | `"sm" \| "default" \| "lg"` | `"default"` | アイコンの大きさ。 |
20
+ | `fullWidth` | `boolean` | | 親の幅いっぱいに広げる。 |
21
+ | `ariaLabel` | `string` | | グループ全体の説明。 |
22
+
23
+ `icon` には `lucide-react` のコンポーネントをそのまま渡せます。
24
+
25
+ 選択肢が 5 個を超えるなら [`Select`](ui/select)、切り替える対象がページ相当なら
26
+ [`Tabs`](ui/tabs) の方が向いています。
@@ -0,0 +1,47 @@
1
+ # Sparkline
2
+
3
+ > 表のセルや KPI タイルに置く、インラインの推移グラフ。
4
+
5
+ 数値の並びを、軸も凡例もない小さな折れ線・棒で描きます。**`EChart` ではなく単一の `<svg>`**
6
+ なので、表のセルやタイルに何十個並べても軽いままです。
7
+
8
+ ```tsx
9
+ import { Sparkline } from "@squadbase/vantage/components";
10
+ import type { SparklineDataPoint, SparklineVariant } from "@squadbase/vantage/components";
11
+ ```
12
+
13
+ | Prop | Type | Default | 説明 |
14
+ | --- | --- | --- | --- |
15
+ | `data` | `SparklineDataPoint[]` | | `{ value: number; label?: string }` の配列。**必須**。空配列なら何も描かない。 |
16
+ | `variant` | `"line" \| "bar"` | `"line"` | 折れ線か棒か。 |
17
+ | `height` | `number` | `40` | 高さ(px)。幅は親要素いっぱい。 |
18
+ | `color` | `string` | `"text-chart-1"` | Tailwind の **text-* クラス**。`currentColor` 経由で線と塗りの両方に効く。 |
19
+ | `area` | `boolean` | `false` | 折れ線の下を薄く塗る(line のみ)。 |
20
+ | `animate` | `boolean` | `false` | マウント時に描画アニメーションする。 |
21
+ | `className` | `string` | | 足すクラス。 |
22
+
23
+ 残りの props は `<svg>` にそのまま渡ります。
24
+
25
+ > [!WARNING]
26
+ > `color` は**クラス名**です。`color="#3b82f6"` のような値は効きません — 線も塗りも
27
+ > `currentColor` を見ているため、`text-chart-2` のようなユーティリティを渡してください。
28
+ > テーマトークン(`--chart-1`〜`--chart-5`)を変えれば配色も一緒に変わります。
29
+
30
+ ## 大きさを決める
31
+
32
+ `preserveAspectRatio="none"` で横方向に引き伸ばすので、**幅は親要素が決めます**。表のセルに
33
+ 入れるときは幅と高さを絞ってください。
34
+
35
+ ```tsx
36
+ <Sparkline data={points} height={16} className="w-20 shrink-0" />
37
+ ```
38
+
39
+ ## EChart との使い分け
40
+
41
+ 軸・凡例・ツールチップ・複数系列が要るなら [`EChart`](parts/echart) を使います。
42
+ `Sparkline` が持つのは「値の並びの形」だけで、**目盛りも数値も出しません**。
43
+
44
+ > [!NOTE]
45
+ > `aria-hidden="true"` が付いているため、スクリーンリーダーには読まれません。実際の数値は
46
+ > [`MetricValue`](parts/metric-value) や
47
+ > [`TrendIndicator`](parts/trend-indicator) など、テキストとして隣に置いてください。
@@ -0,0 +1,44 @@
1
+ # StatusBadge
2
+
3
+ > ドット付きのステータスバッジ。色は名前で決まる。
4
+
5
+ 行やレコードの状態を、色付きのドットとラベルで示します。状態の文字列から色への対応は
6
+ 組み込みの表で決まり、`colorMap` で足したり上書きしたりできます。
7
+
8
+ ```tsx
9
+ import { StatusBadge } from "@squadbase/vantage/components";
10
+ ```
11
+
12
+ | Prop | Type | 説明 |
13
+ | --- | --- | --- |
14
+ | `status` | `string` | 状態の文字列。色はこれで決まる。 |
15
+ | `label` | `string` | 表示するテキスト。省くと `status` がそのまま出る。 |
16
+ | `colorMap` | `Record<string, string>` | 状態 → 色名の対応。既定の表に上書きされる。 |
17
+ | `className` | `string` | 足すクラス。 |
18
+
19
+ ## 既定の対応
20
+
21
+ | `status` | 色 |
22
+ | --- | --- |
23
+ | `active` | green |
24
+ | `inactive` | gray |
25
+ | `warning` | yellow |
26
+ | `error` | red |
27
+ | `pending` | blue |
28
+
29
+ 未知の状態は gray になります。独自の状態を足すときは `colorMap` に
30
+ `green` / `gray` / `yellow` / `red` / `blue` のいずれかを割り当ててください。
31
+
32
+ ```tsx
33
+ <StatusBadge status="reviewing" label="レビュー中" colorMap={{ reviewing: "blue" }} />
34
+ ```
35
+
36
+ テーブルのセルにそのまま置けます。
37
+
38
+ ```tsx
39
+ {
40
+ accessorKey: "status",
41
+ header: "状態",
42
+ cell: ({ row }) => <StatusBadge status={row.original.status} />,
43
+ }
44
+ ```
@@ -0,0 +1,26 @@
1
+ # TrendIndicator
2
+
3
+ > 増減の矢印と変化率。良し悪しは positiveIsGood で決まる。
4
+
5
+ 前期比などの変化を、矢印と変化率で示します。**「上がった=良い」とは限らない**ので、色は
6
+ `direction` と `positiveIsGood` の組み合わせで決まります — 解約率のように下がる方が良い指標では
7
+ `positiveIsGood={false}` を渡してください。
8
+
9
+ ```tsx
10
+ import { TrendIndicator } from "@squadbase/vantage/components";
11
+ import type { TrendDirection } from "@squadbase/vantage/components";
12
+ ```
13
+
14
+ | Prop | Type | Default | 説明 |
15
+ | --- | --- | --- | --- |
16
+ | `value` | `number` | | 変化率(`12.4` で 12.4%)。 |
17
+ | `direction` | `"up" \| "down" \| "neutral"` | | 矢印の向き。**必須**。 |
18
+ | `positiveIsGood` | `boolean` | `true` | 上がることが良いか。`false` にすると色が反転する。 |
19
+ | `className` | `string` | | 足すクラス。 |
20
+
21
+ > [!WARNING]
22
+ > `direction` は必須です。`value` の符号からは推測しません — 「値は減ったが、それは良いこと」と
23
+ > いう場合を表現できるようにするためです。
24
+
25
+ 色は 3 通りです。良い方向なら `--chart-1`、悪い方向なら `--primary`、`neutral` なら
26
+ `--muted-foreground`。テーマトークンを変えればここも一緒に変わります。
@@ -0,0 +1,175 @@
1
+ # ファイルベースルーティング
2
+
3
+ > ファイルを置くだけでルートが生まれる。ページ・レイアウト・動的パラメータ・404/error の規約。
4
+
5
+ Vantage のルーティングは **ファイルの配置がそのまま URL** になります。ルーターの設定は書きません。
6
+
7
+ ## ページの規約
8
+
9
+ | ファイル | ルート |
10
+ |---|---|
11
+ | `index.tsx` | `/` |
12
+ | `monthly-analysis.tsx` | `/monthly-analysis` |
13
+ | `sales/index.tsx` | `/sales` |
14
+ | `sales/[customerId].tsx` | `/sales/:customerId` |
15
+ | `sales/[...path].tsx` | `/sales/*`(catchall) |
16
+ | `_layout.tsx` | そのディレクトリ配下のレイアウト(入れ子可) |
17
+ | `_404.tsx` | not-found の UI(**ルートのみ**) |
18
+ | `_error.tsx` | error の UI(**ルートのみ**) |
19
+
20
+ - `[name]` → 動的パラメータ、`[...name]` → catchall。
21
+ - `index` は自身のディレクトリにマップ(名前は URL から落ちる)。
22
+ - `_` で始まるファイルは予約(`_layout`/`_404`/`_error`)またはプライベート(ルーティングされない)。
23
+
24
+ ## ルーティングされないディレクトリ
25
+
26
+ 次のディレクトリは決して走査されません。ここには自由にコードを置けます。
27
+
28
+ ```text
29
+ components/ 再利用する React コンポーネント
30
+ hooks/ カスタムフック
31
+ lib/ ユーティリティ
32
+ server/ API(存在するとサーバーが有効になる)
33
+ public/ 静的アセット
34
+ ```
35
+
36
+ > [!NOTE]
37
+ > ファイル間の import は **ランタイムの `.js` 指定子**を使います(例: `./components/revenue-chart.js`)。
38
+ > ESM の Node 解決に必要です。
39
+
40
+ ## 動的パラメータの 3 つの綴り
41
+
42
+ 同じパラメータが、場所によって 3 つの綴りで現れます。**必ず一致させます。**
43
+
44
+ | 場所 | 綴り | 例 |
45
+ |---|---|---|
46
+ | ファイル名 | `[id]` | `sales/[customerId].tsx` |
47
+ | 表示ルート | `:id` | `/sales/:customerId` |
48
+ | リンク | `$id` + `params` | `to="/sales/$customerId"` `params={{ customerId }}` |
49
+
50
+ ```tsx
51
+ import { Link, useParams } from "@squadbase/vantage/router";
52
+
53
+ function Row({ customerId }: { customerId: string }) {
54
+ return (
55
+ <Link to="/sales/$customerId" params={{ customerId }}>
56
+ 顧客を開く
57
+ </Link>
58
+ );
59
+ }
60
+
61
+ // sales/[customerId].tsx
62
+ export default function Customer() {
63
+ const { customerId } = useParams({ strict: false });
64
+ return <div>顧客 {customerId}</div>;
65
+ }
66
+ ```
67
+
68
+ ## レイアウトと入れ子
69
+
70
+ `_layout.tsx` は `<Outlet />` を描画して子ルートを囲みます。ディレクトリごとに置けば入れ子になります。
71
+
72
+ ```tsx
73
+ // _layout.tsx
74
+ import { Outlet } from "@squadbase/vantage/router";
75
+
76
+ export default function RootLayout() {
77
+ return (
78
+ <div className="min-h-screen">
79
+ <nav className="border-b p-4">My Dashboard</nav>
80
+ <Outlet />
81
+ </div>
82
+ );
83
+ }
84
+ ```
85
+
86
+ `_404.tsx` と `_error.tsx` は **ルート(プロジェクト直下)でのみ**認識されます。
87
+
88
+ ## ルート一覧からナビを作る
89
+
90
+ `useRoutes()` はアプリの全ページルートを返します。ファイルシステムが正本なので、
91
+ ページファイルを 1 つ足せばナビに 1 行増えます。手で管理するリンク配列は不要です。
92
+
93
+ ```tsx
94
+ // _layout.tsx
95
+ import { Link, Outlet, useCurrentRoute, useRoutes } from "@squadbase/vantage/router";
96
+
97
+ export default function RootLayout() {
98
+ // 動的ルート(/sales/:customerId)は URL が 1 つに定まらないので外す
99
+ const routes = useRoutes().filter((route) => !route.dynamic);
100
+ const current = useCurrentRoute();
101
+
102
+ return (
103
+ <div>
104
+ <nav>
105
+ {routes.map((route) => (
106
+ <Link key={route.path} to={route.to} aria-current={route.path === current?.path}>
107
+ {route.label}
108
+ </Link>
109
+ ))}
110
+ </nav>
111
+ <Outlet />
112
+ </div>
113
+ );
114
+ }
115
+ ```
116
+
117
+ 並び順は Vantage のスキャン順(浅い順 → 静的が動的より先 → アルファベット順)で、
118
+ そのままナビに使える順序です。
119
+
120
+ 各要素は `RouteInfo` です。
121
+
122
+ | フィールド | 型 | 内容 |
123
+ |---|---|---|
124
+ | `path` | `string` | 表示パス。`/sales/:customerId` |
125
+ | `to` | `string` | `Link` の `to` に渡す形。`/sales/$customerId` |
126
+ | `params` | `string[]` | 動的パラメータ名。catch-all は `_splat` |
127
+ | `dynamic` | `boolean` | 動的パラメータを持つか |
128
+ | `index` | `boolean` | ディレクトリの index ルートか |
129
+ | `label` | `string` | `navLabel` → `title` → `path` の順で決まる表示名 |
130
+ | `title` / `description` / `navLabel` | `string \| undefined` | [`definePage`](pages-and-metadata) の値 |
131
+
132
+ `useCurrentRoute()` は今表示中のルートを返します(404 のときは `undefined`)。
133
+ 上の例のような「現在地」判定のほか、パンくずやページ見出しに使えます。
134
+
135
+ > [!NOTE]
136
+ > `label` は `navLabel` を優先します。`title` は `document.title` に使われるためサイト名を
137
+ > 含めがちで、ナビには長すぎることが多いためです。
138
+
139
+ ## URL にフィルタ状態を置く
140
+
141
+ ダッシュボードの絞り込みは URL に置くと、リロードで消えず、そのまま同僚に共有できます。
142
+ `useSearchParam` は `useState` と同じ形で search params を読み書きします。
143
+
144
+ ```tsx
145
+ import { useSearchParam } from "@squadbase/vantage/router";
146
+ import { SegmentedControl } from "@squadbase/vantage/components";
147
+
148
+ export default function Sales() {
149
+ const [region, setRegion] = useSearchParam("region", "all");
150
+
151
+ return <SegmentedControl options={REGIONS} value={region} onChange={setRegion} />;
152
+ }
153
+ ```
154
+
155
+ - 値は**常に文字列**です(`?year=2024` は数値としてパースされますが、この hook が文字列に戻します)。
156
+ - **デフォルト値**(上の例では `"all"`)や `null` を書き込むと、キーは URL から取り除かれます。
157
+ - 履歴は既定で `replace`(戻るボタンが埋まらない)。`{ replace: false }` で push に変えられます。
158
+
159
+ 配列やオブジェクトなど JSON になる値は `useSearchState` を使います。関数更新も渡せます。
160
+
161
+ ```tsx
162
+ import { useSearchState } from "@squadbase/vantage/router";
163
+
164
+ const [segments, setSegments] = useSearchState<string[]>("segments", []);
165
+ setSegments((prev) => [...prev, "enterprise"]);
166
+ ```
167
+
168
+ ## HMR とルート再生成
169
+
170
+ `.tsx` ページや `server/api` ファイルを追加・削除すると、開発サーバーがルートを再生成して
171
+ フルリロードします。ページ本体を編集した場合は React Fast Refresh がその場で反映します。
172
+
173
+ ## 次に読む
174
+
175
+ - [ページと definePage](pages-and-metadata) — ページの契約とメタデータ
@@ -0,0 +1,37 @@
1
+ # Accordion
2
+
3
+ > 開閉する見出しの縦積み。既定では 1 つだけ開く。
4
+
5
+ 見出しをクリックして中身を開閉するリストです。既定では一度に 1 つだけ開きます。複数を同時に開き
6
+ たいときは `openMultiple` を付けます。
7
+
8
+ ```tsx
9
+ import {
10
+ Accordion,
11
+ AccordionItem,
12
+ AccordionTrigger,
13
+ AccordionContent,
14
+ } from "@squadbase/vantage/ui";
15
+ ```
16
+
17
+ ## パーツ
18
+
19
+ | パーツ | 役割 |
20
+ | --- | --- |
21
+ | `Accordion` | 全体。`value` / `defaultValue` は**開いている項目の配列** |
22
+ | `AccordionItem` | 1 項目。`value` で識別する |
23
+ | `AccordionTrigger` | 見出しボタン。シェブロンは自動で付く |
24
+ | `AccordionContent` | 開閉する中身 |
25
+
26
+ ## 複数同時に開く
27
+
28
+ ```tsx
29
+ <Accordion openMultiple defaultValue={["a", "b"]}>
30
+ ```
31
+
32
+ > [!NOTE]
33
+ > `value` は Radix 版のような文字列ではなく**配列**です(Base UI の仕様)。1 つだけ開く場合も
34
+ > `defaultValue={["freshness"]}` のように配列で渡します。
35
+
36
+ 常に開いている単独の折りたたみが欲しいだけなら
37
+ [`Collapsible`](ui/collapsible) の方が軽量です。