@squadbase/vantage-template 0.1.1-dev1.3f269fd → 0.1.1-dev1.40460e8

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 (33) hide show
  1. package/README.md +12 -2
  2. package/base-template/.squadbase/skills/vantage-add-feature/SKILL.md +9 -7
  3. package/base-template/.squadbase/skills/vantage-app/SKILL.md +10 -6
  4. package/base-template/.squadbase/skills/vantage-design/SKILL.md +60 -52
  5. package/base-template/.squadbase/skills/vantage-design/references/extract.md +26 -27
  6. package/base-template/.squadbase/skills/vantage-design/references/format.md +12 -172
  7. package/base-template/.squadbase/skills/vantage-design/references/presets.md +50 -110
  8. package/base-template/.squadbase/skills/vantage-pitfalls/SKILL.md +50 -1
  9. package/base-template/.squadbase/skills/vantage-slide/SKILL.md +299 -0
  10. package/base-template/.squadbase/skills/vantage-slide/references/morph.md +102 -0
  11. package/base-template/.squadbase/skills/vantage-slide/references/steps.md +57 -0
  12. package/base-template/.squadbase/skills/vantage-slide/references/tokens.md +87 -0
  13. package/base-template/.squadbase/skills/vantage-slide/references/transitions.md +196 -0
  14. package/base-template/AGENTS.md +118 -20
  15. package/base-template/agents/csv.md +2 -1
  16. package/base-template/agents/doc.md +52 -3
  17. package/base-template/agents/page.md +53 -8
  18. package/base-template/agents/slide.md +77 -3
  19. package/base-template/agents/xlsx.md +2 -1
  20. package/base-template/bun.lock +24 -24
  21. package/base-template/bunfig.toml +5 -0
  22. package/base-template/package.json +2 -2
  23. package/base-template/src/_layout.tsx +13 -6
  24. package/base-template/src/components/build-recovery.tsx +37 -1
  25. package/base-template/src/components/user-card.tsx +11 -11
  26. package/base-template/src/index.tsx +1 -1
  27. package/base-template/src/styles.css +105 -18
  28. package/dist/index.js +956 -0
  29. package/package.json +20 -17
  30. package/ui-templates/CLAUDE.md +2 -0
  31. package/ui-templates/kpi-chart-simple/pages/index.tsx +47 -47
  32. package/ui-templates/kpi-chart-simple-ja/pages/index.tsx +47 -47
  33. package/base-template/DESIGN.md +0 -108
@@ -12,9 +12,16 @@
12
12
 
