@squadbase/vantage 0.6.2 → 0.7.0-stg.18ca87d

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 (346) 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-2IAPIOPS.js +152 -0
  8. package/dist/chunk-2IAPIOPS.js.map +1 -0
  9. package/dist/chunk-3RJEOP3J.js +174 -0
  10. package/dist/chunk-3RJEOP3J.js.map +1 -0
  11. package/dist/chunk-77CISBMG.js +7581 -0
  12. package/dist/chunk-77CISBMG.js.map +1 -0
  13. package/dist/{chunk-QDZA5JSL.js → chunk-AABMKHEU.js} +4 -4
  14. package/dist/{chunk-QDZA5JSL.js.map → chunk-AABMKHEU.js.map} +1 -1
  15. package/dist/{chunk-PVTHHV7X.js → chunk-ANZLVSEP.js} +28 -7
  16. package/dist/chunk-ANZLVSEP.js.map +1 -0
  17. package/dist/chunk-CKWPK4RO.js +50 -0
  18. package/dist/chunk-CKWPK4RO.js.map +1 -0
  19. package/dist/chunk-EG4PX726.js +678 -0
  20. package/dist/chunk-EG4PX726.js.map +1 -0
  21. package/dist/{chunk-3G43C6OL.js → chunk-GNXCX4WE.js} +46 -3
  22. package/dist/chunk-GNXCX4WE.js.map +1 -0
  23. package/dist/chunk-NZ5QIIG4.js +74 -0
  24. package/dist/chunk-NZ5QIIG4.js.map +1 -0
  25. package/dist/{chunk-BCE22JSM.js → chunk-PJ4SPXHS.js} +52 -16
  26. package/dist/chunk-PJ4SPXHS.js.map +1 -0
  27. package/dist/{chunk-RPZAALCX.js → chunk-QNOX7WLZ.js} +256 -165
  28. package/dist/chunk-QNOX7WLZ.js.map +1 -0
  29. package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
  30. package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
  31. package/dist/{chunk-PXRX5PEC.js → chunk-ROHNXP7J.js} +73 -4
  32. package/dist/chunk-ROHNXP7J.js.map +1 -0
  33. package/dist/chunk-S5MDTHH7.js +466 -0
  34. package/dist/chunk-S5MDTHH7.js.map +1 -0
  35. package/dist/chunk-SDJTTMLK.js +1877 -0
  36. package/dist/chunk-SDJTTMLK.js.map +1 -0
  37. package/dist/{chunk-EP6JHXSR.js → chunk-SHZM3EXB.js} +68 -12
  38. package/dist/chunk-SHZM3EXB.js.map +1 -0
  39. package/dist/chunk-TRMHNMMZ.js +61 -0
  40. package/dist/chunk-TRMHNMMZ.js.map +1 -0
  41. package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
  42. package/dist/chunk-U736PVHY.js.map +1 -0
  43. package/dist/{chunk-JGRMRXXZ.js → chunk-UWSQUHX6.js} +4 -99
  44. package/dist/chunk-UWSQUHX6.js.map +1 -0
  45. package/dist/cli.js +15 -11
  46. package/dist/cli.js.map +1 -1
  47. package/dist/client/index.d.ts +34 -3
  48. package/dist/client/index.js +211 -12
  49. package/dist/client/index.js.map +1 -1
  50. package/dist/components/index.d.ts +1768 -30
  51. package/dist/components/index.js +7 -4
  52. package/dist/delta-text-CbrOaW83.d.ts +17 -0
  53. package/dist/{dev-NZRLOQCL.js → dev-O42JFQ64.js} +24 -13
  54. package/dist/dev-O42JFQ64.js.map +1 -0
  55. package/dist/doc/index.d.ts +215 -2
  56. package/dist/doc/index.js +423 -5
  57. package/dist/doc/index.js.map +1 -1
  58. package/dist/{docs-ZGDJUHJI.js → docs-JVP4RPKT.js} +3 -3
  59. package/dist/{docs-ZGDJUHJI.js.map → docs-JVP4RPKT.js.map} +1 -1
  60. package/dist/{doctor-VFKEMR54.js → doctor-YD3XAAOT.js} +8 -8
  61. package/dist/doctor-YD3XAAOT.js.map +1 -0
  62. package/dist/format-DihQkL1N.d.ts +249 -0
  63. package/dist/markdown/index.js +1 -1
  64. package/dist/markdown/index.js.map +1 -1
  65. package/dist/{preview-QDCIVVSR.js → preview-T6CLSQVX.js} +12 -4
  66. package/dist/preview-T6CLSQVX.js.map +1 -0
  67. package/dist/query/index.d.ts +0 -11
  68. package/dist/query/index.js +2 -2
  69. package/dist/{routes-RHP5FVGD.js → routes-PVKNT777.js} +6 -6
  70. package/dist/{routes-RHP5FVGD.js.map → routes-PVKNT777.js.map} +1 -1
  71. package/dist/{search-RFBELGY7.js → search-5LC4XPB5.js} +3 -3
  72. package/dist/{search-RFBELGY7.js.map → search-5LC4XPB5.js.map} +1 -1
  73. package/dist/slide/index.d.ts +272 -1
  74. package/dist/slide/index.js +1086 -19
  75. package/dist/slide/index.js.map +1 -1
  76. package/dist/table/index.js +14 -10
  77. package/dist/table/index.js.map +1 -1
  78. package/dist/ui/index.d.ts +148 -12
  79. package/dist/ui/index.js +1340 -88
  80. package/dist/ui/index.js.map +1 -1
  81. package/dist/{upgrade-GF2P67M6.js → upgrade-6DT7ADRP.js} +7 -7
  82. package/dist/{upgrade-GF2P67M6.js.map → upgrade-6DT7ADRP.js.map} +1 -1
  83. package/dist/vite/index.d.ts +10 -0
  84. package/dist/vite/index.js +4 -4
  85. package/docs/en/agent-skills.md +1 -1
  86. package/docs/en/changelog.md +82 -0
  87. package/docs/en/cli-reference.md +30 -0
  88. package/docs/en/components.md +42 -17
  89. package/docs/en/doc/delta-text.md +40 -0
  90. package/docs/en/doc/doc-action-items.md +49 -0
  91. package/docs/en/doc/doc-callout.md +38 -0
  92. package/docs/en/doc/doc-data-table.md +60 -0
  93. package/docs/en/doc/doc-executive-summary.md +64 -0
  94. package/docs/en/doc/doc-figure.md +56 -0
  95. package/docs/en/doc/doc-key-findings.md +61 -0
  96. package/docs/en/doc/doc-kpi-scorecard.md +80 -0
  97. package/docs/en/doc/doc-notes-and-sources.md +43 -0
  98. package/docs/en/doc/doc-report-header.md +46 -0
  99. package/docs/en/pages-and-metadata.md +15 -0
  100. package/docs/en/parts/area-chart.md +99 -0
  101. package/docs/en/parts/bar-chart.md +91 -0
  102. package/docs/en/parts/bar-list.md +50 -0
  103. package/docs/en/parts/category-bar.md +37 -0
  104. package/docs/en/parts/chart-frame.md +39 -0
  105. package/docs/en/parts/data-table.md +22 -0
  106. package/docs/en/parts/delta.md +51 -0
  107. package/docs/en/parts/donut-chart.md +72 -0
  108. package/docs/en/parts/format.md +43 -0
  109. package/docs/en/parts/funnel-steps.md +2 -1
  110. package/docs/en/parts/heatmap.md +53 -0
  111. package/docs/en/parts/kpi-card.md +58 -0
  112. package/docs/en/parts/legend.md +35 -0
  113. package/docs/en/parts/line-chart.md +94 -0
  114. package/docs/en/parts/metric-value.md +3 -2
  115. package/docs/en/parts/page-shell.md +1 -1
  116. package/docs/en/parts/progress-circle.md +33 -0
  117. package/docs/en/parts/sample-data.md +39 -0
  118. package/docs/en/parts/scatter-chart.md +56 -0
  119. package/docs/en/parts/sparkline.md +1 -1
  120. package/docs/en/parts/tracker.md +36 -0
  121. package/docs/en/parts/trend-indicator.md +17 -1
  122. package/docs/en/parts/updated-at.md +30 -0
  123. package/docs/en/parts/waterfall-chart.md +56 -0
  124. package/docs/en/slide/slide-chart-full.md +48 -0
  125. package/docs/en/slide/slide-chart-insight.md +52 -0
  126. package/docs/en/slide/slide-columns.md +46 -0
  127. package/docs/en/slide/slide-comparison.md +68 -0
  128. package/docs/en/slide/slide-cover.md +39 -0
  129. package/docs/en/slide/slide-exec-summary.md +47 -0
  130. package/docs/en/slide/slide-heading.md +38 -0
  131. package/docs/en/slide/slide-kpi-grid.md +55 -0
  132. package/docs/en/slide/slide-kpi-hero.md +58 -0
  133. package/docs/en/slide/slide-next-actions.md +49 -0
  134. package/docs/en/slide/slide-scorecard-table.md +54 -0
  135. package/docs/en/slide/slide-section.md +44 -0
  136. package/docs/en/slide/slide-source-line.md +34 -0
  137. package/docs/en/ui/alert-dialog.md +42 -0
  138. package/docs/en/ui/avatar.md +31 -0
  139. package/docs/en/ui/combobox.md +74 -0
  140. package/docs/en/ui/drawer.md +41 -0
  141. package/docs/en/ui/empty.md +1 -1
  142. package/docs/en/ui/error-state.md +4 -3
  143. package/docs/en/ui/field.md +42 -0
  144. package/docs/en/ui/hover-card.md +21 -0
  145. package/docs/en/ui/kbd.md +17 -0
  146. package/docs/en/ui/loading.md +1 -1
  147. package/docs/en/ui/pagination.md +36 -0
  148. package/docs/en/ui/radio-group.md +21 -0
  149. package/docs/en/ui/toast.md +44 -0
  150. package/docs/en/ui/toggle-group.md +4 -3
  151. package/docs/en/ui-and-theming.md +1 -1
  152. package/docs/index.json +1184 -114
  153. package/docs/ja/agent-skills.md +1 -1
  154. package/docs/ja/changelog.md +84 -0
  155. package/docs/ja/cli-reference.md +29 -0
  156. package/docs/ja/components.md +68 -101
  157. package/docs/ja/doc/delta-text.md +40 -0
  158. package/docs/ja/doc/doc-action-items.md +49 -0
  159. package/docs/ja/doc/doc-callout.md +38 -0
  160. package/docs/ja/doc/doc-data-table.md +60 -0
  161. package/docs/ja/doc/doc-executive-summary.md +64 -0
  162. package/docs/ja/doc/doc-figure.md +56 -0
  163. package/docs/ja/doc/doc-key-findings.md +61 -0
  164. package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
  165. package/docs/ja/doc/doc-notes-and-sources.md +43 -0
  166. package/docs/ja/doc/doc-report-header.md +46 -0
  167. package/docs/ja/page-types/csv.md +83 -0
  168. package/docs/ja/page-types/doc.md +83 -0
  169. package/docs/ja/page-types/excel.md +82 -0
  170. package/docs/ja/page-types/slide.md +133 -0
  171. package/docs/ja/page-types.md +47 -0
  172. package/docs/ja/pages-and-metadata.md +15 -0
  173. package/docs/ja/parts/area-chart.md +85 -0
  174. package/docs/ja/parts/bar-chart.md +95 -0
  175. package/docs/ja/parts/bar-list.md +58 -0
  176. package/docs/ja/parts/category-bar.md +36 -0
  177. package/docs/ja/parts/chart-frame.md +36 -0
  178. package/docs/ja/parts/data-table.md +22 -0
  179. package/docs/ja/parts/delta.md +51 -0
  180. package/docs/ja/parts/donut-chart.md +66 -0
  181. package/docs/ja/parts/echart.md +3 -0
  182. package/docs/ja/parts/format.md +44 -0
  183. package/docs/ja/parts/funnel-steps.md +27 -8
  184. package/docs/ja/parts/heatmap.md +45 -0
  185. package/docs/ja/parts/kpi-card.md +56 -0
  186. package/docs/ja/parts/legend.md +36 -0
  187. package/docs/ja/parts/line-chart.md +84 -0
  188. package/docs/ja/parts/metric-value.md +3 -2
  189. package/docs/ja/parts/page-shell.md +1 -1
  190. package/docs/ja/parts/progress-circle.md +34 -0
  191. package/docs/ja/parts/sample-data.md +61 -0
  192. package/docs/ja/parts/scatter-chart.md +69 -0
  193. package/docs/ja/parts/sparkline.md +2 -2
  194. package/docs/ja/parts/tracker.md +32 -0
  195. package/docs/ja/parts/trend-indicator.md +17 -1
  196. package/docs/ja/parts/updated-at.md +27 -0
  197. package/docs/ja/parts/waterfall-chart.md +61 -0
  198. package/docs/ja/routing.md +8 -86
  199. package/docs/ja/slide/slide-chart-full.md +48 -0
  200. package/docs/ja/slide/slide-chart-insight.md +52 -0
  201. package/docs/ja/slide/slide-columns.md +46 -0
  202. package/docs/ja/slide/slide-comparison.md +68 -0
  203. package/docs/ja/slide/slide-cover.md +39 -0
  204. package/docs/ja/slide/slide-exec-summary.md +47 -0
  205. package/docs/ja/slide/slide-heading.md +38 -0
  206. package/docs/ja/slide/slide-kpi-grid.md +55 -0
  207. package/docs/ja/slide/slide-kpi-hero.md +58 -0
  208. package/docs/ja/slide/slide-next-actions.md +49 -0
  209. package/docs/ja/slide/slide-scorecard-table.md +54 -0
  210. package/docs/ja/slide/slide-section.md +44 -0
  211. package/docs/ja/slide/slide-source-line.md +34 -0
  212. package/docs/ja/ui/alert-dialog.md +41 -0
  213. package/docs/ja/ui/avatar.md +31 -0
  214. package/docs/ja/ui/combobox.md +74 -0
  215. package/docs/ja/ui/drawer.md +41 -0
  216. package/docs/ja/ui/empty.md +1 -1
  217. package/docs/ja/ui/error-state.md +4 -3
  218. package/docs/ja/ui/field.md +42 -0
  219. package/docs/ja/ui/hover-card.md +21 -0
  220. package/docs/ja/ui/kbd.md +16 -0
  221. package/docs/ja/ui/loading.md +1 -1
  222. package/docs/ja/ui/pagination.md +36 -0
  223. package/docs/ja/ui/radio-group.md +21 -0
  224. package/docs/ja/ui/toast.md +46 -0
  225. package/docs/ja/ui/toggle-group.md +4 -3
  226. package/docs/ja/ui-and-theming.md +14 -7
  227. package/package.json +43 -29
  228. package/registry/ui/accordion.tsx +76 -0
  229. package/registry/ui/alert-dialog.tsx +189 -0
  230. package/registry/ui/alert.tsx +80 -0
  231. package/registry/ui/app-shell.tsx +424 -0
  232. package/registry/ui/area-chart.tsx +3960 -0
  233. package/registry/ui/attention-list.tsx +465 -0
  234. package/registry/ui/avatar.tsx +110 -0
  235. package/registry/ui/badge.tsx +56 -0
  236. package/registry/ui/bar-chart.tsx +3954 -0
  237. package/registry/ui/bar-list.tsx +3998 -0
  238. package/registry/ui/box-plot-chart.tsx +4214 -0
  239. package/registry/ui/breadcrumb.tsx +128 -0
  240. package/registry/ui/button.tsx +62 -0
  241. package/registry/ui/calendar.tsx +223 -0
  242. package/registry/ui/card.tsx +107 -0
  243. package/registry/ui/category-bar.tsx +1498 -0
  244. package/registry/ui/chart-frame.tsx +1604 -0
  245. package/registry/ui/checkbox.tsx +30 -0
  246. package/registry/ui/collapsible.tsx +23 -0
  247. package/registry/ui/combobox.tsx +310 -0
  248. package/registry/ui/command.tsx +198 -0
  249. package/registry/ui/dashboard-card.tsx +217 -0
  250. package/registry/ui/data-table.tsx +896 -157
  251. package/registry/ui/date-range-picker.tsx +544 -0
  252. package/registry/ui/delta.tsx +350 -0
  253. package/registry/ui/dialog.tsx +161 -0
  254. package/registry/ui/donut-chart.tsx +4006 -0
  255. package/registry/ui/drawer.tsx +229 -0
  256. package/registry/ui/dropdown-menu.tsx +274 -0
  257. package/registry/ui/echart.tsx +1178 -0
  258. package/registry/ui/field.tsx +240 -0
  259. package/registry/ui/filter-bar.tsx +551 -0
  260. package/registry/ui/funnel-steps.tsx +3843 -0
  261. package/registry/ui/heatmap.tsx +2027 -0
  262. package/registry/ui/histogram-chart.tsx +4284 -0
  263. package/registry/ui/hover-card.tsx +52 -0
  264. package/registry/ui/input-group.tsx +160 -0
  265. package/registry/ui/input.tsx +24 -0
  266. package/registry/ui/kbd.tsx +30 -0
  267. package/registry/ui/kpi-card.tsx +905 -0
  268. package/registry/ui/label.tsx +22 -0
  269. package/registry/ui/legend.tsx +3817 -0
  270. package/registry/ui/line-chart.tsx +3958 -0
  271. package/registry/ui/metric-value.tsx +62 -0
  272. package/registry/ui/multi-select.tsx +382 -0
  273. package/registry/ui/page-shell.tsx +420 -0
  274. package/registry/ui/pagination.tsx +140 -0
  275. package/registry/ui/paired-chart.tsx +4086 -0
  276. package/registry/ui/placeholder.tsx +36 -0
  277. package/registry/ui/popover.tsx +92 -0
  278. package/registry/ui/progress-circle.tsx +1033 -0
  279. package/registry/ui/progress.tsx +85 -0
  280. package/registry/ui/radio-group.tsx +39 -0
  281. package/registry/ui/sample-data.tsx +230 -0
  282. package/registry/ui/scatter-chart.tsx +4503 -0
  283. package/registry/ui/scroll-area.tsx +56 -0
  284. package/registry/ui/searchable-select.tsx +352 -0
  285. package/registry/ui/section-header.tsx +43 -0
  286. package/registry/ui/segmented-control.tsx +76 -0
  287. package/registry/ui/select.tsx +255 -0
  288. package/registry/ui/separator.tsx +27 -0
  289. package/registry/ui/sheet.tsx +139 -0
  290. package/registry/ui/sidebar.tsx +725 -0
  291. package/registry/ui/skeleton.tsx +17 -0
  292. package/registry/ui/slider.tsx +56 -0
  293. package/registry/ui/sparkline.tsx +230 -0
  294. package/registry/ui/spinner.tsx +14 -0
  295. package/registry/ui/states.tsx +247 -0
  296. package/registry/ui/status-badge.tsx +286 -0
  297. package/registry/ui/switch.tsx +34 -0
  298. package/registry/ui/table.tsx +118 -0
  299. package/registry/ui/tabs.tsx +84 -0
  300. package/registry/ui/textarea.tsx +22 -0
  301. package/registry/ui/toast.tsx +250 -0
  302. package/registry/ui/toggle-group.tsx +91 -0
  303. package/registry/ui/toggle.tsx +47 -0
  304. package/registry/ui/tooltip.tsx +72 -0
  305. package/registry/ui/tracker.tsx +1015 -0
  306. package/registry/ui/trend-indicator.tsx +217 -0
  307. package/registry/ui/updated-at.tsx +276 -0
  308. package/registry/ui/waterfall-chart.tsx +4561 -0
  309. package/skills/vantage-add-feature/SKILL.md +14 -7
  310. package/skills/vantage-design/SKILL.md +62 -52
  311. package/skills/vantage-design/references/extract.md +26 -27
  312. package/skills/vantage-design/references/format.md +12 -172
  313. package/skills/vantage-design/references/presets.md +50 -110
  314. package/skills/vantage-pitfalls/SKILL.md +10 -1
  315. package/skills/vantage-slide/SKILL.md +71 -36
  316. package/templates/AGENTS.md +54 -16
  317. package/templates/agents/api.md +36 -0
  318. package/templates/agents/csv.md +2 -1
  319. package/templates/agents/doc.md +52 -3
  320. package/templates/agents/page.md +91 -10
  321. package/templates/agents/slide.md +90 -4
  322. package/templates/agents/xlsx.md +2 -1
  323. package/theme.css +247 -132
  324. package/dist/add-EISGSZAH.js +0 -6
  325. package/dist/add-EISGSZAH.js.map +0 -1
  326. package/dist/chunk-3G43C6OL.js.map +0 -1
  327. package/dist/chunk-5ZOP4SQR.js +0 -47
  328. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  329. package/dist/chunk-A2UUGASH.js.map +0 -1
  330. package/dist/chunk-BCE22JSM.js.map +0 -1
  331. package/dist/chunk-DTDVSFRY.js +0 -29
  332. package/dist/chunk-DTDVSFRY.js.map +0 -1
  333. package/dist/chunk-EP6JHXSR.js.map +0 -1
  334. package/dist/chunk-JGRMRXXZ.js.map +0 -1
  335. package/dist/chunk-KLEIVDUV.js +0 -165
  336. package/dist/chunk-KLEIVDUV.js.map +0 -1
  337. package/dist/chunk-LSRMRIXA.js +0 -2227
  338. package/dist/chunk-LSRMRIXA.js.map +0 -1
  339. package/dist/chunk-PVTHHV7X.js.map +0 -1
  340. package/dist/chunk-PXRX5PEC.js.map +0 -1
  341. package/dist/chunk-RPZAALCX.js.map +0 -1
  342. package/dist/chunk-T3FLAGI6.js +0 -316
  343. package/dist/chunk-T3FLAGI6.js.map +0 -1
  344. package/dist/dev-NZRLOQCL.js.map +0 -1
  345. package/dist/doctor-VFKEMR54.js.map +0 -1
  346. package/dist/preview-QDCIVVSR.js.map +0 -1
