@squadbase/vantage 0.6.2 → 0.7.0-dev1.1197de7

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 (357) hide show
  1. package/dist/add-4GHF2TX2.js +6 -0
  2. package/dist/add-4GHF2TX2.js.map +1 -0
  3. package/dist/{build-O5TVNH4E.js → build-U7GO26HR.js} +9 -9
  4. package/dist/{build-O5TVNH4E.js.map → build-U7GO26HR.js.map} +1 -1
  5. package/dist/{check-WFBEDHDR.js → check-MRVAIHG5.js} +7 -7
  6. package/dist/{check-WFBEDHDR.js.map → check-MRVAIHG5.js.map} +1 -1
  7. package/dist/{chunk-QDZA5JSL.js → chunk-AABMKHEU.js} +4 -4
  8. package/dist/{chunk-QDZA5JSL.js.map → chunk-AABMKHEU.js.map} +1 -1
  9. package/dist/{chunk-PVTHHV7X.js → chunk-ANZLVSEP.js} +28 -7
  10. package/dist/chunk-ANZLVSEP.js.map +1 -0
  11. package/dist/chunk-CKWPK4RO.js +50 -0
  12. package/dist/chunk-CKWPK4RO.js.map +1 -0
  13. package/dist/chunk-EG4PX726.js +678 -0
  14. package/dist/chunk-EG4PX726.js.map +1 -0
  15. package/dist/{chunk-3G43C6OL.js → chunk-GNXCX4WE.js} +46 -3
  16. package/dist/chunk-GNXCX4WE.js.map +1 -0
  17. package/dist/chunk-LYUGDHSF.js +61 -0
  18. package/dist/chunk-LYUGDHSF.js.map +1 -0
  19. package/dist/{chunk-RPZAALCX.js → chunk-MQUIAP66.js} +321 -165
  20. package/dist/chunk-MQUIAP66.js.map +1 -0
  21. package/dist/chunk-P2KIHF65.js +152 -0
  22. package/dist/chunk-P2KIHF65.js.map +1 -0
  23. package/dist/{chunk-BCE22JSM.js → chunk-PJ4SPXHS.js} +52 -16
  24. package/dist/chunk-PJ4SPXHS.js.map +1 -0
  25. package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
  26. package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
  27. package/dist/{chunk-PXRX5PEC.js → chunk-ROHNXP7J.js} +73 -4
  28. package/dist/chunk-ROHNXP7J.js.map +1 -0
  29. package/dist/chunk-S5MDTHH7.js +466 -0
  30. package/dist/chunk-S5MDTHH7.js.map +1 -0
  31. package/dist/chunk-SDJTTMLK.js +1877 -0
  32. package/dist/chunk-SDJTTMLK.js.map +1 -0
  33. package/dist/{chunk-EP6JHXSR.js → chunk-SHZM3EXB.js} +68 -12
  34. package/dist/chunk-SHZM3EXB.js.map +1 -0
  35. package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
  36. package/dist/chunk-U736PVHY.js.map +1 -0
  37. package/dist/{chunk-JGRMRXXZ.js → chunk-UWSQUHX6.js} +4 -99
  38. package/dist/chunk-UWSQUHX6.js.map +1 -0
  39. package/dist/chunk-XRKSIC5Z.js +176 -0
  40. package/dist/chunk-XRKSIC5Z.js.map +1 -0
  41. package/dist/chunk-YJQCB3UP.js +10764 -0
  42. package/dist/chunk-YJQCB3UP.js.map +1 -0
  43. package/dist/cli.js +15 -11
  44. package/dist/cli.js.map +1 -1
  45. package/dist/client/index.d.ts +34 -3
  46. package/dist/client/index.js +211 -12
  47. package/dist/client/index.js.map +1 -1
  48. package/dist/components/index.d.ts +2389 -31
  49. package/dist/components/index.js +7 -4
  50. package/dist/delta-text-tav2Lh5d.d.ts +17 -0
  51. package/dist/{dev-NZRLOQCL.js → dev-O42JFQ64.js} +24 -13
  52. package/dist/dev-O42JFQ64.js.map +1 -0
  53. package/dist/doc/index.d.ts +215 -2
  54. package/dist/doc/index.js +423 -5
  55. package/dist/doc/index.js.map +1 -1
  56. package/dist/{docs-ZGDJUHJI.js → docs-JVP4RPKT.js} +3 -3
  57. package/dist/{docs-ZGDJUHJI.js.map → docs-JVP4RPKT.js.map} +1 -1
  58. package/dist/{doctor-VFKEMR54.js → doctor-YD3XAAOT.js} +8 -8
  59. package/dist/doctor-YD3XAAOT.js.map +1 -0
  60. package/dist/format-D34piCei.d.ts +250 -0
  61. package/dist/geo-japan-7BMSOJRX.js +8 -0
  62. package/dist/geo-japan-7BMSOJRX.js.map +1 -0
  63. package/dist/geo-us-GVOG7VXH.js +8 -0
  64. package/dist/geo-us-GVOG7VXH.js.map +1 -0
  65. package/dist/geo-world-35HL56UU.js +8 -0
  66. package/dist/geo-world-35HL56UU.js.map +1 -0
  67. package/dist/markdown/index.js +1 -1
  68. package/dist/markdown/index.js.map +1 -1
  69. package/dist/{preview-QDCIVVSR.js → preview-T6CLSQVX.js} +12 -4
  70. package/dist/preview-T6CLSQVX.js.map +1 -0
  71. package/dist/query/index.d.ts +0 -11
  72. package/dist/query/index.js +2 -2
  73. package/dist/{routes-RHP5FVGD.js → routes-PVKNT777.js} +6 -6
  74. package/dist/{routes-RHP5FVGD.js.map → routes-PVKNT777.js.map} +1 -1
  75. package/dist/{search-RFBELGY7.js → search-5LC4XPB5.js} +3 -3
  76. package/dist/{search-RFBELGY7.js.map → search-5LC4XPB5.js.map} +1 -1
  77. package/dist/slide/index.d.ts +272 -1
  78. package/dist/slide/index.js +1086 -19
  79. package/dist/slide/index.js.map +1 -1
  80. package/dist/table/index.js +13 -10
  81. package/dist/table/index.js.map +1 -1
  82. package/dist/ui/index.d.ts +148 -12
  83. package/dist/ui/index.js +1339 -88
  84. package/dist/ui/index.js.map +1 -1
  85. package/dist/{upgrade-GF2P67M6.js → upgrade-6DT7ADRP.js} +7 -7
  86. package/dist/{upgrade-GF2P67M6.js.map → upgrade-6DT7ADRP.js.map} +1 -1
  87. package/dist/vite/index.d.ts +10 -0
  88. package/dist/vite/index.js +4 -4
  89. package/docs/en/agent-skills.md +1 -1
  90. package/docs/en/changelog.md +82 -0
  91. package/docs/en/cli-reference.md +30 -0
  92. package/docs/en/components.md +42 -17
  93. package/docs/en/doc/delta-text.md +40 -0
  94. package/docs/en/doc/doc-action-items.md +49 -0
  95. package/docs/en/doc/doc-callout.md +38 -0
  96. package/docs/en/doc/doc-data-table.md +60 -0
  97. package/docs/en/doc/doc-executive-summary.md +64 -0
  98. package/docs/en/doc/doc-figure.md +56 -0
  99. package/docs/en/doc/doc-key-findings.md +61 -0
  100. package/docs/en/doc/doc-kpi-scorecard.md +80 -0
  101. package/docs/en/doc/doc-notes-and-sources.md +43 -0
  102. package/docs/en/doc/doc-report-header.md +46 -0
  103. package/docs/en/pages-and-metadata.md +15 -0
  104. package/docs/en/parts/area-chart.md +99 -0
  105. package/docs/en/parts/bar-chart.md +91 -0
  106. package/docs/en/parts/bar-list.md +50 -0
  107. package/docs/en/parts/category-bar.md +37 -0
  108. package/docs/en/parts/chart-frame.md +39 -0
  109. package/docs/en/parts/data-table.md +22 -0
  110. package/docs/en/parts/delta.md +51 -0
  111. package/docs/en/parts/donut-chart.md +72 -0
  112. package/docs/en/parts/draft-chart.md +42 -0
  113. package/docs/en/parts/format.md +43 -0
  114. package/docs/en/parts/funnel-steps.md +2 -1
  115. package/docs/en/parts/heatmap.md +53 -0
  116. package/docs/en/parts/kpi-card.md +58 -0
  117. package/docs/en/parts/legend.md +35 -0
  118. package/docs/en/parts/line-chart.md +94 -0
  119. package/docs/en/parts/metric-value.md +3 -2
  120. package/docs/en/parts/page-shell.md +2 -2
  121. package/docs/en/parts/progress-circle.md +33 -0
  122. package/docs/en/parts/sample-data.md +39 -0
  123. package/docs/en/parts/scatter-chart.md +56 -0
  124. package/docs/en/parts/sparkline.md +1 -1
  125. package/docs/en/parts/tracker.md +36 -0
  126. package/docs/en/parts/trend-indicator.md +17 -1
  127. package/docs/en/parts/updated-at.md +30 -0
  128. package/docs/en/parts/waterfall-chart.md +56 -0
  129. package/docs/en/slide/slide-chart-full.md +48 -0
  130. package/docs/en/slide/slide-chart-insight.md +52 -0
  131. package/docs/en/slide/slide-columns.md +46 -0
  132. package/docs/en/slide/slide-comparison.md +68 -0
  133. package/docs/en/slide/slide-cover.md +39 -0
  134. package/docs/en/slide/slide-exec-summary.md +47 -0
  135. package/docs/en/slide/slide-heading.md +38 -0
  136. package/docs/en/slide/slide-kpi-grid.md +55 -0
  137. package/docs/en/slide/slide-kpi-hero.md +58 -0
  138. package/docs/en/slide/slide-next-actions.md +49 -0
  139. package/docs/en/slide/slide-scorecard-table.md +54 -0
  140. package/docs/en/slide/slide-section.md +44 -0
  141. package/docs/en/slide/slide-source-line.md +34 -0
  142. package/docs/en/ui/alert-dialog.md +42 -0
  143. package/docs/en/ui/avatar.md +31 -0
  144. package/docs/en/ui/combobox.md +74 -0
  145. package/docs/en/ui/drawer.md +41 -0
  146. package/docs/en/ui/empty.md +1 -1
  147. package/docs/en/ui/error-state.md +4 -3
  148. package/docs/en/ui/field.md +42 -0
  149. package/docs/en/ui/hover-card.md +21 -0
  150. package/docs/en/ui/kbd.md +17 -0
  151. package/docs/en/ui/loading.md +1 -1
  152. package/docs/en/ui/pagination.md +36 -0
  153. package/docs/en/ui/radio-group.md +21 -0
  154. package/docs/en/ui/toast.md +44 -0
  155. package/docs/en/ui/toggle-group.md +4 -3
  156. package/docs/en/ui-and-theming.md +1 -1
  157. package/docs/index.json +1222 -132
  158. package/docs/ja/agent-skills.md +1 -1
  159. package/docs/ja/changelog.md +84 -0
  160. package/docs/ja/cli-reference.md +29 -0
  161. package/docs/ja/components.md +68 -101
  162. package/docs/ja/doc/delta-text.md +40 -0
  163. package/docs/ja/doc/doc-action-items.md +49 -0
  164. package/docs/ja/doc/doc-callout.md +38 -0
  165. package/docs/ja/doc/doc-data-table.md +60 -0
  166. package/docs/ja/doc/doc-executive-summary.md +64 -0
  167. package/docs/ja/doc/doc-figure.md +56 -0
  168. package/docs/ja/doc/doc-key-findings.md +61 -0
  169. package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
  170. package/docs/ja/doc/doc-notes-and-sources.md +43 -0
  171. package/docs/ja/doc/doc-report-header.md +46 -0
  172. package/docs/ja/page-types/csv.md +83 -0
  173. package/docs/ja/page-types/doc.md +83 -0
  174. package/docs/ja/page-types/excel.md +82 -0
  175. package/docs/ja/page-types/slide.md +133 -0
  176. package/docs/ja/page-types.md +47 -0
  177. package/docs/ja/pages-and-metadata.md +15 -0
  178. package/docs/ja/parts/area-chart.md +85 -0
  179. package/docs/ja/parts/bar-chart.md +95 -0
  180. package/docs/ja/parts/bar-list.md +58 -0
  181. package/docs/ja/parts/category-bar.md +36 -0
  182. package/docs/ja/parts/chart-frame.md +36 -0
  183. package/docs/ja/parts/data-table.md +22 -0
  184. package/docs/ja/parts/delta.md +51 -0
  185. package/docs/ja/parts/donut-chart.md +66 -0
  186. package/docs/ja/parts/draft-chart.md +40 -0
  187. package/docs/ja/parts/echart.md +3 -0
  188. package/docs/ja/parts/format.md +44 -0
  189. package/docs/ja/parts/funnel-steps.md +27 -8
  190. package/docs/ja/parts/heatmap.md +45 -0
  191. package/docs/ja/parts/kpi-card.md +56 -0
  192. package/docs/ja/parts/legend.md +36 -0
  193. package/docs/ja/parts/line-chart.md +84 -0
  194. package/docs/ja/parts/metric-value.md +3 -2
  195. package/docs/ja/parts/page-shell.md +2 -2
  196. package/docs/ja/parts/progress-circle.md +34 -0
  197. package/docs/ja/parts/sample-data.md +61 -0
  198. package/docs/ja/parts/scatter-chart.md +69 -0
  199. package/docs/ja/parts/sparkline.md +2 -2
  200. package/docs/ja/parts/tracker.md +32 -0
  201. package/docs/ja/parts/trend-indicator.md +17 -1
  202. package/docs/ja/parts/updated-at.md +27 -0
  203. package/docs/ja/parts/waterfall-chart.md +61 -0
  204. package/docs/ja/routing.md +8 -86
  205. package/docs/ja/slide/slide-chart-full.md +48 -0
  206. package/docs/ja/slide/slide-chart-insight.md +52 -0
  207. package/docs/ja/slide/slide-columns.md +46 -0
  208. package/docs/ja/slide/slide-comparison.md +68 -0
  209. package/docs/ja/slide/slide-cover.md +39 -0
  210. package/docs/ja/slide/slide-exec-summary.md +47 -0
  211. package/docs/ja/slide/slide-heading.md +38 -0
  212. package/docs/ja/slide/slide-kpi-grid.md +55 -0
  213. package/docs/ja/slide/slide-kpi-hero.md +58 -0
  214. package/docs/ja/slide/slide-next-actions.md +49 -0
  215. package/docs/ja/slide/slide-scorecard-table.md +54 -0
  216. package/docs/ja/slide/slide-section.md +44 -0
  217. package/docs/ja/slide/slide-source-line.md +34 -0
  218. package/docs/ja/ui/alert-dialog.md +41 -0
  219. package/docs/ja/ui/avatar.md +31 -0
  220. package/docs/ja/ui/combobox.md +74 -0
  221. package/docs/ja/ui/drawer.md +41 -0
  222. package/docs/ja/ui/empty.md +1 -1
  223. package/docs/ja/ui/error-state.md +4 -3
  224. package/docs/ja/ui/field.md +42 -0
  225. package/docs/ja/ui/hover-card.md +21 -0
  226. package/docs/ja/ui/kbd.md +16 -0
  227. package/docs/ja/ui/loading.md +1 -1
  228. package/docs/ja/ui/pagination.md +36 -0
  229. package/docs/ja/ui/radio-group.md +21 -0
  230. package/docs/ja/ui/toast.md +46 -0
  231. package/docs/ja/ui/toggle-group.md +4 -3
  232. package/docs/ja/ui-and-theming.md +14 -7
  233. package/package.json +43 -29
  234. package/registry/parts.json +5221 -0
  235. package/registry/ui/accordion.tsx +76 -0
  236. package/registry/ui/alert-dialog.tsx +189 -0
  237. package/registry/ui/alert.tsx +80 -0
  238. package/registry/ui/app-shell.tsx +424 -0
  239. package/registry/ui/area-chart.tsx +3960 -0
  240. package/registry/ui/attention-list.tsx +465 -0
  241. package/registry/ui/avatar.tsx +110 -0
  242. package/registry/ui/badge.tsx +56 -0
  243. package/registry/ui/bar-chart.tsx +3954 -0
  244. package/registry/ui/bar-list.tsx +3998 -0
  245. package/registry/ui/box-plot-chart.tsx +4214 -0
  246. package/registry/ui/breadcrumb.tsx +128 -0
  247. package/registry/ui/button.tsx +62 -0
  248. package/registry/ui/calendar.tsx +223 -0
  249. package/registry/ui/card.tsx +107 -0
  250. package/registry/ui/category-bar.tsx +1498 -0
  251. package/registry/ui/chart-frame.tsx +1612 -0
  252. package/registry/ui/checkbox.tsx +30 -0
  253. package/registry/ui/collapsible.tsx +23 -0
  254. package/registry/ui/combo-chart.tsx +1852 -0
  255. package/registry/ui/combobox.tsx +310 -0
  256. package/registry/ui/command.tsx +198 -0
  257. package/registry/ui/dashboard-card.tsx +219 -0
  258. package/registry/ui/data-table.tsx +899 -158
  259. package/registry/ui/date-range-picker.tsx +544 -0
  260. package/registry/ui/delta.tsx +352 -0
  261. package/registry/ui/dialog.tsx +161 -0
  262. package/registry/ui/donut-chart.tsx +4006 -0
  263. package/registry/ui/drawer.tsx +229 -0
  264. package/registry/ui/dropdown-menu.tsx +274 -0
  265. package/registry/ui/echart.tsx +1178 -0
  266. package/registry/ui/field.tsx +240 -0
  267. package/registry/ui/filter-bar.tsx +553 -0
  268. package/registry/ui/forecast-chart.tsx +4734 -0
  269. package/registry/ui/funnel-steps.tsx +3843 -0
  270. package/registry/ui/heatmap.tsx +2027 -0
  271. package/registry/ui/histogram-chart.tsx +4284 -0
  272. package/registry/ui/hover-card.tsx +52 -0
  273. package/registry/ui/input-group.tsx +160 -0
  274. package/registry/ui/input.tsx +24 -0
  275. package/registry/ui/kbd.tsx +30 -0
  276. package/registry/ui/kpi-card.tsx +907 -0
  277. package/registry/ui/label.tsx +22 -0
  278. package/registry/ui/legend.tsx +3817 -0
  279. package/registry/ui/line-chart.tsx +3958 -0
  280. package/registry/ui/metric-value.tsx +62 -0
  281. package/registry/ui/multi-select.tsx +382 -0
  282. package/registry/ui/page-shell.tsx +441 -0
  283. package/registry/ui/pagination.tsx +140 -0
  284. package/registry/ui/paired-chart.tsx +4086 -0
  285. package/registry/ui/pivot-table.tsx +1260 -0
  286. package/registry/ui/placeholder.tsx +36 -0
  287. package/registry/ui/popover.tsx +92 -0
  288. package/registry/ui/progress-circle.tsx +1033 -0
  289. package/registry/ui/progress.tsx +85 -0
  290. package/registry/ui/radio-group.tsx +39 -0
  291. package/registry/ui/sample-data.tsx +230 -0
  292. package/registry/ui/scatter-chart.tsx +4503 -0
  293. package/registry/ui/scroll-area.tsx +56 -0
  294. package/registry/ui/searchable-select.tsx +352 -0
  295. package/registry/ui/section-header.tsx +43 -0
  296. package/registry/ui/segmented-control.tsx +76 -0
  297. package/registry/ui/select.tsx +255 -0
  298. package/registry/ui/separator.tsx +27 -0
  299. package/registry/ui/sheet.tsx +139 -0
  300. package/registry/ui/sidebar.tsx +725 -0
  301. package/registry/ui/skeleton.tsx +17 -0
  302. package/registry/ui/slider.tsx +56 -0
  303. package/registry/ui/sparkline.tsx +230 -0
  304. package/registry/ui/spinner.tsx +14 -0
  305. package/registry/ui/states.tsx +247 -0
  306. package/registry/ui/status-badge.tsx +286 -0
  307. package/registry/ui/switch.tsx +34 -0
  308. package/registry/ui/table.tsx +118 -0
  309. package/registry/ui/tabs.tsx +84 -0
  310. package/registry/ui/textarea.tsx +22 -0
  311. package/registry/ui/toast.tsx +250 -0
  312. package/registry/ui/toggle-group.tsx +91 -0
  313. package/registry/ui/toggle.tsx +47 -0
  314. package/registry/ui/tooltip.tsx +72 -0
  315. package/registry/ui/tracker.tsx +1015 -0
  316. package/registry/ui/treemap.tsx +1917 -0
  317. package/registry/ui/trend-indicator.tsx +217 -0
  318. package/registry/ui/updated-at.tsx +276 -0
  319. package/registry/ui/waterfall-chart.tsx +4561 -0
  320. package/skills/vantage-add-feature/SKILL.md +14 -7
  321. package/skills/vantage-design/SKILL.md +62 -52
  322. package/skills/vantage-design/references/extract.md +26 -27
  323. package/skills/vantage-design/references/format.md +12 -172
  324. package/skills/vantage-design/references/presets.md +50 -110
  325. package/skills/vantage-pitfalls/SKILL.md +10 -1
  326. package/skills/vantage-slide/SKILL.md +71 -36
  327. package/templates/AGENTS.md +54 -16
  328. package/templates/agents/api.md +36 -0
  329. package/templates/agents/csv.md +2 -1
  330. package/templates/agents/doc.md +52 -3
  331. package/templates/agents/page.md +91 -10
  332. package/templates/agents/slide.md +90 -4
  333. package/templates/agents/xlsx.md +2 -1
  334. package/theme.css +247 -132
  335. package/dist/add-EISGSZAH.js +0 -6
  336. package/dist/add-EISGSZAH.js.map +0 -1
  337. package/dist/chunk-3G43C6OL.js.map +0 -1
  338. package/dist/chunk-5ZOP4SQR.js +0 -47
  339. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  340. package/dist/chunk-A2UUGASH.js.map +0 -1
  341. package/dist/chunk-BCE22JSM.js.map +0 -1
  342. package/dist/chunk-DTDVSFRY.js +0 -29
  343. package/dist/chunk-DTDVSFRY.js.map +0 -1
  344. package/dist/chunk-EP6JHXSR.js.map +0 -1
  345. package/dist/chunk-JGRMRXXZ.js.map +0 -1
  346. package/dist/chunk-KLEIVDUV.js +0 -165
  347. package/dist/chunk-KLEIVDUV.js.map +0 -1
  348. package/dist/chunk-LSRMRIXA.js +0 -2227
  349. package/dist/chunk-LSRMRIXA.js.map +0 -1
  350. package/dist/chunk-PVTHHV7X.js.map +0 -1
  351. package/dist/chunk-PXRX5PEC.js.map +0 -1
  352. package/dist/chunk-RPZAALCX.js.map +0 -1
  353. package/dist/chunk-T3FLAGI6.js +0 -316
  354. package/dist/chunk-T3FLAGI6.js.map +0 -1
  355. package/dist/dev-NZRLOQCL.js.map +0 -1
  356. package/dist/doctor-VFKEMR54.js.map +0 -1
  357. package/dist/preview-QDCIVVSR.js.map +0 -1