13
13
  ```tsx
14
14
  import { definePage } from "@squadbase/vantage"
15
- import { EChart } from "@squadbase/vantage/components"
15
+ import { BarChart } from "@squadbase/vantage/components"
16
16
  import { Document } from "@squadbase/vantage/doc"
17
17
 
18
+ const weekly = [
19
+ { week: "第1週", 売上: 1180 },
20
+ { week: "第2週", 売上: 1240 },
21
+ { week: "第3週", 売上: 1210 },
22
+ { week: "第4週", 売上: 1620 },
23
+ ]
24
+
18
25
  export const page = definePage({ title: "6月度サマリー", navLabel: "6月度サマリー" })
19
26
  export default function JuneSummary() {
20
27
  return (
@@ -23,7 +30,7 @@ export default function JuneSummary() {
23
30
  <p>6月の売上は <strong>5,250 万円</strong>で、目標を 5% 上回りました。</p>
24
31
  <h2>週次の売上</h2>
25
32
  <figure>
26
- <EChart option={option} height={280} ariaLabel="6月の週次売上" />
33
+ <BarChart data={weekly} index="week" categories={["売上"]} height={280} ariaLabel="6月の週次売上" />
27
34
  <figcaption>第4週はキャンペーン初週</figcaption>
28
35
  </figure>
29
36
  <table>…</table>
@@ -42,13 +49,38 @@ export default function JuneSummary() {
42
49
  見た目を変えたいときはユーティリティを並べず、下の `--doc-*` を変えます。
43
50
  - **数値はコードに直接書く。** ドキュメントは書いた時点の内容を残すページです。
44
51
  `useApiQuery` などで読み込むと、開くたびに値が変わります。
45
- - **チャートは `EChart`(`@squadbase/vantage/components`)を文中に置く。** `figure` で囲めば
52
+ - **チャートは型付きチャート(`BarChart`・`LineChart` など。`@squadbase/vantage/components`)を
53
+ 文中に置く**(選び方は `agents/page.md` の「グラフはまず型付きチャートで描く」)。`figure` で囲めば
46
54
  `figcaption` がキャプションになります。
47
55
  - **PDF の保存ボタンは作らない。** `<Document>` が右下に PDF 保存のボタンを出し、印刷時は
48
56
  本文だけをライトの配色で出します。
49
57
  - **ページ全体を包むのは `<Document>` だけ。** `PageShell` などのダッシュボード用の枠で包まない
50
58
  (本文の幅と余白は `<Document>` が決めます)。
51
59
 
60
+ ## まず block を探す
61
+
62
+ 1 節分の中身は、手で組む前に `@squadbase/vantage/doc` の block から探します(`<Document>` の直下に
63
+ 並べる。多くは 1 block = 1 節。`DocCallout`・`DocFigure`・`DocDataTable` は節ではなく、節の中(本文の間)に置く部品)。props は `vantage docs <name>`(例: `vantage docs doc-kpi-scorecard`)で引く。
64
+
65
+ | block | 用途 |
66
+ | --- | --- |
67
+ | `DocReportHeader` | レポートの冒頭(タイトル・サブタイトル・対象期間・データ時点・作成者・出典) |
68
+ | `DocExecutiveSummary` | 結論を先に述べる要約の節 |
69
+ | `DocKpiScorecard` | 主要指標をまとめたスコアカード |
70
+ | `DocFigure` | 図表 1 つとキャプション(チャートは children で渡す) |
71
+ | `DocDataTable` | 素の `table` による表 |
72
+ | `DocCallout` | 補足・示唆・注意・決定の囲み(`kind`: `note` / `insight` / `warning` / `decision`) |
73
+ | `DocKeyFindings` | 主要な発見の箇条 |
74
+ | `DocActionItems` | 次のアクション(担当・期限つき) |
75
+ | `DocNotesAndSources` | 末尾の注記・用語の定義・データソースをまとめた節 |
76
+
77
+ **props の渡し方は block 間で共通。** 数値は `value: number | null` と `format`(整形は block がする。表示を上書きするときだけ `display`。`null` は「—」)。前期比などは `delta: { value, format? }` と `comparisonLabel`(例 `"前年同期比"`)、良し悪しは指標ごとの `betterWhen`(`"up"` が既定、コストなど下がるほど良いものは `"down"`。向きは block が符号から出す)。目標は `target: number`。出典は `source`、時点は `asOf` に**日付だけ**(例 `"2026-09-30"`。「データ時点」は block が付けるので「時点」を書かない)。時系列は、単一系列なら `{ x, y }[]`(`trend`)。
78
+
79
+ 本文の中で増減を書くときは `DeltaText`(部品。「▲ +3.2%」の形で、文字サイズは持たず置かれた行に従う。`value` `format` `betterWhen` `comparisonLabel`)を使う。節ではなく文の中に置く。
80
+
81
+ block が合わない**1 節だけ**を素の HTML 要素で手で書く。import 元は `@squadbase/vantage/doc` のままで、
82
+ block のための新しい import 元はありません。本文は文字列か ReactNode で渡し、Markdown 文字列は渡さない。
83
+
52
84
  ## 見た目を変える
53
85
 
54
86
  配色・書体・本文の幅は `--doc-*` の CSS 変数です。既定値はアプリのトークンへの別名なので、
@@ -73,3 +105,20 @@ export default function JuneSummary() {
73
105
  `.doc` を付けられるのはルートになるページモジュールだけで、`_layout.doc.tsx` などは
74
106
  `INVALID_PAGE_VARIANT` エラーになります。`june.doc.tsx` と `june.tsx` は同じ URL に解決するので
75
107
  `ROUTE_CONFLICT` です。
108
+
109
+ ## ファイル形式の規約
110
+
111
+ 置き場所・URL・default export・`definePage` の書き方は全ページ共通(`agents/page.md` の
112
+ 「ページファイルの規約」)。ここではドキュメント固有のものだけを挙げます。
113
+
114
+ **MUST**
115
+
116
+ - ファイル名は `<name>.doc.tsx`(`.jsx` も可)。サフィックスは小文字で 1 つだけ。`.doc.mdx` は
117
+ `INVALID_PAGE_VARIANT`、`.DOC.tsx`・二重サフィックスは黙って通常ページになる
118
+ - default export は `<Document>` をルートに返す。フレームワークは包まない
119
+ - ドキュメントの部品は `@squadbase/vantage/doc` から import する
120
+
121
+ **SHOULD**
122
+
123
+ - `PageShell` で包まない・PDF の保存ボタンを自作しない(上の「書き方」)
124
+ - 数値はコードに直接書き、いつ時点の値かを本文に書く
@@ -4,7 +4,7 @@
4
4
  (ダッシュボード)を書くときに読んでください。前提となる不変条件・ディレクトリ構造は
5
5
  `AGENTS.md` を先に読んでいる想定です。
6
6
 
7
- プロジェクトルートに `DESIGN.md` があれば、書き始める前に読んで配色・書体・レイアウトの規則に従う。
7
+ 書き始める前に `AGENTS.md` の「見た目の規約」(と、あればプロジェクトルートの `DESIGN.md`)に従う。
8
8
 
9
9
  ## 最小アプリ(2 ファイル)
10
10
 
@@ -71,6 +71,7 @@ URL になる。各ページは**デフォルトエクスポートの React コ
71
71
  | `_404.tsx` | Not Found ページ |
72
72
  | `_error.tsx` | ルートが throw したときのエラーページ |
73
73
  | `monthly-report.slide.tsx` | `/monthly-report`(スライドデッキ。詳しくは `agents/slide.md`) |
74
+ | `june-summary.doc.tsx` | `/june-summary`(ドキュメント。詳しくは `agents/doc.md`) |
74
75
  | `sales-export.csv` | `/sales-export`(詳しくは `agents/csv.md`) |
75
76
  | `data/june.xlsx` | `/data/june`(詳しくは `agents/xlsx.md`) |
76
77
 
@@ -89,6 +90,26 @@ export default function MonthlyAnalysis() {
89
90
  }
90
91
  ```
91
92
 
93
+ ### ページファイルの規約(`.tsx` / `.slide.tsx` / `.doc.tsx` 共通)
94
+
95
+ **MUST**
96
+
97
+ - ページルートの配下に置く。`components/` などの走査対象外のディレクトリに置いたファイルはページに
98
+ ならず、エラーも出ない。`_` 始まりの名前は予約名(`_layout` / `_404` / `_error`)にだけ使う
99
+ (それ以外の `_` 始まりはページにならない。予約名にサフィックスを付けると `INVALID_PAGE_VARIANT`)
100
+ - URL はサフィックスと拡張子を除いたパスで決まる。同じ URL になる別ファイル(`june.tsx` /
101
+ `june.slide.tsx` / `june.doc.tsx` / `june.csv`)を並べない(`ROUTE_CONFLICT`)。テンプレートの
102
+ 未編集の `index.tsx` だけは例外で、`index.slide.tsx` / `index.doc.tsx` が `/` を取れる
103
+ - default export は React の関数コンポーネント(無いと `MISSING_DEFAULT_EXPORT`。関数かどうかは
104
+ 検査されない)
105
+ - `definePage({ ... })` にはオブジェクトリテラルを直接渡し、`title` / `description` / `navLabel` は
106
+ 文字列リテラルで書く。ビルド時に静的抽出されるので、変数・関数呼び出し・spread・shorthand・
107
+ `${}` を含むテンプレート文字列は**エラーにならず黙ってメタなし**になる
108
+
109
+ **SHOULD**
110
+
111
+ - `definePage` に `title` と `navLabel` を書く(ナビの表示名とブラウザのタブ名になる)
112
+
92
113
  ### ナビはルート一覧から組む
93
114
 
94
115
  `useRoutes()` がページルート一覧(スキャン順)を返すので、リンク配列を手で持たない。
