@squadbase/vantage 0.6.1 → 0.6.2-dev1.0010f67

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-MXI3PZFT.js → chunk-QNOX7WLZ.js} +257 -210
  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-ROHNXP7J.js +123 -0
  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 -3
  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 +219 -2
  56. package/dist/doc/index.js +525 -11
  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 -9
  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 -87
  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 +26 -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/routing.md +4 -2
  125. package/docs/en/slide/slide-chart-full.md +48 -0
  126. package/docs/en/slide/slide-chart-insight.md +52 -0
  127. package/docs/en/slide/slide-columns.md +46 -0
  128. package/docs/en/slide/slide-comparison.md +68 -0
  129. package/docs/en/slide/slide-cover.md +39 -0
  130. package/docs/en/slide/slide-exec-summary.md +47 -0
  131. package/docs/en/slide/slide-heading.md +38 -0
  132. package/docs/en/slide/slide-kpi-grid.md +55 -0
  133. package/docs/en/slide/slide-kpi-hero.md +58 -0
  134. package/docs/en/slide/slide-next-actions.md +49 -0
  135. package/docs/en/slide/slide-scorecard-table.md +54 -0
  136. package/docs/en/slide/slide-section.md +44 -0
  137. package/docs/en/slide/slide-source-line.md +34 -0
  138. package/docs/en/ui/alert-dialog.md +42 -0
  139. package/docs/en/ui/avatar.md +31 -0
  140. package/docs/en/ui/combobox.md +74 -0
  141. package/docs/en/ui/drawer.md +41 -0
  142. package/docs/en/ui/empty.md +1 -1
  143. package/docs/en/ui/error-state.md +4 -3
  144. package/docs/en/ui/field.md +42 -0
  145. package/docs/en/ui/hover-card.md +21 -0
  146. package/docs/en/ui/kbd.md +17 -0
  147. package/docs/en/ui/loading.md +1 -1
  148. package/docs/en/ui/pagination.md +36 -0
  149. package/docs/en/ui/radio-group.md +21 -0
  150. package/docs/en/ui/toast.md +44 -0
  151. package/docs/en/ui/toggle-group.md +4 -3
  152. package/docs/en/ui-and-theming.md +1 -1
  153. package/docs/index.json +1184 -114
  154. package/docs/ja/agent-skills.md +1 -1
  155. package/docs/ja/changelog.md +57 -0
  156. package/docs/ja/cli-reference.md +29 -0
  157. package/docs/ja/components.md +68 -101
  158. package/docs/ja/doc/delta-text.md +40 -0
  159. package/docs/ja/doc/doc-action-items.md +49 -0
  160. package/docs/ja/doc/doc-callout.md +38 -0
  161. package/docs/ja/doc/doc-data-table.md +60 -0
  162. package/docs/ja/doc/doc-executive-summary.md +64 -0
  163. package/docs/ja/doc/doc-figure.md +56 -0
  164. package/docs/ja/doc/doc-key-findings.md +61 -0
  165. package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
  166. package/docs/ja/doc/doc-notes-and-sources.md +43 -0
  167. package/docs/ja/doc/doc-report-header.md +46 -0
  168. package/docs/ja/page-types/csv.md +83 -0
  169. package/docs/ja/page-types/doc.md +83 -0
  170. package/docs/ja/page-types/excel.md +82 -0
  171. package/docs/ja/page-types/slide.md +133 -0
  172. package/docs/ja/page-types.md +47 -0
  173. package/docs/ja/pages-and-metadata.md +15 -0
  174. package/docs/ja/parts/area-chart.md +85 -0
  175. package/docs/ja/parts/bar-chart.md +95 -0
  176. package/docs/ja/parts/bar-list.md +58 -0
  177. package/docs/ja/parts/category-bar.md +36 -0
  178. package/docs/ja/parts/chart-frame.md +36 -0
  179. package/docs/ja/parts/data-table.md +22 -0
  180. package/docs/ja/parts/delta.md +51 -0
  181. package/docs/ja/parts/donut-chart.md +66 -0
  182. package/docs/ja/parts/echart.md +3 -0
  183. package/docs/ja/parts/format.md +44 -0
  184. package/docs/ja/parts/funnel-steps.md +27 -8
  185. package/docs/ja/parts/heatmap.md +45 -0
  186. package/docs/ja/parts/kpi-card.md +56 -0
  187. package/docs/ja/parts/legend.md +36 -0
  188. package/docs/ja/parts/line-chart.md +84 -0
  189. package/docs/ja/parts/metric-value.md +3 -2
  190. package/docs/ja/parts/page-shell.md +1 -1
  191. package/docs/ja/parts/progress-circle.md +34 -0
  192. package/docs/ja/parts/sample-data.md +61 -0
  193. package/docs/ja/parts/scatter-chart.md +69 -0
  194. package/docs/ja/parts/sparkline.md +2 -2
  195. package/docs/ja/parts/tracker.md +32 -0
  196. package/docs/ja/parts/trend-indicator.md +17 -1
  197. package/docs/ja/parts/updated-at.md +27 -0
  198. package/docs/ja/parts/waterfall-chart.md +61 -0
  199. package/docs/ja/routing.md +8 -84
  200. package/docs/ja/slide/slide-chart-full.md +48 -0
  201. package/docs/ja/slide/slide-chart-insight.md +52 -0
  202. package/docs/ja/slide/slide-columns.md +46 -0
  203. package/docs/ja/slide/slide-comparison.md +68 -0
  204. package/docs/ja/slide/slide-cover.md +39 -0
  205. package/docs/ja/slide/slide-exec-summary.md +47 -0
  206. package/docs/ja/slide/slide-heading.md +38 -0
  207. package/docs/ja/slide/slide-kpi-grid.md +55 -0
  208. package/docs/ja/slide/slide-kpi-hero.md +58 -0
  209. package/docs/ja/slide/slide-next-actions.md +49 -0
  210. package/docs/ja/slide/slide-scorecard-table.md +54 -0
  211. package/docs/ja/slide/slide-section.md +44 -0
  212. package/docs/ja/slide/slide-source-line.md +34 -0
  213. package/docs/ja/ui/alert-dialog.md +41 -0
  214. package/docs/ja/ui/avatar.md +31 -0
  215. package/docs/ja/ui/combobox.md +74 -0
  216. package/docs/ja/ui/drawer.md +41 -0
  217. package/docs/ja/ui/empty.md +1 -1
  218. package/docs/ja/ui/error-state.md +4 -3
  219. package/docs/ja/ui/field.md +42 -0
  220. package/docs/ja/ui/hover-card.md +21 -0
  221. package/docs/ja/ui/kbd.md +16 -0
  222. package/docs/ja/ui/loading.md +1 -1
  223. package/docs/ja/ui/pagination.md +36 -0
  224. package/docs/ja/ui/radio-group.md +21 -0
  225. package/docs/ja/ui/toast.md +46 -0
  226. package/docs/ja/ui/toggle-group.md +4 -3
  227. package/docs/ja/ui-and-theming.md +14 -7
  228. package/package.json +43 -29
  229. package/registry/ui/accordion.tsx +76 -0
  230. package/registry/ui/alert-dialog.tsx +189 -0
  231. package/registry/ui/alert.tsx +80 -0
  232. package/registry/ui/app-shell.tsx +424 -0
  233. package/registry/ui/area-chart.tsx +3960 -0
  234. package/registry/ui/attention-list.tsx +465 -0
  235. package/registry/ui/avatar.tsx +110 -0
  236. package/registry/ui/badge.tsx +56 -0
  237. package/registry/ui/bar-chart.tsx +3954 -0
  238. package/registry/ui/bar-list.tsx +3998 -0
  239. package/registry/ui/box-plot-chart.tsx +4214 -0
  240. package/registry/ui/breadcrumb.tsx +128 -0
  241. package/registry/ui/button.tsx +62 -0
  242. package/registry/ui/calendar.tsx +223 -0
  243. package/registry/ui/card.tsx +107 -0
  244. package/registry/ui/category-bar.tsx +1498 -0
  245. package/registry/ui/chart-frame.tsx +1604 -0
  246. package/registry/ui/checkbox.tsx +30 -0
  247. package/registry/ui/collapsible.tsx +23 -0
  248. package/registry/ui/combobox.tsx +310 -0
  249. package/registry/ui/command.tsx +198 -0
  250. package/registry/ui/dashboard-card.tsx +217 -0
  251. package/registry/ui/data-table.tsx +896 -157
  252. package/registry/ui/date-range-picker.tsx +544 -0
  253. package/registry/ui/delta.tsx +350 -0
  254. package/registry/ui/dialog.tsx +161 -0
  255. package/registry/ui/donut-chart.tsx +4006 -0
  256. package/registry/ui/drawer.tsx +229 -0
  257. package/registry/ui/dropdown-menu.tsx +274 -0
  258. package/registry/ui/echart.tsx +1178 -0
  259. package/registry/ui/field.tsx +240 -0
  260. package/registry/ui/filter-bar.tsx +551 -0
  261. package/registry/ui/funnel-steps.tsx +3843 -0
  262. package/registry/ui/heatmap.tsx +2027 -0
  263. package/registry/ui/histogram-chart.tsx +4284 -0
  264. package/registry/ui/hover-card.tsx +52 -0
  265. package/registry/ui/input-group.tsx +160 -0
  266. package/registry/ui/input.tsx +24 -0
  267. package/registry/ui/kbd.tsx +30 -0
  268. package/registry/ui/kpi-card.tsx +905 -0
  269. package/registry/ui/label.tsx +22 -0
  270. package/registry/ui/legend.tsx +3817 -0
  271. package/registry/ui/line-chart.tsx +3958 -0
  272. package/registry/ui/metric-value.tsx +62 -0
  273. package/registry/ui/multi-select.tsx +382 -0
  274. package/registry/ui/page-shell.tsx +420 -0
  275. package/registry/ui/pagination.tsx +140 -0
  276. package/registry/ui/paired-chart.tsx +4086 -0
  277. package/registry/ui/placeholder.tsx +36 -0
  278. package/registry/ui/popover.tsx +92 -0
  279. package/registry/ui/progress-circle.tsx +1033 -0
  280. package/registry/ui/progress.tsx +85 -0
  281. package/registry/ui/radio-group.tsx +39 -0
  282. package/registry/ui/sample-data.tsx +230 -0
  283. package/registry/ui/scatter-chart.tsx +4503 -0
  284. package/registry/ui/scroll-area.tsx +56 -0
  285. package/registry/ui/searchable-select.tsx +352 -0
  286. package/registry/ui/section-header.tsx +43 -0
  287. package/registry/ui/segmented-control.tsx +76 -0
  288. package/registry/ui/select.tsx +255 -0
  289. package/registry/ui/separator.tsx +27 -0
  290. package/registry/ui/sheet.tsx +139 -0
  291. package/registry/ui/sidebar.tsx +725 -0
  292. package/registry/ui/skeleton.tsx +17 -0
  293. package/registry/ui/slider.tsx +56 -0
  294. package/registry/ui/sparkline.tsx +230 -0
  295. package/registry/ui/spinner.tsx +14 -0
  296. package/registry/ui/states.tsx +247 -0
  297. package/registry/ui/status-badge.tsx +286 -0
  298. package/registry/ui/switch.tsx +34 -0
  299. package/registry/ui/table.tsx +118 -0
  300. package/registry/ui/tabs.tsx +84 -0
  301. package/registry/ui/textarea.tsx +22 -0
  302. package/registry/ui/toast.tsx +250 -0
  303. package/registry/ui/toggle-group.tsx +91 -0
  304. package/registry/ui/toggle.tsx +47 -0
  305. package/registry/ui/tooltip.tsx +72 -0
  306. package/registry/ui/tracker.tsx +1015 -0
  307. package/registry/ui/trend-indicator.tsx +217 -0
  308. package/registry/ui/updated-at.tsx +276 -0
  309. package/registry/ui/waterfall-chart.tsx +4561 -0
  310. package/skills/vantage-add-feature/SKILL.md +9 -7
  311. package/skills/vantage-design/SKILL.md +62 -52
  312. package/skills/vantage-design/references/extract.md +26 -27
  313. package/skills/vantage-design/references/format.md +12 -172
  314. package/skills/vantage-design/references/presets.md +50 -110
  315. package/skills/vantage-pitfalls/SKILL.md +10 -1
  316. package/skills/vantage-slide/SKILL.md +71 -36
  317. package/templates/AGENTS.md +53 -16
  318. package/templates/agents/api.md +29 -0
  319. package/templates/agents/csv.md +2 -1
  320. package/templates/agents/doc.md +54 -3
  321. package/templates/agents/page.md +55 -10
  322. package/templates/agents/slide.md +90 -4
  323. package/templates/agents/xlsx.md +2 -1
  324. package/theme.css +287 -128
  325. package/dist/add-EISGSZAH.js +0 -6
  326. package/dist/add-EISGSZAH.js.map +0 -1
  327. package/dist/chunk-3G43C6OL.js.map +0 -1
  328. package/dist/chunk-5ZOP4SQR.js +0 -47
  329. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  330. package/dist/chunk-A2UUGASH.js.map +0 -1
  331. package/dist/chunk-BCE22JSM.js.map +0 -1
  332. package/dist/chunk-DTDVSFRY.js +0 -29
  333. package/dist/chunk-DTDVSFRY.js.map +0 -1
  334. package/dist/chunk-EP6JHXSR.js.map +0 -1
  335. package/dist/chunk-JGRMRXXZ.js.map +0 -1
  336. package/dist/chunk-KLEIVDUV.js +0 -165
  337. package/dist/chunk-KLEIVDUV.js.map +0 -1
  338. package/dist/chunk-MXI3PZFT.js.map +0 -1
  339. package/dist/chunk-PLST5Q7T.js +0 -2221
  340. package/dist/chunk-PLST5Q7T.js.map +0 -1
  341. package/dist/chunk-PVTHHV7X.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,465 @@