@@ -0,0 +1,424 @@
1
+ // Copied by `vantage add ui app-shell`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/components/app-shell.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ /**
6
+ * AppShell — the outermost application frame. `variant="sidebar"` (default)
7
+ * renders a collapsible sidebar with nested nav groups; `variant="header"`
8
+ * collapses the same nav into a single select in a top bar.
9
+ *
10
+ * Navigation is router-agnostic: pass `linkComponent` to render links with your
11
+ * router's Link, or leave it and `onNavigate` handles the header variant.
12
+ */
13
+ import { forwardRef, type ElementType, type ReactNode } from "react"
14
+ import { ChevronRight } from "lucide-react"
15
+
16
+ import { cn } from "@squadbase/vantage/ui"
17
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@squadbase/vantage/ui"
18
+ import { Separator } from "@squadbase/vantage/ui"
19
+ import {
20
+ Select,
21
+ SelectContent,
22
+ SelectGroup,
23
+ SelectItem,
24
+ SelectLabel,
25
+ SelectTrigger,
26
+ SelectValue,
27
+ } from "@squadbase/vantage/ui"
28
+ import {
29
+ Sidebar,
30
+ SidebarContent,
31
+ SidebarFooter,
32
+ SidebarGroup,
33
+ SidebarGroupLabel,
34
+ SidebarInset,
35
+ SidebarMenu,
36
+ SidebarMenuBadge,
37
+ SidebarMenuButton,
38
+ SidebarMenuItem,
39
+ SidebarMenuSub,
40
+ SidebarMenuSubButton,
41
+ SidebarMenuSubItem,
42
+ SidebarProvider,
43
+ SidebarRail,
44
+ SidebarTrigger,
45
+ } from "@squadbase/vantage/ui"
46
+ import type { NavGroup, NavItem } from "@squadbase/vantage/components"
47
+ import { useSyncExternalStore } from "react"
48
+
49
+ /* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
50
+
51
+ /**
52
+ * The display language of the parts and the defaults that follow it.
53
+ *
54
+ * The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
55
+ * Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
56
+ * (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
57
+ *
58
+ * Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
59
+ * and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
60
+ */
61
+
62
+ /** The language of the built-in wording: Japanese or English. */
63
+ type UiLanguage = "ja" | "en"
64
+
65
+ /** The locale used when `<html lang>` gives none (and on the server). */
66
+ const FALLBACK_LOCALE = "en-US"
67
+
68
+ /** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
69
+ function uiLanguage(locale: string | null | undefined): UiLanguage {
70
+ return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
71
+ }
72
+
73
+ /** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
74
+ function normalizeLocale(tag: string | null | undefined): string {
75
+ const value = tag?.trim()
76
+ if (!value) return FALLBACK_LOCALE
77
+ try {
78
+ return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
79
+ } catch {
80
+ return FALLBACK_LOCALE
81
+ }
82
+ }
83
+
84
+ /**
85
+ * The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
86
+ * invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
87
+ */
88
+ function documentLocale(): string {
89
+ if (typeof document === "undefined") return FALLBACK_LOCALE
90
+ return normalizeLocale(document.documentElement?.getAttribute("lang"))
91
+ }
92
+
93
+ /** `locale` when given, else the page's locale (`documentLocale()`). */
94
+ function resolveLocale(locale?: string | null): string {
95
+ return locale || documentLocale()
96
+ }
97
+
98
+ /** Picks the wording table of the locale's language. */
99
+ function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
100
+ return table[uiLanguage(resolveLocale(locale))]
101
+ }
102
+
103
+ /** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
104
+ function defaultCurrency(locale?: string | null): string {
105
+ return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
106
+ }
107
+
108
+ /** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
109
+ function defaultFiscalYearStartMonth(locale?: string | null): number {
110
+ return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
111
+ }
112
+
113
+ /** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
114
+ type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
115
+
116
+ /** Locales whose week starts on Sunday when the runtime has no week data. */
117
+ const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
118
+
119
+ /**
120
+ * The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
121
+ * (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
122
+ * Monday for the rest.
123
+ */
124
+ function weekStartsOn(locale?: string | null): WeekDay {
125
+ const tag = normalizeLocale(resolveLocale(locale))
126
+ if (uiLanguage(tag) === "ja") return 1
127
+ try {
128
+ const info = new Intl.Locale(tag) as Intl.Locale & {
129
+ getWeekInfo?: () => { firstDay: number }
130
+ weekInfo?: { firstDay: number }
131
+ }
132
+ const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
133
+ if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
134
+ } catch {
135
+ // Fall through to the table below.
136
+ }
137
+ return SUNDAY_FIRST.has(tag) ? 0 : 1
138
+ }
139
+
140
+ /* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
141
+
142
+ const listeners = new Set<() => void>()
143
+ let observer: MutationObserver | null = null
144
+
145
+ /** One observer on `<html lang>` for every subscribed part. */
146
+ function subscribe(onChange: () => void): () => void {
147
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
148
+ listeners.add(onChange)
149
+ if (!observer) {
150
+ observer = new MutationObserver(() => {
151
+ for (const listener of [...listeners]) listener()
152
+ })
153
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
154
+ }
155
+ return () => {
156
+ listeners.delete(onChange)
157
+ if (listeners.size === 0 && observer) {
158
+ observer.disconnect()
159
+ observer = null
160
+ }
161
+ }
162
+ }
163
+
164
+ const serverLocale = () => FALLBACK_LOCALE
165
+
166
+ /**
167
+ * The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
168
+ * hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
169
+ */
170
+ function useDocumentLocale(): string {
171
+ return useSyncExternalStore(subscribe, documentLocale, serverLocale)
172
+ }
173
+
174
+ /** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
175
+ function useLocale(locale?: string | null): string {
176
+ const page = useDocumentLocale()
177
+ return locale || page
178
+ }
179
+
180
+ /* ---------- end of inlined code ---------- */
181
+
182
+ const PAGE_PLACEHOLDER = { ja: "ページを選択", en: "Select a page" }
183
+
184
+ export interface AppShellSidebarProps {
185
+ variant?: "sidebar"
186
+ groups: NavGroup[]
187
+ actions?: ReactNode
188
+ header?: ReactNode
189
+ children: ReactNode
190
+ defaultOpen?: boolean
191
+ className?: string
192
+ linkComponent?: ElementType
193
+ onNavigate?: (href: string) => void
194
+ }
195
+
196
+ export interface AppShellHeaderProps {
197
+ variant: "header"
198
+ groups: NavGroup[]
199
+ actions?: ReactNode
200
+ header?: ReactNode
201
+ children: ReactNode
202
+ className?: string
203
+ linkComponent?: ElementType
204
+ onNavigate?: (href: string) => void
205
+ }
206
+
207
+ export type AppShellProps = AppShellSidebarProps | AppShellHeaderProps
208
+
209
+ /** Nested groups collapse to their leaves — the select is a flat list. */
210
+ function flattenItems(item: NavItem): NavItem[] {
211
+ if (item.children && item.children.length > 0) {
212
+ return item.children.flatMap(flattenItems)
213
+ }
214
+ return [item]
215
+ }
216
+
217
+ function NavSelect({
218
+ groups,
219
+ onNavigate,
220
+ }: {
221
+ groups: NavGroup[]
222
+ onNavigate: (href: string) => void
223
+ }) {
224
+ const allItems = groups.flatMap((g) => g.items.flatMap(flattenItems))
225
+ const currentValue = allItems.find((item) => item.isActive)?.href ?? ""
226
+ // Base UI's SelectValue renders the raw value (the href) unless `items` maps
227
+ // it to a label, so pass the page names explicitly.
228
+ const selectItems = allItems.map((item) => ({ value: item.href, label: item.label }))
229
+ const placeholder = PAGE_PLACEHOLDER[uiLanguage(useLocale())]
230
+
231
+ return (
232
+ <Select
233
+ items={selectItems}
234
+ value={currentValue}
235
+ onValueChange={(href) => {
236
+ // Base UI reports `null` when the selection is cleared; there is no
237
+ // page to navigate to in that case.
238
+ if (href !== null) onNavigate(href)
239
+ }}
240
+ >
241
+ <SelectTrigger size="sm" className="w-48">
242
+ <SelectValue placeholder={placeholder} />
243
+ </SelectTrigger>
244
+ {/*
245
+ Page titles are author-written and often longer than the 12rem trigger,
246
+ so the list is allowed to grow past the anchor width (bounded by the
247
+ viewport) instead of clamping every title to the trigger's width.
248
+ */}
249
+ <SelectContent
250
+ align="start"
251
+ className="w-auto min-w-(--anchor-width) max-w-[min(24rem,var(--available-width))]"
252
+ >
253
+ {groups.map((group, index) => (
254
+ <SelectGroup key={group.label ?? index}>
255
+ {group.label && <SelectLabel>{group.label}</SelectLabel>}
256
+ {group.items.flatMap(flattenItems).map((item) => (
257
+ <SelectItem key={item.href} value={item.href} disabled={item.disabled}>
258
+ {item.label}
259
+ </SelectItem>
260
+ ))}
261
+ </SelectGroup>
262
+ ))}
263
+ </SelectContent>
264
+ </Select>
265
+ )
266
+ }
267
+
268
+ function NavItemWithChildren({
269
+ item,
270
+ linkComponent: LinkComponent = "a",
271
+ }: {
272
+ item: NavItem
273
+ linkComponent?: ElementType
274
+ }) {
275
+ return (
276
+ <Collapsible
277
+ defaultOpen={item.isActive}
278
+ className="group/collapsible"
279
+ render={<SidebarMenuItem />}
280
+ >
281
+ <CollapsibleTrigger
282
+ render={
283
+ <SidebarMenuButton
284
+ tooltip={item.label}
285
+ aria-disabled={item.disabled}
286
+ className={cn(item.disabled && "pointer-events-none")}
287
+ />
288
+ }
289
+ >
290
+ {item.icon && <item.icon />}
291
+ <span>{item.label}</span>
292
+ <ChevronRight className="ml-auto transition-transform duration-200 group-data-open/collapsible:rotate-90" />
293
+ </CollapsibleTrigger>
294
+ {item.badge && <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>}
295
+ <CollapsibleContent>
296
+ <SidebarMenuSub>
297
+ {item.children!.map((child) => (
298
+ <SidebarMenuSubItem key={child.href}>
299
+ <SidebarMenuSubButton
300
+ isActive={child.isActive}
301
+ render={
302
+ <LinkComponent
303
+ href={child.href}
304
+ aria-disabled={child.disabled}
305
+ tabIndex={child.disabled ? -1 : undefined}
306
+ className={cn(child.disabled && "pointer-events-none opacity-50")}
307
+ />
308
+ }
309
+ >
310
+ {child.icon && <child.icon />}
311
+ <span>{child.label}</span>
312
+ </SidebarMenuSubButton>
313
+ </SidebarMenuSubItem>
314
+ ))}
315
+ </SidebarMenuSub>
316
+ </CollapsibleContent>
317
+ </Collapsible>
318
+ )
319
+ }
320
+
321
+ function NavItemLink({
322
+ item,
323
+ linkComponent: LinkComponent = "a",
324
+ }: {
325
+ item: NavItem
326
+ linkComponent?: ElementType
327
+ }) {
328
+ return (
329
+ <SidebarMenuItem>
330
+ <SidebarMenuButton
331
+ tooltip={item.label}
332
+ isActive={item.isActive}
333
+ render={
334
+ <LinkComponent
335
+ href={item.href}
336
+ aria-disabled={item.disabled}
337
+ tabIndex={item.disabled ? -1 : undefined}
338
+ className={cn(item.disabled && "pointer-events-none")}
339
+ />
340
+ }
341
+ >
342
+ {item.icon && <item.icon />}
343
+ <span>{item.label}</span>
344
+ </SidebarMenuButton>
345
+ {item.badge && <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>}
346
+ </SidebarMenuItem>
347
+ )
348
+ }
349
+
350
+ const defaultNavigate = (href: string) => {
351
+ window.location.assign(href)
352
+ }
353
+
354
+ export const AppShell = forwardRef<HTMLDivElement, AppShellProps>((props, ref) => {
355
+ const {
356
+ variant = "sidebar",
357
+ groups,
358
+ actions,
359
+ header,
360
+ children,
361
+ className,
362
+ linkComponent,
363
+ onNavigate = defaultNavigate,
364
+ } = props
365
+
366
+ if (variant === "header") {
367
+ return (
368
+ <div ref={ref} data-slot="app-shell" className={cn("flex h-full flex-col", className)}>
369
+ {header !== undefined ? (
370
+ header
371
+ ) : (
372
+ <header className="flex h-14 shrink-0 items-center gap-3 border-b px-4">
373
+ {groups.length > 0 && <NavSelect groups={groups} onNavigate={onNavigate} />}
374
+ {actions && <div className="ml-auto flex items-center gap-2">{actions}</div>}
375
+ </header>
376
+ )}
377
+ <main className="flex-1 overflow-auto">{children}</main>
378
+ </div>
379
+ )
380
+ }
381
+
382
+ const { defaultOpen = true } = props as AppShellSidebarProps
383
+
384
+ return (
385
+ <SidebarProvider defaultOpen={defaultOpen}>
386
+ <Sidebar data-slot="app-sidebar" collapsible="offcanvas">
387
+ <SidebarContent>
388
+ {groups.map((group, index) => (
389
+ <SidebarGroup key={group.label ?? index}>
390
+ {group.label && <SidebarGroupLabel>{group.label}</SidebarGroupLabel>}
391
+ <SidebarMenu>
392
+ {group.items.map((item) =>
393
+ item.children && item.children.length > 0 ? (
394
+ <NavItemWithChildren
395
+ key={item.href}
396
+ item={item}
397
+ linkComponent={linkComponent}
398
+ />
399
+ ) : (
400
+ <NavItemLink key={item.href} item={item} linkComponent={linkComponent} />
401
+ ),
402
+ )}
403
+ </SidebarMenu>
404
+ </SidebarGroup>
405
+ ))}
406
+ </SidebarContent>
407
+ {actions && <SidebarFooter>{actions}</SidebarFooter>}
408
+ <SidebarRail />
409
+ </Sidebar>
410
+ <SidebarInset ref={ref} data-slot="app-shell" className={className}>
411
+ {header !== undefined ? (
412
+ header
413
+ ) : (
414
+ <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
415
+ <SidebarTrigger />
416
+ <Separator orientation="vertical" className="h-4" />
417
+ </header>
418
+ )}
419
+ <main className="flex-1 overflow-auto">{children}</main>
420
+ </SidebarInset>
421
+ </SidebarProvider>
422
+ )
423
+ })
424
+ AppShell.displayName = "AppShell"