@@ -109,7 +130,7 @@ routes.map((r) => (
109
130
  ```
110
131
 
111
132
  `RouteInfo`: `path`(`/sales/:id`)・`to`(`/sales/$id`)・`params`・`dynamic`・`index`・`label`・
112
- `title`・`description`・`navLabel`・`kind`(`"module"` | `"file"`)・`variant`(`"slide"`)。
133
+ `title`・`description`・`navLabel`・`kind`(`"module"` | `"file"`)・`variant`(`"slide"` | `"doc"`)。
113
134
  後ろの 2 つで、ナビをダッシュボード / スライド / データに分けたりアイコンを変えたりできます。
114
135
 
115
136
  ### フィルタ状態は URL に置く
@@ -164,17 +185,41 @@ refetchOnWindowFocus false・networkMode "always")。挙動を変えたいとき
164
185
  ## 組み込み UI / コンポーネントの入口
165
186
 
166
187
  - **プリミティブ**は `@squadbase/vantage/ui` から import する(`Button`・`Loading`・
167
- `ErrorState`・`Empty`・`Select`・`Checkbox` ほか)。
188
+ `ErrorState`・`Empty`・`Select`・`Checkbox`・`RadioGroup`・`Field`・`Combobox`・`Pagination`・
189
+ `Avatar`・`Kbd`・`HoverCard`・`AlertDialog`・`Drawer`・`Toaster` + `toast.add()` ほか)。
168
190
  - **複合パーツ**は `@squadbase/vantage/components` から(`PageShell`・`DashboardCardPreset`・
169
- `DataTablePreset`・`EChart` ほか)。
191
+ `DataTablePreset`・型付きチャート(下の「グラフ」)・`EChart` ほか)。
170
192
  - **どの名前が import 可能か / props の詳細は `vantage docs` で引く。** ガイドとコンポーネント
171
193
  リファレンスはパッケージに同梱されていて、オフラインでも読める(→ `AGENTS.md` の
172
194
  「ドキュメントを引く」)。**名前が分からないとき**はやりたいことで `vantage search` する
173
195
  (→ 同節)。
174
- - **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui|block` は
175
- ソースを手元にコピーして**改造したいとき専用**のコマンドで、取り出せるのは
176
- `ui: data-table` と `block: sales-overview` の 2 つだけ。それ以外の名前は import 専用で
177
- `add` の対象ではない(未知名で実行すると候補が一覧表示される)。
196
+ - **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui <name>` は
197
+ ソースを手元にコピーして**改造したいとき専用**のコマンド。`/ui` のプリミティブも
198
+ `/components` の複合パーツも全部取り出せる(名前は kebab-case: `add ui bar-chart`。
199
+ ブロックは `add block sales-overview`。未知名で実行すると候補が一覧表示される)。
200
+
201
+ ### 長い表はページングする(縦スクロール箱を作らない)
202
+
203
+ - 行が多い表は `DataTablePreset`(または `DataTable`)に `enablePagination` を付けて**ページング**する
204
+ (既定は 10 行 / ページ。ページングは既定で無効なので、付け忘れると全行が並ぶ)。素の `<table>` を
205
+ 手書きして全行を流し込まない。
206
+ - カードの中に `max-h-*` + `overflow-y-auto` の**縦スクロール領域を作らない**。ホイールやキー
207
+ (End / Space)がその箱に吸われ、ページ全体がスクロールしなくなる。高さは内容に任せる。
208
+ - 横に広い表の `overflow-x-auto` は構わない。`SheetGrid`(`.csv` / `.xlsx` のビューア)は
209
+ グリッドとして意図した入れ子スクロールなので対象外。
210
+
211
+ ### グラフはまず型付きチャートで描く
212
+
213
+ - 推移は `LineChart` / `AreaChart`、比較は `BarChart`、構成比は `DonutChart`。`data`(行の配列)・
214
+ `index`(x 軸の列)・`categories`(系列の列)を渡すだけで、option は書かない
215
+ (`DonutChart` は `category` / `value`)。
216
+ - 上位 N 件は `BarList`、判定帯や予算消化は `CategoryBar`、達成率は `ProgressCircle`、
217
+ 日ごとの状態は `Tracker`。
218
+ - `EChart` + `EChartsOption` は、二軸・散布図・ヒートマップ・注釈線など型付きチャートの props で
219
+ 表せないときだけ使う。
220
+ - 色は省略してテーマトークンに任せる。指定するなら `"chart-1"`〜`"chart-5"` か
221
+ `"var(--destructive)"` などの CSS 色。hex の直書きや Tailwind クラスは使わない。
222
+ - 数値の書式(`¥`・`%`・桁区切り)は `valueFormatter` に渡す。
178
223
 
179
224
  ### ダークモードは opt-in
180
225
 
@@ -4,7 +4,13 @@
4
4
  スライドデッキを書くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
5
5
  先に読んでいる想定です。
6
6
 
7
- プロジェクトルートに `DESIGN.md` があれば、書き始める前に読んで「スライド」の節と配色・書体の規則に従う。
7
+ 書き始める前に `AGENTS.md` の「見た目の規約」(と、あればプロジェクトルートの `DESIGN.md`)に従う。
8
+ スライド固有の規則:
9
+
10
+ - 1 枚に 1 メッセージ。見出しに結論を書く。
11
+ - 色は `--slide-bg` / `--slide-fg` / `--slide-accent` / `--slide-muted` を使う(既定では
12
+ `--background` / `--foreground` / `--primary` / `--muted-foreground` に連動)。
13
+ - 強調色は 1 枚につき 1 か所まで。
8
14
 
9
15
  ## スライドは `.slide.tsx` で書く
10
16
 
@@ -19,6 +25,7 @@
19
25
  - 新規プロジェクトでまだ `/` が空いている場合のみ、`index.slide.tsx` を使ってよい。
20
26
 
21
27
  ```tsx
28
+ import { definePage } from "@squadbase/vantage"
22
29
  import { Slide, SlideDeck } from "@squadbase/vantage/slide"
23
30
 
24
31
  export const page = definePage({ title: "6月度レビュー", navLabel: "6月度" })
@@ -34,8 +41,10 @@ export default function Deck() {
34
41
 
35
42
  **`<Slide>` は `<SlideDeck>` の直接の子に書く。** `SlideDeck` は直下の `<Slide>` 要素だけを数えるので、
36
43
  `<Slide>` を自作コンポーネント(`<Slide1 />` など)や Fragment で包むと 1 枚も数えられず「1 / 0」に
37
- なります(`{items.map((x) => <Slide key={x.id}>…</Slide>)}` のような配列は可)。共通の部品は
38
- `<Slide>` の**中**に置くコンポーネントとして切り出します(`<Slide><CoverPage /></Slide>`)。
44
+ なります(`{items.map((x) => <Slide key={x.id}>…</Slide>)}` のような配列はファイル形式としては可。
45
+ 1 枚の中で視覚要素を `map` で量産しない方針は `vantage-slide` skill の「繰り返す要素は `map` ではなく
46
+ コンポーネント」)。共通の部品は `<Slide>` の**中**に置くコンポーネントとして切り出します
47
+ (`<Slide><CoverPage /></Slide>`)。
39
48
 
40
49
  1920×1080 の固定キャンバスに絶対 px で書き、画面サイズに合わせて縮小されます。キー / クリックで
41
50
  送れ、左のスライド一覧(サムネイル列)は `L` で開閉、`F` で全画面、ツールバーから pptx を
@@ -51,3 +60,68 @@ pptx が壊れる条件、説明と図表のデータ時点の揃え方)。
51
60
  `.slide` を付けられるのはルートになるページモジュールだけで、`_layout.slide.tsx` などは
52
61
  `INVALID_PAGE_VARIANT` エラーになります。`june.slide.tsx` と `june.tsx` は同じ URL に解決するので
53
62
  `ROUTE_CONFLICT` です。
63
+
64
+ ## まず block を探す
65
+
66
+ 1 枚分の中身は、手で組む前に `@squadbase/vantage/slide` の block から探します(`<Slide>` の**中**に
67
+ 置く。ルートは 100% で、`<Slide>` 自体は持たない)。props は `vantage docs <name>`(例:
68
+ `vantage docs slide-kpi-hero`)で引く。
69
+
70
+ | block | 用途 |
71
+ | --- | --- |
72
+ | `SlideCover` | 表紙(タイトル・サブタイトル・期間) |
73
+ | `SlideExecSummary` | 結論を先に述べるエグゼクティブサマリー |
74
+ | `SlideKpiHero` | 主要な KPI 1 つを大きく見せる |
75
+ | `SlideKpiGrid` | 複数の KPI を並べる |
76
+ | `SlideChartInsight` | チャート 1 つと、そこから読み取れること |
77
+ | `SlideScorecardTable` | 指標と目標・達成度を表にしたスコアカード |
78
+ | `SlideNextActions` | 次のアクション(担当・期限つき) |
79
+ | `SlideSection` | 章の扉(`items` を渡すと番号付きのアジェンダ。`current` の章を強調) |
80
+ | `SlideComparison` | A vs B・前後の 2〜3 列比較(各列に見出し・主要数値・箇条) |
81
+ | `SlideChartFull` | チャートを全幅に置き、注記を 1 行添える |
82
+
83
+ **手書きの 1 枚には部品を使う。** block が合わない 1 枚でも、見出し・出典行・列割りは自前で組まず、
84
+ 次の部品を使う(どれも `@squadbase/vantage/slide`。1 枚にはならないので `<Slide>` の中に並べる)。
85
+
86
+ | 部品 | 用途 |
87
+ | --- | --- |
88
+ | `SlideHeading` | 見出し(`title`、任意で `eyebrow`)。1 枚の先頭に置く |
89
+ | `SlideSourceLine` | 足元の出典・時点(`source` `asOf`)。`page={{ current, total }}` を渡すとページ番号も出す |
90
+ | `SlideColumns` / `SlideColumn` | 12 列の割り付け(`<SlideColumn span={8}>` と `span={4}` など)。`align` は `start` / `center` / `stretch` |
91
+ | `DeltaText` | 増減の文字(「▲ +3.2%」)。`value` `format` `betterWhen` `comparisonLabel` |
92
+
93
+ `SlideSection` は `Steps` を持たない。順に見せたいときは呼び出し側で `<Steps>` で包む。
94
+
95
+ ```tsx
96
+ import { Slide, SlideDeck, SlideCover, SlideExecSummary } from "@squadbase/vantage/slide"
97
+ // <SlideDeck><Slide><SlideCover … /></Slide><Slide><SlideExecSummary … /></Slide></SlideDeck>
98
+ ```
99
+
100
+ **props の渡し方は block 間で共通。** 数値は `value: number | null` と `format`(整形は block がする。表示を上書きするときだけ `display`。`null` は「—」)。前期比などは `delta: { value, format? }` と `comparisonLabel`(例 `"前年同期比"`)、良し悪しは指標ごとの `betterWhen`(`"up"` が既定、コストなど下がるほど良いものは `"down"`。向きは block が符号から出す)。目標は `target: number`。出典は `source`(文字列)、時点は `asOf` に**日付だけ**(例 `"2026-09-30"`。「時点」は block が付けるので書かない)。時系列は、単一系列なら `{ x, y }[]`(kpi-hero の `trend`。scorecard に `trend` は無い)、複数系列なら `{ categories, series }`(chart-insight の `chart`)。
101
+
102
+ block が合わない**1 枚だけ**を手で書く(デッキ全体を手書きに切り替えない)。import 元は
103
+ `@squadbase/vantage/slide` のままで、block のための新しい import 元はありません。
104
+
105
+ ## ファイル形式の規約
106
+
107
+ 置き場所・URL・default export・`definePage` の書き方は全ページ共通(`agents/page.md` の
108
+ 「ページファイルの規約」)。ここではスライド固有のものだけを挙げます。**中身の値(キャンバス・
109
+ セーフエリア・グリッド・文字サイズ・余白)は `vantage-slide` skill を参照。**
110
+
111
+ **MUST**(破ると黙って壊れるものが多い。`vantage check` が拾うのは名前の誤りだけ)
112
+
113
+ - ファイル名は `<name>.slide.tsx`(`.jsx` も可)。サフィックスは小文字で 1 つだけ。`.slide.ts` は
114
+ `INVALID_PAGE_VARIANT`、`.SLIDE.tsx`・二重サフィックス・`.slide.test.tsx` は黙って通常ページになる
115
+ - default export は `<SlideDeck>` をルートに返す。フレームワークは包まない
116
+ - `<Slide>` は `<SlideDeck>` の直接の子(配列は可。Fragment・自作コンポーネントで包まない)
117
+ - `<Step>` は `<Steps>` の直接の子(包むと常に表示される)
118
+ - スライドの部品は `@squadbase/vantage/slide` から import する
119
+
120
+ **SHOULD**
121
+
122
+ - 1 ファイル = 1 デッキ。ヘルパーコンポーネント・定数も同じ `.slide.tsx` に書く
123
+ - 各 `<Slide>` のルート要素は `width: "100%"; height: "100%"` でキャンバスを埋める
124
+ - canvas に描くチャート(`EChart`)は `data-waitfor="canvas"` で包む(無いと pptx でそのスライドが白紙になりうる)
125
+ - pptx に出る中身をアプリの Context(router / query / テーマ)に依存させない
126
+ - `MorphElement` の `id` はページ内で一意にし、入れ子にしない。遷移先の `<Slide>` で `transition.morph` を有効にする
127
+ - pptx 用などの依存を追加しない(html-to-image / fflate は自動で入る)
@@ -28,6 +28,7 @@
28
28
  - **複数シートに対応**しています。シートのタブは下端に並び、切り替えて閲覧できます。
29
29
  - 数式・グラフ・セル書式は再現されません(値として読めれば十分、という設計)。ブラウザでパースするので
30
30
  25MB を超えるファイルはそのページにエラーが出ます —— 大きいデータは `server/api/` から配って
31
- `DataTable` で描いてください
31
+ `DataTable` で描いてください。20 万行を超えると先頭
32
+ 20 万行だけが表示されます(残りはダウンロードして見る)
32
33
  - **ビューアの無い拡張子(`.xls`・`.ods` など)はルートになりません。** `vantage check` の
33
34
  `UNSUPPORTED_PAGE_FILE` 警告が知らせます
@@ -6,8 +6,8 @@
6
6
  "name": "vibe-app",
7
7
  "dependencies": {
8
8
  "@squadbase/react": "^0.1.0",
9
- "@squadbase/vantage": "0.6.2-dev1.b332e5a",
10
- "@squadbase/vantage-sdk": "0.1.1-dev1.28afad5",
9
+ "@squadbase/vantage": "0.6.2-dev1.26a3cce",
10
+ "@squadbase/vantage-sdk": "0.1.1-dev1.c070adc",
11
11
  "date-fns": "^4.1.0",
12
12
  "lucide-react": "^0.468.0",
13
13
  "react": "^19.3.1",
@@ -114,7 +114,7 @@
114
114
 
115
115
  "@mermaid-js/parser": ["@mermaid-js/parser@1.2.1", "", { "dependencies": { "@chevrotain/types": "~11.1.2" } }, "sha512-n12NohV3mrUyUL2o93IgG/ifeW9FTyeJn3zDxkhwa8MJ9Fxg3HQMlA3RiGmD/3UnJvheztkjjQAjA2T4LmUcpw=="],
116
116
 
117
- "@oxc-project/types": ["@oxc-project/types@0.154.0", "", {}, "sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA=="],
117
+ "@oxc-project/types": ["@oxc-project/types@0.155.0", "", {}, "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q=="],
118
118
 
119
119
  "@radix-ui/primitive": ["@radix-ui/primitive@1.1.7", "", {}, "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q=="],
120
120
 
@@ -148,35 +148,35 @@
148
148
 
149
149
  "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rDiah9wvtqihWtWz02XreeRKIxt2EJF8y5D9rtY9l5A2zxePAtcPiOMpDugNRw5bFHz+1/8viVoc7ZVKiJknCw=="],
150
150
 
151
- "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.14", "", { "os": "android", "cpu": "arm" }, "sha512-aWR+XKH9+rW7m5fWq/5360J3mHycrx/o6xZM2DQFdJnTMdyP7/WzxPjhtLbVWdKo2y612/4U1bWqb3HQhiF7vg=="],
151
+ "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.15", "", { "os": "android", "cpu": "arm" }, "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw=="],
152
152
 