1
+ // Copied by `vantage add ui attention-list`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/components/attention-list.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ /**
6
+ * AttentionList — 期日超過・期限間近・リスク・滞留に当たる行を上に寄せ、理由と次の一手を添えて並べる要対応一覧。
7
+ * 判定は `judgeAttention`(純関数)が行い、部品は並べ替えと描画だけをする。区分の文言としきい値
8
+ * (`dueSoonDays` / `staleDays`)は props で渡す。業務の意味(請求・商談・契約など)は呼び元が決める。
9
+ *
10
+ * - 区分は 1 行に 1 つ。複数に当たるときは 期日超過 > リスク > 期限間近 > 滞留 の順で強いほうを採る。
11
+ * - 並びは区分の強さ、同じ区分では日数の大きい(遅れている・止まっている)行が先。日数が同じなら元の順。
12
+ * - 区分の色は StatusBadge の意味色(negative / warning / info)。色だけでなく区分名と日数の文で伝える。
13
+ * - 判定に当たらない行は既定で出さない(`includeUnflagged` で末尾に出す)。当たる行がなければ Empty を出す。
14
+ * - 行の項目は関数(`getDueDate` など)か列名(`dueDateKey` など)で渡す。列名は JSON で書けるので、下書きはこちらを使う。
15
+ * 両方あれば関数が先。どちらも無ければ、期日・動き・リスクは「無い」として判定せず、行の ID は行の順番、見出しは空になる。
16
+ * - 行を押すと `onRowClick(row)` を呼ぶ。渡さなければ押せない行(button ではなく li)になる。
17
+ *
18
+ * @example
19
+ * import { AttentionList } from "@/components/attention-list"
20
+ * // Vantage: import { AttentionList } from "@squadbase/vantage/components"
21
+ *
22
+ * <AttentionList
23
+ * rows={receivables}
24
+ * asOf="2026-10-23"
25
+ * dueSoonDays={7}
26
+ * getRowId={(r) => r.id}
27
+ * getTitle={(r) => r.customer}
28
+ * getDueDate={(r) => r.dueDate}
29
+ * getNextAction={(r) => r.nextAction}
30
+ * onRowClick={(r) => openDetail(r.id)}
31
+ * />
32
+ */
33
+ import { differenceInCalendarDays, parseISO } from "date-fns"
34
+ import { useMemo, type HTMLAttributes, type ReactNode } from "react"
35
+
36
+ import { formatDate } from "@squadbase/vantage/components"
37
+ import { cn } from "@squadbase/vantage/ui"
38
+ import { Empty } from "@squadbase/vantage/ui"
39
+ import { StatusBadge } from "@squadbase/vantage/components"
40
+ import { useSyncExternalStore } from "react"
41
+
42
+ /* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
43
+
44
+ /**
45
+ * The display language of the parts and the defaults that follow it.
46
+ *
47
+ * The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
48
+ * Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
49
+ * (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
50
+ *
51
+ * Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
52
+ * and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
53
+ */
54
+
55
+ /** The language of the built-in wording: Japanese or English. */
56
+ type UiLanguage = "ja" | "en"
57
+
58
+ /** The locale used when `<html lang>` gives none (and on the server). */
59
+ const FALLBACK_LOCALE = "en-US"
60
+
61
+ /** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
62
+ function uiLanguage(locale: string | null | undefined): UiLanguage {
63
+ return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
64
+ }
65
+
66
+ /** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
67
+ function normalizeLocale(tag: string | null | undefined): string {
68
+ const value = tag?.trim()
69
+ if (!value) return FALLBACK_LOCALE
70
+ try {
71
+ return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
72
+ } catch {
73
+ return FALLBACK_LOCALE
74
+ }
75
+ }
76
+
77
+ /**
78
+ * The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
79
+ * invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
80
+ */
81
+ function documentLocale(): string {
82
+ if (typeof document === "undefined") return FALLBACK_LOCALE
83
+ return normalizeLocale(document.documentElement?.getAttribute("lang"))
84
+ }
85
+
86
+ /** `locale` when given, else the page's locale (`documentLocale()`). */
87
+ function resolveLocale(locale?: string | null): string {
88
+ return locale || documentLocale()
89
+ }
90
+
91
+ /** Picks the wording table of the locale's language. */
92
+ function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
93
+ return table[uiLanguage(resolveLocale(locale))]
94
+ }
95
+
96
+ /** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
97
+ function defaultCurrency(locale?: string | null): string {
98
+ return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
99
+ }
100
+
101
+ /** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
102
+ function defaultFiscalYearStartMonth(locale?: string | null): number {
103
+ return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
104
+ }
105
+
106
+ /** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
107
+ type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
108
+
109
+ /** Locales whose week starts on Sunday when the runtime has no week data. */
110
+ const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
111
+
112
+ /**
113
+ * The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
114
+ * (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
115
+ * Monday for the rest.
116
+ */
117
+ function weekStartsOn(locale?: string | null): WeekDay {
118
+ const tag = normalizeLocale(resolveLocale(locale))
119
+ if (uiLanguage(tag) === "ja") return 1
120
+ try {
121
+ const info = new Intl.Locale(tag) as Intl.Locale & {
122
+ getWeekInfo?: () => { firstDay: number }
123
+ weekInfo?: { firstDay: number }
124
+ }
125
+ const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
126
+ if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
127
+ } catch {
128
+ // Fall through to the table below.
129
+ }
130
+ return SUNDAY_FIRST.has(tag) ? 0 : 1
131
+ }
132
+
133
+ /* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
134
+
135
+ const listeners = new Set<() => void>()
136
+ let observer: MutationObserver | null = null
137
+
138
+ /** One observer on `<html lang>` for every subscribed part. */
139
+ function subscribe(onChange: () => void): () => void {
140
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
141
+ listeners.add(onChange)
142
+ if (!observer) {
143
+ observer = new MutationObserver(() => {
144
+ for (const listener of [...listeners]) listener()
145
+ })
146
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
147
+ }
148
+ return () => {
149
+ listeners.delete(onChange)
150
+ if (listeners.size === 0 && observer) {
151
+ observer.disconnect()
152
+ observer = null
153
+ }
154
+ }
155
+ }
156
+
157
+ const serverLocale = () => FALLBACK_LOCALE
158
+
159
+ /**
160
+ * The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
161
+ * hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
162
+ */
163
+ function useDocumentLocale(): string {
164
+ return useSyncExternalStore(subscribe, documentLocale, serverLocale)
165
+ }
166
+
167
+ /** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
168
+ function useLocale(locale?: string | null): string {
169
+ const page = useDocumentLocale()
170
+ return locale || page
171
+ }
172
+
173
+ /* ---------- end of inlined code ---------- */
174
+
175
+ export type AttentionKind = "overdue" | "risk" | "dueSoon" | "stale"
176
+
177
+ /** 強い順。並びと、複数に当たったときの採用に使う。 */
178
+ const KIND_ORDER: readonly AttentionKind[] = ["overdue", "risk", "dueSoon", "stale"]
179
+
180
+ const KIND_TONES: Record<AttentionKind, string> = {
181
+ overdue: "negative",
182
+ risk: "negative",
183
+ dueSoon: "warning",
184
+ stale: "info",
185
+ }
186
+
187
+ const daysEn = (n: number) => (n === 1 ? "1 day" : `${n} days`)
188
+
189
+ const TEXT = {
190
+ ja: {
191
+ labels: { overdue: "期日超過", risk: "リスク", dueSoon: "期限間近", stale: "滞留" } as Record<AttentionKind, string>,
192
+ overdue: (days: number) => `期日を ${days} 日過ぎています`,
193
+ dueToday: "期日は今日です",
194
+ dueIn: (days: number) => `期日まであと ${days} 日です`,
195
+ stale: (days: number) => `${days} 日間動きがありません`,
196
+ empty: "対応が必要な項目はありません",
197
+ due: "期日",
198
+ nextAction: "次の一手: ",
199
+ },
200
+ en: {
201
+ labels: { overdue: "Overdue", risk: "At risk", dueSoon: "Due soon", stale: "Stalled" } as Record<AttentionKind, string>,
202
+ overdue: (days: number) => `${daysEn(days)} overdue`,
203
+ dueToday: "Due today",
204
+ dueIn: (days: number) => `Due in ${daysEn(days)}`,
205
+ stale: (days: number) => `No activity for ${daysEn(days)}`,
206
+ empty: "Nothing needs attention",
207
+ due: "Due",
208
+ nextAction: "Next step: ",
209
+ },
210
+ } satisfies Record<UiLanguage, unknown>
211
+
212
+ /** The category names in English (the fallback language). The list picks the page's language (`<html lang>`); ja reads 期日超過 / リスク / 期限間近 / 滞留. */
213
+ export const DEFAULT_ATTENTION_LABELS: Record<AttentionKind, string> = TEXT.en.labels
214
+
215
+ /** The category names in `locale`'s language (default the page's, `<html lang>`). */
216
+ export function attentionLabels(locale?: string): Record<AttentionKind, string> {
217
+ return TEXT[uiLanguage(resolveLocale(locale))].labels
218
+ }
219
+
220
+ type DateInput = Date | string | null | undefined
221
+
222
+ export interface AttentionJudgement {
223
+ kind: AttentionKind
224
+ /**
225
+ * overdue: 期日を過ぎた日数(1 以上)/ dueSoon: 期日までの日数(0 = 当日)/
226
+ * stale: 最終の動きからの日数/ risk: 0。
227
+ */
228
+ days: number
229
+ }
230
+
231
+ export interface JudgeAttentionInput {
232
+ /** 期日。無ければ期日の判定(超過・間近)はしない。 */
233
+ dueDate?: DateInput
234
+ /** 最後に動きがあった日。無ければ滞留の判定はしない。 */
235
+ lastActivityAt?: DateInput
236
+ /** 呼び元がリスクと判定した行。 */
237
+ risk?: boolean
238
+ /** 基準日。必ず渡す(部品の内で「今日」を決めない)。 */
239
+ asOf: Date | string
240
+ /** 期日の何日前から「期限間近」にするか。当日を含み、この日数ちょうども含む。既定 7。 */
241
+ dueSoonDays?: number
242
+ /** 何日動きがなければ「滞留」にするか。この日数ちょうどから滞留。未指定なら滞留は判定しない。 */
243
+ staleDays?: number
244
+ }
245
+
246
+ function toDate(value: DateInput): Date | null {
247
+ if (value === null || value === undefined || value === "") return null
248
+ const date = typeof value === "string" ? parseISO(value) : value
249
+ return Number.isFinite(date.getTime()) ? date : null
250
+ }
251
+
252
+ /**
253
+ * 1 行が要対応かを判定する。当たらなければ `null`。日数は暦日(時刻は無視)で数える。
254
+ * 期日の当日は「超過」ではなく「期限間近(0 日)」。
255
+ */
256
+ export function judgeAttention(input: JudgeAttentionInput): AttentionJudgement | null {
257
+ const asOf = toDate(input.asOf)
258
+ if (!asOf) return null
259
+ const dueSoonDays = input.dueSoonDays ?? 7
260
+
261
+ const due = toDate(input.dueDate)
262
+ if (due) {
263
+ const untilDue = differenceInCalendarDays(due, asOf)
264
+ if (untilDue < 0) return { kind: "overdue", days: -untilDue }
265
+ }
266
+ if (input.risk) return { kind: "risk", days: 0 }
267
+ if (due) {
268
+ const untilDue = differenceInCalendarDays(due, asOf)
269
+ if (untilDue <= dueSoonDays) return { kind: "dueSoon", days: untilDue }
270
+ }
271
+ const last = toDate(input.lastActivityAt)
272
+ if (last && input.staleDays !== undefined) {
273
+ const idle = differenceInCalendarDays(asOf, last)
274
+ if (idle >= input.staleDays) return { kind: "stale", days: idle }
275
+ }
276
+ return null
277
+ }
278
+
279
+ /** 区分の強さ → 日数の大きい順(dueSoon は期日が近い順)。同順位は 0 を返し、元の順を保つ。 */
280
+ export function compareAttention(a: AttentionJudgement | null, b: AttentionJudgement | null): number {
281
+ if (!a || !b) return a ? -1 : b ? 1 : 0
282
+ const byKind = KIND_ORDER.indexOf(a.kind) - KIND_ORDER.indexOf(b.kind)
283
+ if (byKind !== 0) return byKind
284
+ return a.kind === "dueSoon" ? a.days - b.days : b.days - a.days
285
+ }
286
+
287
+ function defaultReason(j: AttentionJudgement, labels: Record<AttentionKind, string>, t: (typeof TEXT)[UiLanguage]): string {
288
+ switch (j.kind) {
289
+ case "overdue":
290
+ return t.overdue(j.days)
291
+ case "dueSoon":
292
+ return j.days === 0 ? t.dueToday : t.dueIn(j.days)
293
+ case "stale":
294
+ return t.stale(j.days)
295
+ case "risk":
296
+ return labels.risk
297
+ }
298
+ }
299
+
300
+ export interface AttentionListProps<T> {
301
+ rows: T[]
302
+ /** 基準日(`"2026-10-23"` か Date)。 */
303
+ asOf: Date | string
304
+ /** 期日の何日前から「期限間近」にするか。既定 7。 */
305
+ dueSoonDays?: number
306
+ /** この日数動きがなければ「滞留」。未指定なら滞留は判定しない。 */
307
+ staleDays?: number
308
+ /** 区分名の差し替え(例: `{ overdue: "入金遅れ" }`)。 */
309
+ labels?: Partial<Record<AttentionKind, string>>
310
+ /** 行の ID。省略時は `idKey` の列、それも無ければ行の順番。 */
311
+ getRowId?: (row: T) => string
312
+ /** 行の見出し(顧客名・案件名など)。省略時は `titleKey` の列、それも無ければ空。 */
313
+ getTitle?: (row: T) => ReactNode
314
+ getDueDate?: (row: T) => DateInput
315
+ getLastActivityAt?: (row: T) => DateInput
316
+ /** リスクと判定する行。期日・滞留より先に出す。 */
317
+ isRisk?: (row: T) => boolean
318
+ /** 行の ID の列名(JSON で書ける `getRowId`)。 */
319
+ idKey?: string
320
+ /** 見出しの列名(JSON で書ける `getTitle`)。 */
321
+ titleKey?: string
322
+ /** 期日の列名(JSON で書ける `getDueDate`)。値は `"2026-10-23"` 形式の日付か Date。 */
323
+ dueDateKey?: string
324
+ /** 最後に動きがあった日の列名(JSON で書ける `getLastActivityAt`)。 */
325
+ lastActivityAtKey?: string
326
+ /** リスクの列名(JSON で書ける `isRisk`)。値が真の行をリストにする。 */
327
+ riskKey?: string
328
+ /** 次の一手の列名(JSON で書ける `getNextAction`)。値が空の行には添えない。 */
329
+ nextActionKey?: string
330
+ /** 理由の文。省略すると区分と日数から作る。 */
331
+ getReason?: (row: T, judgement: AttentionJudgement) => ReactNode
332
+ /** 次の一手。判定に当たる行に添える。 */
333
+ getNextAction?: (row: T, judgement: AttentionJudgement) => ReactNode
334
+ /** 見出しの右に出す補足(金額・担当者など)。 */
335
+ getMeta?: (row: T) => ReactNode
336
+ /** 行を押したとき。渡すと行が button になる。 */
337
+ onRowClick?: (row: T) => void
338
+ /** 判定に当たらない行も末尾に出す。既定 false。 */
339
+ includeUnflagged?: boolean
340
+ /** 該当なしのときの見出し・説明。 */
341
+ emptyTitle?: string
342
+ emptyDescription?: string
343
+ className?: string
344
+ }
345
+
346
+ function cell(row: unknown, key: string | undefined): unknown {
347
+ if (!key || row === null || typeof row !== "object") return undefined
348
+ return (row as Record<string, unknown>)[key]
349
+ }
350
+
351
+ function asDateInput(value: unknown): DateInput {
352
+ return typeof value === "string" || value instanceof Date ? value : undefined
353
+ }
354
+
355
+ function asNode(value: unknown): ReactNode {
356
+ return typeof value === "string" || typeof value === "number" ? value : null
357
+ }
358
+
359
+ export function AttentionList<T>({
360
+ rows,
361
+ asOf,
362
+ dueSoonDays,
363
+ staleDays,
364
+ labels,
365
+ getRowId,
366
+ getTitle,
367
+ getDueDate,
368
+ getLastActivityAt,
369
+ isRisk,
370
+ idKey,
371
+ titleKey,
372
+ dueDateKey,
373
+ lastActivityAtKey,
374
+ riskKey,
375
+ nextActionKey,
376
+ getReason,
377
+ getNextAction,
378
+ getMeta,
379
+ onRowClick,
380
+ includeUnflagged = false,
381
+ emptyTitle,
382
+ emptyDescription,
383
+ className,
384
+ ...rest
385
+ }: AttentionListProps<T> & Omit<HTMLAttributes<HTMLUListElement>, keyof AttentionListProps<T>>) {
386
+ const locale = useLocale()
387
+ const t = TEXT[uiLanguage(locale)]
388
+ const mergedLabels = useMemo(() => ({ ...t.labels, ...labels }), [t, labels])
389
+ const colorMap = KIND_TONES
390
+ const dueOf = (row: T) => (getDueDate ? getDueDate(row) : asDateInput(cell(row, dueDateKey)))
391
+ const nextActionOf = (row: T, j: AttentionJudgement): ReactNode =>
392
+ getNextAction ? getNextAction(row, j) : asNode(cell(row, nextActionKey))
393
+
394
+ // アクセサは呼び元の判定そのものなので、rows が同じ参照でも毎回かけ直す(メモ化すると古い判定が残る)
395
+ const items = (rows ?? [])
396
+ .map((row, index) => ({
397
+ row,
398
+ index,
399
+ judgement: judgeAttention({
400
+ dueDate: dueOf(row),
401
+ lastActivityAt: getLastActivityAt ? getLastActivityAt(row) : asDateInput(cell(row, lastActivityAtKey)),
402
+ risk: isRisk ? isRisk(row) : Boolean(cell(row, riskKey)),
403
+ asOf,
404
+ dueSoonDays,
405
+ staleDays,
406
+ }),
407
+ }))
408
+ .filter((item) => includeUnflagged || item.judgement)
409
+ .sort((a, b) => compareAttention(a.judgement, b.judgement) || a.index - b.index)
410
+
411
+ if (items.length === 0) {
412
+ return <Empty title={emptyTitle ?? t.empty} description={emptyDescription} className={className} />
413
+ }
414
+
415
+ return (
416
+ <ul data-slot="attention-list" className={cn("divide-y divide-border", className)} {...rest}>
417
+ {items.map(({ row, index, judgement }) => {
418
+ const due = dueOf(row)
419
+ const body = (
420
+ <>
421
+ <div className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1">
422
+ {judgement && (
423
+ <StatusBadge status={judgement.kind} label={mergedLabels[judgement.kind]} colorMap={colorMap} />
424
+ )}
425
+ <span className="min-w-0 font-medium">{getTitle ? getTitle(row) : asNode(cell(row, titleKey))}</span>
426
+ {getMeta && <span className="text-sm tabular-nums text-muted-foreground">{getMeta(row)}</span>}
427
+ {due ? (
428
+ <span className="ml-auto text-sm tabular-nums text-muted-foreground">
429
+ {t.due} {formatDate(due, "date", locale)}
430
+ </span>
431
+ ) : null}
432
+ </div>
433
+ {judgement && (
434
+ <p className="mt-1 text-sm text-muted-foreground">
435
+ {getReason ? getReason(row, judgement) : defaultReason(judgement, mergedLabels, t)}
436
+ </p>
437
+ )}
438
+ {judgement && (getNextAction || nextActionKey) && nextActionOf(row, judgement) ? (
439
+ <p className="mt-1 text-sm">
440
+ <span className="text-muted-foreground">{t.nextAction}</span>
441
+ {nextActionOf(row, judgement)}
442
+ </p>
443
+ ) : null}
444
+ </>
445
+ )
446
+ return (
447
+ <li key={getRowId ? getRowId(row) : String(cell(row, idKey) ?? index)} data-slot="attention-list-row">
448
+ {onRowClick ? (
449
+ <button
450
+ type="button"
451
+ onClick={() => onRowClick(row)}
452
+ className="block w-full px-3 py-3 text-left transition-colors hover:bg-muted/50 focus-visible:bg-muted/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
453
+ >
454
+ {body}
455
+ </button>
456
+ ) : (
457
+ <div className="px-3 py-3">{body}</div>
458
+ )}
459
+ </li>
460
+ )
461
+ })}
462
+ </ul>
463
+ )
464
+ }
465
+ AttentionList.displayName = "AttentionList"
@@ -0,0 +1,110 @@
1
+ // Copied by `vantage add ui avatar`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/ui/avatar.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ import * as React from "react"
6
+ import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
7
+ import { cn } from "@squadbase/vantage/ui"
8
+
9
+ function Avatar({
10
+ className,
11
+ size = "default",
12
+ ...props
13
+ }: AvatarPrimitive.Root.Props & {
14
+ size?: "default" | "sm" | "lg"
15
+ }) {
16
+ return (
17
+ <AvatarPrimitive.Root
18
+ data-slot="avatar"
19
+ data-size={size}
20
+ className={cn(
21
+ "group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten",
22
+ className
23
+ )}
24
+ {...props}
25
+ />
26
+ )
27
+ }
28
+
29
+ function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
30
+ return (
31
+ <AvatarPrimitive.Image
32
+ data-slot="avatar-image"
33
+ className={cn(
34
+ "aspect-square size-full rounded-full object-cover",
35
+ className
36
+ )}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+
42
+ function AvatarFallback({
43
+ className,
44
+ ...props
45
+ }: AvatarPrimitive.Fallback.Props) {
46
+ return (
47
+ <AvatarPrimitive.Fallback
48
+ data-slot="avatar-fallback"
49
+ className={cn(
50
+ "flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
51
+ className
52
+ )}
53
+ {...props}
54
+ />
55
+ )
56
+ }
57
+
58
+ function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
59
+ return (
60
+ <span
61
+ data-slot="avatar-badge"
62
+ className={cn(
63
+ "absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none",
64
+ "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
65
+ "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
66
+ "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
67
+ className
68
+ )}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
75
+ return (
76
+ <div
77
+ data-slot="avatar-group"
78
+ className={cn(
79
+ "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
80
+ className
81
+ )}
82
+ {...props}
83
+ />
84
+ )
85
+ }
86
+
87
+ function AvatarGroupCount({
88
+ className,
89
+ ...props
90
+ }: React.ComponentProps<"div">) {
91
+ return (
92
+ <div
93
+ data-slot="avatar-group-count"
94
+ className={cn(
95
+ "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
96
+ className
97
+ )}
98
+ {...props}
99
+ />
100
+ )
101
+ }
102
+
103
+ export {
104
+ Avatar,
105
+ AvatarImage,
106
+ AvatarFallback,
107
+ AvatarGroup,
108
+ AvatarGroupCount,
109
+ AvatarBadge,
110
+ }
@@ -0,0 +1,56 @@
1
+ // Copied by `vantage add ui badge`. This file is yours to edit.
2
+ // Generated from @squadbase/squadkit registry/ui/badge.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
3
+ "use client"
4
+
5
+ import { mergeProps } from "@base-ui/react/merge-props"
6
+ import { useRender } from "@base-ui/react/use-render"
7
+ import { cva, type VariantProps } from "class-variance-authority"
8
+
9
+ import { cn } from "@squadbase/vantage/ui"
10
+
11
+ const badgeVariants = cva(
12
+ "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
13
+ {
14
+ variants: {
15
+ variant: {
16
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
19
+ destructive:
20
+ "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
21
+ outline:
22
+ "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
23
+ ghost:
24
+ "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
25
+ link: "text-primary underline-offset-4 hover:underline",
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ variant: "default",
30
+ },
31
+ }
32
+ )
33
+
34
+ function Badge({
35
+ className,
36
+ variant = "default",
37
+ render,
38
+ ...props
39
+ }: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
40
+ return useRender({
41
+ defaultTagName: "span",
42
+ props: mergeProps<"span">(
43
+ {
44
+ className: cn(badgeVariants({ variant }), className),
45
+ },
46
+ props
47
+ ),
48
+ render,
49
+ state: {
50
+ slot: "badge",
51
+ variant,
52
+ },
53
+ })
54
+ }
55
+
56
+ export { Badge, badgeVariants }