@@ -0,0 +1,217 @@
1
+ // Copied by `vantage add ui trend-indicator`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/components/trend-indicator.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ /**
6
+ * TrendIndicator — an arrow plus percentage change. Colour tracks *sentiment*,
7
+ * not direction: set `positiveIsGood={false}` for metrics where going up is bad
8
+ * (churn, error rate) and a rise renders as negative.
9
+ *
10
+ * @deprecated 新規は Delta を使う。value/direction を別々に受けるため食い違える(C4)。
11
+ */
12
+ import { forwardRef } from "react"
13
+ import { ArrowDown, ArrowUp, Minus } from "lucide-react"
14
+ import { cva } from "class-variance-authority"
15
+
16
+ import { cn } from "@squadbase/vantage/ui"
17
+ import type { TrendDirection } from "@squadbase/vantage/components"
18
+ import { useSyncExternalStore } from "react"
19
+
20
+ /* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
21
+
22
+ /**
23
+ * The display language of the parts and the defaults that follow it.
24
+ *
25
+ * The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
26
+ * Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
27
+ * (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
28
+ *
29
+ * Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
30
+ * and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
31
+ */
32
+
33
+ /** The language of the built-in wording: Japanese or English. */
34
+ type UiLanguage = "ja" | "en"
35
+
36
+ /** The locale used when `<html lang>` gives none (and on the server). */
37
+ const FALLBACK_LOCALE = "en-US"
38
+
39
+ /** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
40
+ function uiLanguage(locale: string | null | undefined): UiLanguage {
41
+ return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
42
+ }
43
+
44
+ /** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
45
+ function normalizeLocale(tag: string | null | undefined): string {
46
+ const value = tag?.trim()
47
+ if (!value) return FALLBACK_LOCALE
48
+ try {
49
+ return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
50
+ } catch {
51
+ return FALLBACK_LOCALE
52
+ }
53
+ }
54
+
55
+ /**
56
+ * The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
57
+ * invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
58
+ */
59
+ function documentLocale(): string {
60
+ if (typeof document === "undefined") return FALLBACK_LOCALE
61
+ return normalizeLocale(document.documentElement?.getAttribute("lang"))
62
+ }
63
+
64
+ /** `locale` when given, else the page's locale (`documentLocale()`). */
65
+ function resolveLocale(locale?: string | null): string {
66
+ return locale || documentLocale()
67
+ }
68
+
69
+ /** Picks the wording table of the locale's language. */
70
+ function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
71
+ return table[uiLanguage(resolveLocale(locale))]
72
+ }
73
+
74
+ /** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
75
+ function defaultCurrency(locale?: string | null): string {
76
+ return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
77
+ }
78
+
79
+ /** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
80
+ function defaultFiscalYearStartMonth(locale?: string | null): number {
81
+ return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
82
+ }
83
+
84
+ /** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
85
+ type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
86
+
87
+ /** Locales whose week starts on Sunday when the runtime has no week data. */
88
+ const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
89
+
90
+ /**
91
+ * The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
92
+ * (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
93
+ * Monday for the rest.
94
+ */
95
+ function weekStartsOn(locale?: string | null): WeekDay {
96
+ const tag = normalizeLocale(resolveLocale(locale))
97
+ if (uiLanguage(tag) === "ja") return 1
98
+ try {
99
+ const info = new Intl.Locale(tag) as Intl.Locale & {
100
+ getWeekInfo?: () => { firstDay: number }
101
+ weekInfo?: { firstDay: number }
102
+ }
103
+ const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
104
+ if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
105
+ } catch {
106
+ // Fall through to the table below.
107
+ }
108
+ return SUNDAY_FIRST.has(tag) ? 0 : 1
109
+ }
110
+
111
+ /* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
112
+
113
+ const listeners = new Set<() => void>()
114
+ let observer: MutationObserver | null = null
115
+
116
+ /** One observer on `<html lang>` for every subscribed part. */
117
+ function subscribe(onChange: () => void): () => void {
118
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
119
+ listeners.add(onChange)
120
+ if (!observer) {
121
+ observer = new MutationObserver(() => {
122
+ for (const listener of [...listeners]) listener()
123
+ })
124
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
125
+ }
126
+ return () => {
127
+ listeners.delete(onChange)
128
+ if (listeners.size === 0 && observer) {
129
+ observer.disconnect()
130
+ observer = null
131
+ }
132
+ }
133
+ }
134
+
135
+ const serverLocale = () => FALLBACK_LOCALE
136
+
137
+ /**
138
+ * The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
139
+ * hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
140
+ */
141
+ function useDocumentLocale(): string {
142
+ return useSyncExternalStore(subscribe, documentLocale, serverLocale)
143
+ }
144
+
145
+ /** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
146
+ function useLocale(locale?: string | null): string {
147
+ const page = useDocumentLocale()
148
+ return locale || page
149
+ }
150
+
151
+ /* ---------- end of inlined code ---------- */
152
+
153
+ const TEXT = {
154
+ ja: {
155
+ flat: (value: number) => `変化なし ${value}%`,
156
+ up: (value: number) => `${value}% 増加`,
157
+ down: (value: number) => `${value}% 減少`,
158
+ },
159
+ en: {
160
+ flat: (value: number) => `No change ${value}%`,
161
+ up: (value: number) => `Up ${value}%`,
162
+ down: (value: number) => `Down ${value}%`,
163
+ },
164
+ }
165
+
166
+ const trendIndicatorVariants = cva("inline-flex items-center gap-0.5 text-sm font-medium", {
167
+ variants: {
168
+ sentiment: {
169
+ positive: "text-positive",
170
+ negative: "text-negative",
171
+ neutral: "text-muted-foreground",
172
+ },
173
+ },
174
+ defaultVariants: {
175
+ sentiment: "neutral",
176
+ },
177
+ })
178
+
179
+ /**
180
+ * @deprecated 新規は Delta を使う。value/direction を別々に受けるため食い違える(C4)。
181
+ */
182
+ export interface TrendIndicatorProps {
183
+ value: number
184
+ direction: TrendDirection
185
+ positiveIsGood?: boolean
186
+ className?: string
187
+ }
188
+
189
+ /**
190
+ * Arrow plus percentage change.
191
+ *
192
+ * @deprecated 新規は Delta を使う。value/direction を別々に受けるため食い違える(C4)。
193
+ */
194
+ export const TrendIndicator = forwardRef<HTMLSpanElement, TrendIndicatorProps>(
195
+ ({ value, direction, positiveIsGood = true, className }, ref) => {
196
+ const isGood = direction === "neutral" ? null : (direction === "up") === positiveIsGood
197
+ const sentiment = isGood === null ? "neutral" : isGood ? "positive" : "negative"
198
+
199
+ const Icon = direction === "up" ? ArrowUp : direction === "down" ? ArrowDown : Minus
200
+
201
+ const t = TEXT[uiLanguage(useLocale())]
202
+ const ariaLabel = direction === "neutral" ? t.flat(value) : direction === "up" ? t.up(value) : t.down(value)
203
+
204
+ return (
205
+ <span
206
+ ref={ref}
207
+ data-slot="trend-indicator"
208
+ className={cn(trendIndicatorVariants({ sentiment }), className)}
209
+ aria-label={ariaLabel}
210
+ >
211
+ <Icon className="size-3.5" aria-hidden="true" />
212
+ <span>{value}%</span>
213
+ </span>
214
+ )
215
+ },
216
+ )
217
+ TrendIndicator.displayName = "TrendIndicator"
@@ -0,0 +1,276 @@
1
+ // Copied by `vantage add ui updated-at`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/components/updated-at.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ /**
6
+ * UpdatedAt — freshness label. Renders a `<time>` whose `dateTime` is the ISO
7
+ * instant, with the absolute time and zone ("2026/10/20 16:41 JST") in both a
8
+ * tooltip and the `title` attribute.
9
+ *
10
+ * `variant="relative"` (default) reads "Updated 23 minutes ago" (ja: "23 分前に更新"); `"absolute-first"` reads
11
+ * "Updated 16:41 (23 minutes ago)" (ja: "16:41 更新(23 分前)") (the date is added when it is not today).
12
+ * The language and date format follow the page (`<html lang>`).
13
+ *
14
+ * Hydration-safe: the first render (server and client) is an empty `<time>`
15
+ * carrying only the ISO `dateTime`, because the text depends on the clock and
16
+ * time zone of whoever renders. After mount it shows the label and refreshes
17
+ * every 60 seconds; the interval is cleared on unmount. `now` pins the clock
18
+ * (tests, fixtures) and skips the timer; `timeZone` pins the zone. The `<time>`
19
+ * sets `suppressHydrationWarning` so sample data built from `Date.now()` at
20
+ * module load (which differs between server and client) does not warn.
21
+ */
22
+ import { forwardRef, useEffect, useState } from "react"
23
+
24
+ import { EMPTY_VALUE, formatDate } from "@squadbase/vantage/components"
25
+ import { formatRelativeTime } from "@squadbase/vantage/components"
26
+ import { cn } from "@squadbase/vantage/ui"
27
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@squadbase/vantage/ui"
28
+ import { useSyncExternalStore } from "react"
29
+
30
+ /* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
31
+
32
+ /**
33
+ * The display language of the parts and the defaults that follow it.
34
+ *
35
+ * The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
36
+ * Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
37
+ * (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
38
+ *
39
+ * Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
40
+ * and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
41
+ */
42
+
43
+ /** The language of the built-in wording: Japanese or English. */
44
+ type UiLanguage = "ja" | "en"
45
+
46
+ /** The locale used when `<html lang>` gives none (and on the server). */
47
+ const FALLBACK_LOCALE = "en-US"
48
+
49
+ /** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
50
+ function uiLanguage(locale: string | null | undefined): UiLanguage {
51
+ return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
52
+ }
53
+
54
+ /** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
55
+ function normalizeLocale(tag: string | null | undefined): string {
56
+ const value = tag?.trim()
57
+ if (!value) return FALLBACK_LOCALE
58
+ try {
59
+ return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
60
+ } catch {
61
+ return FALLBACK_LOCALE
62
+ }
63
+ }
64
+
65
+ /**
66
+ * The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
67
+ * invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
68
+ */
69
+ function documentLocale(): string {
70
+ if (typeof document === "undefined") return FALLBACK_LOCALE
71
+ return normalizeLocale(document.documentElement?.getAttribute("lang"))
72
+ }
73
+
74
+ /** `locale` when given, else the page's locale (`documentLocale()`). */
75
+ function resolveLocale(locale?: string | null): string {
76
+ return locale || documentLocale()
77
+ }
78
+
79
+ /** Picks the wording table of the locale's language. */
80
+ function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
81
+ return table[uiLanguage(resolveLocale(locale))]
82
+ }
83
+
84
+ /** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
85
+ function defaultCurrency(locale?: string | null): string {
86
+ return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
87
+ }
88
+
89
+ /** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
90
+ function defaultFiscalYearStartMonth(locale?: string | null): number {
91
+ return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
92
+ }
93
+
94
+ /** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
95
+ type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
96
+
97
+ /** Locales whose week starts on Sunday when the runtime has no week data. */
98
+ const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
99
+
100
+ /**
101
+ * The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
102
+ * (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
103
+ * Monday for the rest.
104
+ */
105
+ function weekStartsOn(locale?: string | null): WeekDay {
106
+ const tag = normalizeLocale(resolveLocale(locale))
107
+ if (uiLanguage(tag) === "ja") return 1
108
+ try {
109
+ const info = new Intl.Locale(tag) as Intl.Locale & {
110
+ getWeekInfo?: () => { firstDay: number }
111
+ weekInfo?: { firstDay: number }
112
+ }
113
+ const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
114
+ if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
115
+ } catch {
116
+ // Fall through to the table below.
117
+ }
118
+ return SUNDAY_FIRST.has(tag) ? 0 : 1
119
+ }
120
+
121
+ /* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
122
+
123
+ const listeners = new Set<() => void>()
124
+ let observer: MutationObserver | null = null
125
+
126
+ /** One observer on `<html lang>` for every subscribed part. */
127
+ function subscribe(onChange: () => void): () => void {
128
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
129
+ listeners.add(onChange)
130
+ if (!observer) {
131
+ observer = new MutationObserver(() => {
132
+ for (const listener of [...listeners]) listener()
133
+ })
134
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
135
+ }
136
+ return () => {
137
+ listeners.delete(onChange)
138
+ if (listeners.size === 0 && observer) {
139
+ observer.disconnect()
140
+ observer = null
141
+ }
142
+ }
143
+ }
144
+
145
+ const serverLocale = () => FALLBACK_LOCALE
146
+
147
+ /**
148
+ * The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
149
+ * hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
150
+ */
151
+ function useDocumentLocale(): string {
152
+ return useSyncExternalStore(subscribe, documentLocale, serverLocale)
153
+ }
154
+
155
+ /** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
156
+ function useLocale(locale?: string | null): string {
157
+ const page = useDocumentLocale()
158
+ return locale || page
159
+ }
160
+
161
+ /* ---------- end of inlined code ---------- */
162
+
163
+ const REFRESH_MS = 60_000
164
+
165
+ const TEXT = {
166
+ ja: {
167
+ justNow: "たった今",
168
+ relative: (relative: string) => `${relative}に更新`,
169
+ absoluteFirst: (shown: string, relative: string) => `${shown} 更新(${relative})`,
170
+ },
171
+ en: {
172
+ justNow: "just now",
173
+ relative: (relative: string) => `Updated ${relative}`,
174
+ absoluteFirst: (shown: string, relative: string) => `Updated ${shown} (${relative})`,
175
+ },
176
+ }
177
+
178
+ export interface UpdatedAtProps {
179
+ /** When the data was last updated. */
180
+ at: Date | string | number
181
+ /** `"relative"` (default): "23 分前に更新". `"absolute-first"`: "16:41 更新(23 分前)" — for pages where "now" matters. */
182
+ variant?: "relative" | "absolute-first"
183
+ /** IANA time zone (e.g. `"Asia/Tokyo"`) for the absolute time. Defaults to the runtime's zone. */
184
+ timeZone?: string
185
+ /** Text placed before the label, e.g. `"売上データ: "`. */
186
+ prefix?: string
187
+ /** Fixed "current time" for tests and fixtures. Disables the 60 s refresh. */
188
+ now?: Date | number
189
+ className?: string
190
+ }
191
+
192
+ const toMs = (value: Date | string | number) =>
193
+ value instanceof Date ? value.getTime() : new Date(value).getTime()
194
+
195
+ function relative(at: number, now: number, locale: string): string {
196
+ if (now - at < REFRESH_MS && now - at > -REFRESH_MS) return TEXT[uiLanguage(locale)].justNow
197
+ return formatRelativeTime(at, { now, locale })
198
+ }
199
+
200
+ /** "2026/10/20 16:41 JST" */
201
+ function absolute(at: number, locale: string, timeZone?: string): string | undefined {
202
+ if (!Number.isFinite(at)) return undefined
203
+ const zone = new Intl.DateTimeFormat(locale, { timeZone, timeZoneName: "short" })
204
+ .formatToParts(at)
205
+ .find((part) => part.type === "timeZoneName")?.value
206
+ const text = formatDate(at, "datetime", locale, { timeZone })
207
+ return zone ? `${text} ${zone}` : text
208
+ }
209
+
210
+ function label(at: number, now: number, variant: "relative" | "absolute-first", locale: string, timeZone?: string): string {
211
+ if (!Number.isFinite(at) || !Number.isFinite(now)) return EMPTY_VALUE
212
+ const t = TEXT[uiLanguage(locale)]
213
+ if (variant === "relative") {
214
+ return now - at < REFRESH_MS && now - at > -REFRESH_MS
215
+ ? uiLanguage(locale) === "ja"
216
+ ? t.justNow
217
+ : t.relative(t.justNow)
218
+ : t.relative(relative(at, now, locale))
219
+ }
220
+ const today = formatDate(at, "date", locale, { timeZone }) === formatDate(now, "date", locale, { timeZone })
221
+ const when = formatDate(at, "datetime", locale, { timeZone })
222
+ // "2026/10/20 16:41" -> time only when it is today (the time is always the last 5 characters: hourCycle h23).
223
+ const shown = today ? when.slice(-5) : when
224
+ return t.absoluteFirst(shown, relative(at, now, locale))
225
+ }
226
+
227
+ export const UpdatedAt = forwardRef<HTMLTimeElement, UpdatedAtProps>(
228
+ ({ at, variant = "relative", timeZone, prefix, now, className }, ref) => {
229
+ const locale = useLocale()
230
+ const atMs = toMs(at)
231
+ const [current, setCurrent] = useState<number | null>(null)
232
+ const fixed = now === undefined ? undefined : toMs(now as Date | number)
233
+
234
+ useEffect(() => {
235
+ if (fixed !== undefined) return
236
+ setCurrent(Date.now())
237
+ const id = setInterval(() => setCurrent(Date.now()), REFRESH_MS)
238
+ return () => clearInterval(id)
239
+ }, [fixed])
240
+
241
+ const clock = fixed ?? current
242
+ const ready = clock !== null
243
+ const dateTime = Number.isFinite(atMs) ? new Date(atMs).toISOString() : undefined
244
+ const full = ready ? absolute(atMs, locale, timeZone) : undefined
245
+ const classes = cn("text-sm text-muted-foreground tabular-nums", className)
246
+ const text = ready ? `${prefix ?? ""}${label(atMs, clock, variant, locale, timeZone)}` : null
247
+
248
+ if (!full) {
249
+ return (
250
+ <time ref={ref} data-slot="updated-at" dateTime={dateTime} className={classes} suppressHydrationWarning>
251
+ {text}
252
+ </time>
253
+ )
254
+ }
255
+ return (
256
+ <Tooltip>
257
+ <TooltipTrigger
258
+ render={
259
+ <time
260
+ ref={ref}
261
+ data-slot="updated-at"
262
+ dateTime={dateTime}
263
+ title={full}
264
+ className={classes}
265
+ suppressHydrationWarning
266
+ />
267
+ }
268
+ >
269
+ {text}
270
+ </TooltipTrigger>
271
+ <TooltipContent className="tabular-nums">{full}</TooltipContent>
272
+ </Tooltip>
273
+ )
274
+ },
275
+ )
276
+ UpdatedAt.displayName = "UpdatedAt"