153
- "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.14", "", { "os": "android", "cpu": "arm64" }, "sha512-QiVxHofl6A8lQU7WAtOUY4QMVZXohxwz7WJJoeh8NBEUyKfIkMRKhYyq8az/1RypNiIXzNTtiS6KwHz0erxYRQ=="],
153
+ "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.15", "", { "os": "android", "cpu": "arm64" }, "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg=="],
154
154
 
155
- "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lTQOzHuBIooh3jIr5XINQkjPGEuGy+Dsy0meXDr6Sjty0b99kYgGh4uBC/8mJX1T0kC8d6S0aPP1Y+bHkh6aBw=="],
155
+ "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA=="],
156
156
 
157
- "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-hyMKEGatjmBYCs/Q4sbIcL/GqpFEqsX3wc+HYVQ/85A4rxc1o7rPm4DUI4GV4k/h0ITddwFSGpqQunI14GXjTA=="],
157
+ "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A=="],
158
158
 
159
- "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.14", "", { "os": "freebsd", "cpu": "x64" }, "sha512-u371GbXoVXrEgP20PwzoGNOdAOqAMhzo19JzzY+V4YmmnC+DTOoqdbMu+O+54emM59Mik/UdrtWgcuEDKWRPKA=="],
159
+ "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.15", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ=="],
160
160
 
161
- "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.14", "", { "os": "linux", "cpu": "arm" }, "sha512-BqwKsdZQf6EqVWr8fv2MrDYzAvOZ7+NYFSJESRGs87fkseEhs0TU9TXgRJTkZoRRkxTizyEg1LKUXfU3/78uqg=="],
161
+ "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.15", "", { "os": "linux", "cpu": "arm" }, "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ=="],
162
162
 
163
- "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-SD9kY8M009x/7s57Z1dgUVlP5+uYBgKQK0Tkr1WIWngrtUJmRCW1RJFMY7QDla2khXhmg2i5Io7MUjcmZNZ/KQ=="],
163
+ "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw=="],
164
164
 
165
- "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-BJ2CL19M6uuWesMgnqJzgxoI+N+eV7b0A9O9vLV42y+gitC41fNa8KElau1tHVzuLWX5GzEuxMPhAO0tQXQMkg=="],
165
+ "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ=="],
166
166
 
167
- "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.14", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4+Kl8daPV8NDHaD7mfCcc1pRM+Qg7ab8DyMm5FG5WoZgv4h2i3KFN1CybYBNbQqmuYm7ftJLvmMI1eHYJ22S/Q=="],
167
+ "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.15", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw=="],
168
168
 
169
- "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.14", "", { "os": "linux", "cpu": "s390x" }, "sha512-V/h8ePq1fKDrmtFMz6xcCN3DKvuvMRrwwD1q0PkBeeo4DpK64biaKvqWGVxqCeYKqeRk7gE7/iKPxLCn08O97A=="],
169
+ "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.15", "", { "os": "linux", "cpu": "s390x" }, "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA=="],
170
170
 
171
- "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.14", "", { "os": "linux", "cpu": "x64" }, "sha512-WxalXzgrLVpKC93xfpaJ3gCXUWzeCr+FRCbDVD2mUAy4L6Vo3lNVz0epUEUpxPWJkLNYUwM4OSIikv36OJ9mLg=="],
171
+ "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.15", "", { "os": "linux", "cpu": "x64" }, "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw=="],
172
172
 
173
- "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.14", "", { "os": "linux", "cpu": "x64" }, "sha512-3G3tnAmTpdk9jO3GQtyHXqeFD2SlecfTws/Y3M2mmj9nMBwwuLT4kur8sZKeu7ENUHSpVO3cIsm5A52LEWWwlg=="],
173
+ "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.15", "", { "os": "linux", "cpu": "x64" }, "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ=="],
174
174
 
175
- "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.14", "", { "os": "none", "cpu": "arm64" }, "sha512-qyr5XiNGxm2ytx17vvtcJ9nXn6v1gENETi503bJx3OGwZ1tSonj7BosxbMa/xeAfSl5iS9X6KjEWYXLu6v1L7Q=="],
175
+ "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.15", "", { "os": "none", "cpu": "arm64" }, "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w=="],
176
176
 
177
- "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-oA4o5o0S2yB199YyYXDzKUv1Z56Rc+mgOjwm7Z/vJ9Z8igiDPYvoOuDyo6g7AK/ZaF09nPhDKVnGBcYHO11GXA=="],
177
+ "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg=="],
178
178
 
179
- "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.14", "", { "os": "win32", "cpu": "x64" }, "sha512-9mE94bf2GZUaR/fUSXCMpBoWkctu421Mi0ORpm4zqfbkjKep7RxzPFa5etcGs5h+2KApoWBOA/hAJa/7saGgEQ=="],
179
+ "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.15", "", { "os": "win32", "cpu": "x64" }, "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ=="],
180
180
 
181
181
  "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
182
182
 
@@ -196,9 +196,9 @@
196
196
 
197
197
  "@squadbase/react": ["@squadbase/react@0.1.0", "", { "dependencies": { "zod": "^4.3.6" }, "peerDependencies": { "@types/react": "17.x || 18.x || 19.x", "react": "17.x || 18.x || 19.x" }, "optionalPeers": ["@types/react"] }, "sha512-k+Dpyj7eH+Yjydw54iEluCjYDae086d12hWgBjNMpw4wLbQGz3CrJ6Yipodg8n1cKUt7zvwddlcTHd79bgKsXg=="],
198
198
 
199
- "@squadbase/vantage": ["@squadbase/vantage@0.6.2-dev1.b332e5a", "", { "dependencies": { "@base-ui/react": "^1.6.0", "@hono/node-server": "^2.1.5", "@streamdown/code": "^1.1.1", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-query": "^5.101.2", "@tanstack/react-router": "^1.170.17", "@tanstack/react-table": "^8.21.3", "@vitejs/plugin-react": "^6.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "echarts": "^6.0.0", "esbuild": "^0.28.1", "fflate": "^0.8.3", "hono": "^4.13.13", "html-to-image": "^1.11.13", "lucide-react": "^0.468.0", "papaparse": "^5.7.0", "picocolors": "^1.1.1", "react-day-picker": "^10.0.1", "read-excel-file": "^9.3.10", "streamdown": "^2.5.0", "tailwind-merge": "^3.0.0", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.0.0", "vite": "^8.3.4" }, "peerDependencies": { "react": ">=18.2.0", "react-dom": ">=18.2.0" }, "bin": { "vantage": "dist/cli.js" } }, "sha512-ZOXkt4dW8OVdWHC5x7j2osRmBpQw0g8StEQ7hSO760TCx/wdqSGgQo7SpUKFqKOkFPO5C6udh9YWog5x43UgAQ=="],
199
+ "@squadbase/vantage": ["@squadbase/vantage@0.6.2-dev1.26a3cce", "", { "dependencies": { "@base-ui/react": "^1.6.0", "@hono/node-server": "^2.1.5", "@streamdown/code": "^1.1.1", "@tailwindcss/vite": "^4.3.3", "@tanstack/react-query": "^5.101.2", "@tanstack/react-router": "^1.170.17", "@tanstack/react-table": "^8.21.3", "@vitejs/plugin-react": "^6.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "echarts": "^6.0.0", "esbuild": "0.28.1", "fflate": "^0.8.3", "hono": "^4.13.13", "html-to-image": "^1.11.13", "lucide-react": "^0.468.0", "papaparse": "^5.7.0", "picocolors": "^1.1.1", "react-day-picker": "^10.0.1", "read-excel-file": "^9.3.10", "shiki": "3.23.0", "streamdown": "^2.5.0", "tailwind-merge": "3.6.0", "tailwindcss": "^4.3.3", "tw-animate-css": "^1.0.0", "vite": "^8.3.4" }, "peerDependencies": { "react": ">=18.2.0", "react-dom": ">=18.2.0", "typescript": ">=5.0.0" }, "optionalPeers": ["typescript"], "bin": { "vantage": "dist/cli.js" } }, "sha512-8O71PkD2yxA2crQnOK4LPP6ozwEcqPck0jqPQNEBokTIVQ5rMj53CO75uxMUVFgHcECSALBp3pCkqL2iMKqPYg=="],
200
200
 
201
- "@squadbase/vantage-sdk": ["@squadbase/vantage-sdk@0.1.1-dev1.28afad5", "", {}, "sha512-Y2d40uYKTARweiy1lslrmTkA35WyhMnco0e7eGSBYs/HVN+CjRBZQbuhZ4ebPw0L0JG+7B2nTQMzZmUdmyeG9w=="],
201
+ "@squadbase/vantage-sdk": ["@squadbase/vantage-sdk@0.1.1-dev1.c070adc", "", {}, "sha512-tB1/cQfBa9YJrU0J/+WGcX9pttVV8dbHIg8TSImQaZ0F2mnkpeeHQ1jVi3YUwc/84fEcoyGLbJbtJHZAvjuY4Q=="],
202
202
 
203
203
  "@streamdown/code": ["@streamdown/code@1.1.1", "", { "dependencies": { "shiki": "^3.19.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-i7HTNuDgZWb+VdrNVOam9gQhIc5MSSDXKWXgbUrn/4vSRaSMM+Rtl10MQj4wLWPNpF7p80waJsAqFP8HZfb0Jg=="],
204
204
 
@@ -716,7 +716,7 @@
716
716
 
717
717
  "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
718
718
 
719
- "read-excel-file": ["read-excel-file@9.3.10", "", { "dependencies": { "fflate": "^0.8.3", "saxen": "^11.1.0", "unzipper-esm": "^0.13.3", "worker-f": "^0.1.12" } }, "sha512-zFcBdzunLCGBmLRT4Q3mLPJnhKPAXXfGAZ83feODlEqX2aRUbgF1h/n2oY0UF7I8tVwnJNRas6fTRD5veDUs+g=="],
719
+ "read-excel-file": ["read-excel-file@9.3.12", "", { "dependencies": { "fflate": "^0.8.3", "saxen": "^11.1.0", "unzipper-esm": "^0.13.3", "worker-f": "^0.1.12" } }, "sha512-benNAoQbe5HqoTi3qrQkR8wMeHq0gVWLt2Br73hVvmBPGdzMf9OLGsps/812AfZ+bvzVYsUyhF77Y3o4B51yCA=="],
720
720
 
721
721
  "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="],
722
722
 
@@ -744,7 +744,7 @@
744
744
 
745
745
  "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="],
746
746
 
747
- "rolldown": ["rolldown@1.2.14", "", { "dependencies": { "@oxc-project/types": "=0.154.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.14", "@rolldown/binding-android-arm64": "1.2.14", "@rolldown/binding-darwin-arm64": "1.2.14", "@rolldown/binding-darwin-x64": "1.2.14", "@rolldown/binding-freebsd-x64": "1.2.14", "@rolldown/binding-linux-arm-gnueabihf": "1.2.14", "@rolldown/binding-linux-arm64-gnu": "1.2.14", "@rolldown/binding-linux-arm64-musl": "1.2.14", "@rolldown/binding-linux-ppc64-gnu": "1.2.14", "@rolldown/binding-linux-s390x-gnu": "1.2.14", "@rolldown/binding-linux-x64-gnu": "1.2.14", "@rolldown/binding-linux-x64-musl": "1.2.14", "@rolldown/binding-openharmony-arm64": "1.2.14", "@rolldown/binding-win32-arm64-msvc": "1.2.14", "@rolldown/binding-win32-x64-msvc": "1.2.14" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw=="],
747
+ "rolldown": ["rolldown@1.2.15", "", { "dependencies": { "@oxc-project/types": "=0.155.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.15", "@rolldown/binding-android-arm64": "1.2.15", "@rolldown/binding-darwin-arm64": "1.2.15", "@rolldown/binding-darwin-x64": "1.2.15", "@rolldown/binding-freebsd-x64": "1.2.15", "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", "@rolldown/binding-linux-arm64-gnu": "1.2.15", "@rolldown/binding-linux-arm64-musl": "1.2.15", "@rolldown/binding-linux-ppc64-gnu": "1.2.15", "@rolldown/binding-linux-s390x-gnu": "1.2.15", "@rolldown/binding-linux-x64-gnu": "1.2.15", "@rolldown/binding-linux-x64-musl": "1.2.15", "@rolldown/binding-openharmony-arm64": "1.2.15", "@rolldown/binding-win32-arm64-msvc": "1.2.15", "@rolldown/binding-win32-x64-msvc": "1.2.15" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g=="],
748
748
 
749
749
  "roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="],
750
750
 
@@ -752,7 +752,7 @@
752
752
 
753
753
  "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
754
754
 
755
- "saxen": ["saxen@11.1.1", "", {}, "sha512-J4BkmJFaM7VgE7pgkFGsNEcqqM3h7+Mz80vfLWFhx7uNOCOXIu6LLjQHYWNejdst3pf/3JUaBIG9+pkk1umlow=="],
755
+ "saxen": ["saxen@11.2.0", "", {}, "sha512-2bG564AAJcm/3vyZC0Uhs/mACrH+4AHMaKHKAB2M5xMqomUZa27FQ7MYaQGFKVcJk/MVzSEQ34A8QZWW+eiWEw=="],
756
756
 
757
757
  "scheduler": ["scheduler@0.28.0", "", {}, "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw=="],
758
758
 
@@ -830,7 +830,7 @@
830
830
 
831
831
  "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
832
832
 
833
- "vite": ["vite@8.3.4", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.29", "rolldown": "~1.2.12", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ=="],
833
+ "vite": ["vite@8.3.5", "", { "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", "postcss": "^8.5.30", "rolldown": "~1.2.14", "tinyglobby": "^0.2.17" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.7.1 || ^0.8.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ=="],
834
834
 
835
835
  "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
836
836
 
@@ -0,0 +1,5 @@
1
+ # サプライチェーン対策: 公開から 48 時間(172800 秒)未満の版は install で解決しない。
2
+ # 自社パッケージは publish 直後の版を雛形が参照するため除外する。
3
+ [install]
4
+ minimumReleaseAge = 172800
5
+ minimumReleaseAgeExcludes = ["@squadbase/vantage", "@squadbase/vantage-sdk", "@squadbase/react"]
@@ -12,8 +12,8 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@squadbase/react": "^0.1.0",
15
- "@squadbase/vantage": "0.6.2-dev1.b332e5a",
16
- "@squadbase/vantage-sdk": "0.1.1-dev1.28afad5",
15
+ "@squadbase/vantage": "0.6.2-dev1.26a3cce",
16
+ "@squadbase/vantage-sdk": "0.1.1-dev1.c070adc",
17
17
  "date-fns": "^4.1.0",
18
18
  "lucide-react": "^0.468.0",
19
19
  "react": "^19.3.1",
@@ -8,13 +8,11 @@ import { BuildRecovery } from "./components/build-recovery"
8
8
  import { UserCard } from "./components/user-card"
9
9
 
10
10
  /**
11
- * `AppShell` is router-agnostic and renders nav entries through whatever
12
- * component it is handed, using an `href` prop. Adapt it to the Vantage router
13
- * so navigation stays client-side.
11
+ * The app's display language, written to `<html lang>` (a BCP 47 literal, e.g.
12
+ * "ja"). Set it to the language of the app's content: it also switches the slide
13
+ * toolbar messages and enables Japanese phrase-aware line breaking in slides.
14
14
  */
15
- function RouterLink({ href, ...props }: { href: string } & ComponentProps<"a">) {
16
- return <Link to={href} {...props} />
17
- }
15
+ export const lang = "en"
18
16
 
19
17
  /**
20
18
  * The nav *is* the route list — adding a page file puts it in the nav, with no
@@ -67,3 +65,12 @@ export default function RootLayout() {
67
65
  </SquadbaseProvider>
68
66
  )
69
67
  }
68
+
69
+ /**
70
+ * `AppShell` is router-agnostic and renders nav entries through whatever
71
+ * component it is handed, using an `href` prop. Adapt it to the Vantage router
72
+ * so navigation stays client-side.
73
+ */
74
+ function RouterLink({ href, ...props }: { href: string } & ComponentProps<"a">) {
75
+ return <Link to={href} {...props} />
76
+ }
@@ -29,6 +29,12 @@ import { Button, Spinner } from "@squadbase/vantage/ui"
29
29
  */
30
30
  const FRAMEWORK_ERROR_SELECTOR = '[role="alert"] h2'
31
31
 
32
+ /** `import.meta.hot` のうち、ここで使う分だけ。 */
33
+ interface ViteHot {
34
+ on(event: string, cb: () => void): void
35
+ off?(event: string, cb: () => void): void
36
+ }
37
+
32
38
  /** 書き込みの連鎖が落ち着くのを待ってからリロードする。 */
33
39
  const RELOAD_DELAY_MS = 1200
34
40
 
@@ -43,6 +49,21 @@ const SETTLE_MS = 5000
43
49
 
44
50
  const RELOAD_COUNT_KEY = "vantage:build-recovery-reloads"
45
51
 
52
+ /**
53
+ * 書きかけのファイルを下書きとして表示している間、Vantage のクライアントが立てる目印。
54
+ * 下書き中の描画エラーはフレームワークが直前に通った版へ戻すので、ここでは覆わず、
55
+ * リロードもしない(リロードすると下書きの表示ごと消える)。
56
+ */
57
+ declare global {
58
+ interface Window {
59
+ __VANTAGE_DRAFT__?: { active: boolean }
60
+ }
61
+ }
62
+
63
+ function isDraftActive(): boolean {
64
+ return window.__VANTAGE_DRAFT__?.active === true
65
+ }
66
+
46
67
  /** コピーしたことが伝わればいいので、確認表示はすぐ元に戻す。 */
47
68
  const COPIED_FEEDBACK_MS = 2000
48
69
 
@@ -90,6 +111,7 @@ export function RecoveringState({ error }: { error?: unknown }) {
90
111
  const attempts = readReloadCount()
91
112
  if (attempts < MAX_RELOADS) {
92
113
  const timer = setTimeout(() => {
114
+ if (isDraftActive()) return
93
115
  writeReloadCount(attempts + 1)
94
116
  window.location.reload()
95
117
  }, RELOAD_DELAY_MS)
@@ -181,6 +203,11 @@ export function BuildRecovery({ children }: { children: ReactNode }) {
181
203
  const host = hostRef.current
182
204
  if (!host) return
183
205
  const sync = () => {
206
+ // 下書きの表示中は覆わない。終わった時点でエラー画面が残っていれば、次の sync で覆う。
207
+ if (isDraftActive()) {
208
+ setMessage(null)
209
+ return
210
+ }
184
211
  const heading = host.querySelector(FRAMEWORK_ERROR_SELECTOR)
185
212
  // 覆って見えなくする以上、支援技術にも読ませない。`role="alert"` のままだと
186
213
  // 「Something went wrong」がそのまま読み上げられてしまう。属性は observe の
@@ -192,7 +219,16 @@ export function BuildRecovery({ children }: { children: ReactNode }) {
192
219
  sync()
193
220
  const observer = new MutationObserver(sync)
194
221
  observer.observe(host, { childList: true, subtree: true })
195
- return () => observer.disconnect()
222
+ // 下書きの有無が変わったときに見直す(目印の更新を待つため 1 tick 遅らせる)。
223
+ const onDraftState = () => setTimeout(sync, 0)
224
+ // 生成される `ImportMeta` は `env` しか宣言しない(HMR の型を入れるとアプリが vite/client を
225
+ // 入れたときに二重宣言になる)ので、ここだけ局所キャストで読む。
226
+ const hot = (import.meta as unknown as { hot?: ViteHot }).hot
227
+ hot?.on("vantage:draft-state", onDraftState)
228
+ return () => {
229
+ observer.disconnect()
230
+ hot?.off?.("vantage:draft-state", onDraftState)
231
+ }
196
232
  }, [])
197
233
 
198
234
  const crashed = message !== null
@@ -11,6 +11,16 @@ import {
11
11
  cn,
12
12
  } from "@squadbase/vantage/ui"
13
13
 
14
+ export function UserCard() {
15
+ const userState = useUser()
16
+
17
+ if (userState.status === "success") {
18
+ return <UserInfo user={userState.data} />
19
+ }
20
+
21
+ return <UserInfoFallback />
22
+ }
23
+
14
24
  /**
15
25
  * Squadbase-authenticated user chip for the app shell.
16
26
  *
@@ -47,7 +57,7 @@ function DetailRow({ label, children }: { label: string; children: React.ReactNo
47
57
 
48
58
  function UserInfo({ user }: { user: User }) {
49
59
  const fullName = `${user.firstName} ${user.lastName}`
50
- const rolesHref = navigator.language.startsWith("ja")
60
+ const rolesHref = document.documentElement.lang.startsWith("ja")
51
61
  ? "https://www.squadbase.dev/ja/docs/access-control#プロジェクトロール"
52
62
  : "https://www.squadbase.dev/docs/access-control#project-roles"
53
63
 
@@ -120,13 +130,3 @@ function UserInfoFallback() {
120
130
  </div>
121
131
  )
122
132
  }
123
-
124
- export function UserCard() {
125
- const userState = useUser()
126
-
127
- if (userState.status === "success") {
128
- return <UserInfo user={userState.data} />
129
- }
130
-
131
- return <UserInfoFallback />
132
- }