@eifi1/ui-kit 0.11.0 → 0.13.0

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 (397) hide show
  1. package/README.md +59 -34
  2. package/dist/chart.d.ts +3 -1
  3. package/dist/chart.js +2 -0
  4. package/dist/chart.js.map +1 -1
  5. package/dist/components/account-settings-labels.d.ts +105 -0
  6. package/dist/components/account-settings-labels.js +81 -0
  7. package/dist/components/account-settings-labels.js.map +1 -0
  8. package/dist/components/account-settings.d.ts +36 -52
  9. package/dist/components/account-settings.js +44 -8
  10. package/dist/components/account-settings.js.map +1 -1
  11. package/dist/components/amount-input.d.ts +40 -4
  12. package/dist/components/amount-input.js +50 -12
  13. package/dist/components/amount-input.js.map +1 -1
  14. package/dist/components/authed-image.d.ts +68 -0
  15. package/dist/components/authed-image.js +117 -0
  16. package/dist/components/authed-image.js.map +1 -0
  17. package/dist/components/breadcrumbs.d.ts +2 -1
  18. package/dist/components/breadcrumbs.js +5 -2
  19. package/dist/components/breadcrumbs.js.map +1 -1
  20. package/dist/components/bulk-action-bar.d.ts +10 -2
  21. package/dist/components/bulk-action-bar.js.map +1 -1
  22. package/dist/components/button-group.d.ts +51 -2
  23. package/dist/components/button-group.js +5 -1
  24. package/dist/components/button-group.js.map +1 -1
  25. package/dist/components/calculator.d.ts +15 -4
  26. package/dist/components/calendar-heatmap.d.ts +41 -3
  27. package/dist/components/calendar-heatmap.js +48 -7
  28. package/dist/components/calendar-heatmap.js.map +1 -1
  29. package/dist/components/chart.js +14 -8
  30. package/dist/components/chart.js.map +1 -1
  31. package/dist/components/chip.d.ts +2 -1
  32. package/dist/components/chip.js +26 -18
  33. package/dist/components/chip.js.map +1 -1
  34. package/dist/components/choice-card.d.ts +35 -3
  35. package/dist/components/choice-card.js +83 -25
  36. package/dist/components/choice-card.js.map +1 -1
  37. package/dist/components/combobox-core.d.ts +3 -1
  38. package/dist/components/combobox-core.js +18 -5
  39. package/dist/components/combobox-core.js.map +1 -1
  40. package/dist/components/combobox.d.ts +2 -2
  41. package/dist/components/combobox.js +31 -9
  42. package/dist/components/combobox.js.map +1 -1
  43. package/dist/components/copy-button.d.ts +51 -70
  44. package/dist/components/copy-button.js +1 -1
  45. package/dist/components/copy-button.js.map +1 -1
  46. package/dist/components/data-table-cells.d.ts +63 -0
  47. package/dist/components/data-table-cells.js +64 -0
  48. package/dist/components/data-table-cells.js.map +1 -0
  49. package/dist/components/data-table-filter-popover.d.ts +1 -1
  50. package/dist/components/data-table-filter-popover.js +8 -1
  51. package/dist/components/data-table-filter-popover.js.map +1 -1
  52. package/dist/components/data-table-filters.d.ts +1 -1
  53. package/dist/components/data-table-filters.js +31 -1
  54. package/dist/components/data-table-filters.js.map +1 -1
  55. package/dist/components/data-table-labels.d.ts +13 -0
  56. package/dist/components/data-table-labels.js +8 -1
  57. package/dist/components/data-table-labels.js.map +1 -1
  58. package/dist/components/data-table.d.ts +1 -1
  59. package/dist/components/data-table.js +125 -27
  60. package/dist/components/data-table.js.map +1 -1
  61. package/dist/components/date-picker.d.ts +3 -1
  62. package/dist/components/date-picker.js +15 -2
  63. package/dist/components/date-picker.js.map +1 -1
  64. package/dist/components/description-list.d.ts +23 -3
  65. package/dist/components/description-list.js +23 -3
  66. package/dist/components/description-list.js.map +1 -1
  67. package/dist/components/dialog-frame.d.ts +1 -0
  68. package/dist/components/entity-combobox.d.ts +1 -1
  69. package/dist/components/entity-combobox.js +40 -20
  70. package/dist/components/entity-combobox.js.map +1 -1
  71. package/dist/components/error-boundary.d.ts +281 -0
  72. package/dist/components/error-boundary.js +302 -0
  73. package/dist/components/error-boundary.js.map +1 -0
  74. package/dist/components/field-sync.js +90 -83
  75. package/dist/components/field-sync.js.map +1 -1
  76. package/dist/components/field.d.ts +30 -4
  77. package/dist/components/field.js +40 -17
  78. package/dist/components/field.js.map +1 -1
  79. package/dist/components/file-button.d.ts +50 -208
  80. package/dist/components/file-dropzone.d.ts +49 -2
  81. package/dist/components/floating-panel.d.ts +13 -4
  82. package/dist/components/floating-panel.js +7 -3
  83. package/dist/components/floating-panel.js.map +1 -1
  84. package/dist/components/form-actions.d.ts +53 -0
  85. package/dist/components/form-actions.js +98 -0
  86. package/dist/components/form-actions.js.map +1 -0
  87. package/dist/components/full-bleed-dialog.js +4 -0
  88. package/dist/components/full-bleed-dialog.js.map +1 -1
  89. package/dist/components/hover-menu.js +64 -56
  90. package/dist/components/hover-menu.js.map +1 -1
  91. package/dist/components/image-grid.d.ts +67 -0
  92. package/dist/components/image-grid.js +112 -0
  93. package/dist/components/image-grid.js.map +1 -0
  94. package/dist/components/lightbox.d.ts +104 -0
  95. package/dist/components/lightbox.js +229 -0
  96. package/dist/components/lightbox.js.map +1 -0
  97. package/dist/components/line-items.d.ts +114 -0
  98. package/dist/components/line-items.js +238 -0
  99. package/dist/components/line-items.js.map +1 -0
  100. package/dist/components/list.d.ts +37 -4
  101. package/dist/components/list.js +35 -14
  102. package/dist/components/list.js.map +1 -1
  103. package/dist/components/loading-state.d.ts +24 -0
  104. package/dist/components/loading-state.js +32 -0
  105. package/dist/components/loading-state.js.map +1 -0
  106. package/dist/components/menu-item.d.ts +2 -1
  107. package/dist/components/menu-item.js +5 -1
  108. package/dist/components/menu-item.js.map +1 -1
  109. package/dist/components/mini-calendar.d.ts +13 -1
  110. package/dist/components/mini-calendar.js +46 -2
  111. package/dist/components/mini-calendar.js.map +1 -1
  112. package/dist/components/modal.d.ts +20 -1
  113. package/dist/components/modal.js +26 -2
  114. package/dist/components/modal.js.map +1 -1
  115. package/dist/components/month-picker.d.ts +21 -1
  116. package/dist/components/month-picker.js +139 -26
  117. package/dist/components/month-picker.js.map +1 -1
  118. package/dist/components/multi-entity-combobox.d.ts +1 -1
  119. package/dist/components/multi-entity-combobox.js +42 -20
  120. package/dist/components/multi-entity-combobox.js.map +1 -1
  121. package/dist/components/nav-pills.d.ts +2 -1
  122. package/dist/components/nav-pills.js +5 -1
  123. package/dist/components/nav-pills.js.map +1 -1
  124. package/dist/components/number-field.d.ts +24 -5
  125. package/dist/components/number-field.js +5 -7
  126. package/dist/components/number-field.js.map +1 -1
  127. package/dist/components/number-input.d.ts +25 -5
  128. package/dist/components/number-input.js +7 -1
  129. package/dist/components/number-input.js.map +1 -1
  130. package/dist/components/numpad-sheet.d.ts +20 -5
  131. package/dist/components/numpad-sheet.js +3 -2
  132. package/dist/components/numpad-sheet.js.map +1 -1
  133. package/dist/components/page-header.d.ts +35 -6
  134. package/dist/components/page-header.js +7 -1
  135. package/dist/components/page-header.js.map +1 -1
  136. package/dist/components/passkeys-setting.d.ts +67 -0
  137. package/dist/components/passkeys-setting.js +214 -0
  138. package/dist/components/passkeys-setting.js.map +1 -0
  139. package/dist/components/picker-sheet.js +5 -1
  140. package/dist/components/picker-sheet.js.map +1 -1
  141. package/dist/components/pie-chart-labels.d.ts +20 -0
  142. package/dist/components/pie-chart-labels.js +12 -0
  143. package/dist/components/pie-chart-labels.js.map +1 -0
  144. package/dist/components/pie-chart.d.ts +101 -0
  145. package/dist/components/pie-chart.js +283 -0
  146. package/dist/components/pie-chart.js.map +1 -0
  147. package/dist/components/popover.js +3 -0
  148. package/dist/components/popover.js.map +1 -1
  149. package/dist/components/progress-bar.d.ts +44 -3
  150. package/dist/components/progress-bar.js +58 -22
  151. package/dist/components/progress-bar.js.map +1 -1
  152. package/dist/components/qr-code.d.ts +34 -0
  153. package/dist/components/qr-code.js +57 -0
  154. package/dist/components/qr-code.js.map +1 -0
  155. package/dist/components/search-field.d.ts +15 -3
  156. package/dist/components/search-field.js +5 -1
  157. package/dist/components/search-field.js.map +1 -1
  158. package/dist/components/settings-fields.d.ts +49 -1
  159. package/dist/components/signed-amount.d.ts +122 -0
  160. package/dist/components/signed-amount.js +152 -0
  161. package/dist/components/signed-amount.js.map +1 -0
  162. package/dist/components/skeleton.d.ts +10 -3
  163. package/dist/components/skeleton.js +12 -2
  164. package/dist/components/skeleton.js.map +1 -1
  165. package/dist/components/stat-tile.d.ts +2 -1
  166. package/dist/components/stat-tile.js +6 -3
  167. package/dist/components/stat-tile.js.map +1 -1
  168. package/dist/components/swipeable-row.js +4 -3
  169. package/dist/components/swipeable-row.js.map +1 -1
  170. package/dist/components/table.d.ts +39 -5
  171. package/dist/components/table.js +45 -11
  172. package/dist/components/table.js.map +1 -1
  173. package/dist/components/text-link.d.ts +238 -0
  174. package/dist/components/text-link.js +144 -0
  175. package/dist/components/text-link.js.map +1 -0
  176. package/dist/components/text.d.ts +26 -2
  177. package/dist/components/text.js +16 -2
  178. package/dist/components/text.js.map +1 -1
  179. package/dist/components/time-input.d.ts +49 -1
  180. package/dist/components/toggle-group.d.ts +35 -0
  181. package/dist/components/toggle-group.js +43 -14
  182. package/dist/components/toggle-group.js.map +1 -1
  183. package/dist/components/toggle-legend.d.ts +53 -3
  184. package/dist/components/toggle-legend.js +54 -1
  185. package/dist/components/toggle-legend.js.map +1 -1
  186. package/dist/components/tooltip.d.ts +51 -1
  187. package/dist/components/tooltip.js +59 -35
  188. package/dist/components/tooltip.js.map +1 -1
  189. package/dist/components/ui.d.ts +51 -779
  190. package/dist/components/ui.js +364 -34
  191. package/dist/components/ui.js.map +1 -1
  192. package/dist/components/use-table-state.d.ts +3 -52
  193. package/dist/components/use-table-state.js +128 -30
  194. package/dist/components/use-table-state.js.map +1 -1
  195. package/dist/{data-table-filters-Dh9uF_S-.d.ts → data-table-Drun8Fk9.d.ts} +305 -61
  196. package/dist/data-table.d.ts +2 -1
  197. package/dist/data-table.js +5 -1
  198. package/dist/data-table.js.map +1 -1
  199. package/dist/feedback/feedback-attachment.js +4 -6
  200. package/dist/feedback/feedback-attachment.js.map +1 -1
  201. package/dist/feedback/feedback-dialog.d.ts +26 -3
  202. package/dist/feedback/feedback-dialog.js +21 -5
  203. package/dist/feedback/feedback-dialog.js.map +1 -1
  204. package/dist/feedback/feedback-inbox.js +86 -75
  205. package/dist/feedback/feedback-inbox.js.map +1 -1
  206. package/dist/feedback/feedback-thread.d.ts +173 -0
  207. package/dist/feedback/feedback-thread.js +264 -0
  208. package/dist/feedback/feedback-thread.js.map +1 -0
  209. package/dist/feedback.d.ts +2 -1
  210. package/dist/feedback.js +1 -0
  211. package/dist/feedback.js.map +1 -1
  212. package/dist/hooks/use-authed-src.d.ts +71 -0
  213. package/dist/hooks/use-authed-src.js +63 -0
  214. package/dist/hooks/use-authed-src.js.map +1 -0
  215. package/dist/hooks/use-file-drop.d.ts +49 -2
  216. package/dist/hooks/use-hotkey.d.ts +59 -0
  217. package/dist/hooks/use-hotkey.js +105 -0
  218. package/dist/hooks/use-hotkey.js.map +1 -0
  219. package/dist/hooks/use-search-param-state.d.ts +83 -0
  220. package/dist/hooks/use-search-param-state.js +94 -0
  221. package/dist/hooks/use-search-param-state.js.map +1 -0
  222. package/dist/i18n/defaults.d.ts +15 -4
  223. package/dist/i18n/defaults.js +31 -1
  224. package/dist/i18n/defaults.js.map +1 -1
  225. package/dist/i18n/kit-labels.d.ts +46 -312
  226. package/dist/i18n/kit-labels.js +20 -5
  227. package/dist/i18n/kit-labels.js.map +1 -1
  228. package/dist/i18n/locales/de-CH-informal.d.ts +15 -4
  229. package/dist/i18n/locales/de-CH.d.ts +15 -4
  230. package/dist/i18n/locales/de-informal.d.ts +15 -4
  231. package/dist/i18n/locales/de.d.ts +15 -4
  232. package/dist/i18n/locales/de.js +164 -3
  233. package/dist/i18n/locales/de.js.map +1 -1
  234. package/dist/i18n/locales/es.d.ts +15 -4
  235. package/dist/i18n/locales/es.js +161 -3
  236. package/dist/i18n/locales/es.js.map +1 -1
  237. package/dist/i18n/locales/fr.d.ts +15 -4
  238. package/dist/i18n/locales/fr.js +161 -3
  239. package/dist/i18n/locales/fr.js.map +1 -1
  240. package/dist/i18n/locales/hu.d.ts +15 -4
  241. package/dist/i18n/locales/hu.js +161 -3
  242. package/dist/i18n/locales/hu.js.map +1 -1
  243. package/dist/i18n/locales/it.d.ts +15 -4
  244. package/dist/i18n/locales/it.js +161 -3
  245. package/dist/i18n/locales/it.js.map +1 -1
  246. package/dist/i18n/locales/zh.d.ts +15 -4
  247. package/dist/i18n/locales/zh.js +161 -3
  248. package/dist/i18n/locales/zh.js.map +1 -1
  249. package/dist/index.d.ts +39 -19
  250. package/dist/index.js +40 -1
  251. package/dist/index.js.map +1 -1
  252. package/dist/kit-labels-Mz8zZHIF.d.ts +1744 -0
  253. package/dist/lib/format.d.ts +162 -0
  254. package/dist/lib/format.js +151 -0
  255. package/dist/lib/format.js.map +1 -0
  256. package/dist/lib/qr-encode.d.ts +44 -0
  257. package/dist/lib/qr-encode.js +338 -0
  258. package/dist/lib/qr-encode.js.map +1 -0
  259. package/dist/rhf/fields.d.ts +283 -0
  260. package/dist/rhf/fields.js +631 -0
  261. package/dist/rhf/fields.js.map +1 -0
  262. package/dist/rhf/form.d.ts +49 -1
  263. package/dist/rhf/line-items.d.ts +31 -0
  264. package/dist/rhf/line-items.js +59 -0
  265. package/dist/rhf/line-items.js.map +1 -0
  266. package/dist/rhf.d.ts +61 -1
  267. package/dist/rhf.js +2 -0
  268. package/dist/rhf.js.map +1 -1
  269. package/dist/search/command-palette.js +20 -14
  270. package/dist/search/command-palette.js.map +1 -1
  271. package/dist/shell/app-shell.d.ts +99 -2
  272. package/dist/shell/app-shell.js +120 -57
  273. package/dist/shell/app-shell.js.map +1 -1
  274. package/dist/shell/auth-layout.d.ts +74 -0
  275. package/dist/shell/auth-layout.js +97 -0
  276. package/dist/shell/auth-layout.js.map +1 -0
  277. package/dist/shell/top-bar-brand.d.ts +81 -0
  278. package/dist/shell/top-bar-brand.js +47 -0
  279. package/dist/shell/top-bar-brand.js.map +1 -0
  280. package/dist/shell/topbar-action-menu.d.ts +21 -4
  281. package/dist/shell/topbar-action-menu.js +18 -2
  282. package/dist/shell/topbar-action-menu.js.map +1 -1
  283. package/dist/shell.d.ts +56 -1
  284. package/dist/shell.js +2 -0
  285. package/dist/shell.js.map +1 -1
  286. package/dist/tour/tour.js +10 -4
  287. package/dist/tour/tour.js.map +1 -1
  288. package/dist/wizard/stepper-nav.d.ts +48 -1
  289. package/dist/wizard/use-wizard.js +4 -2
  290. package/dist/wizard/use-wizard.js.map +1 -1
  291. package/dist/wizard/wizard-context.d.ts +24 -1
  292. package/dist/wizard/wizard-context.js +19 -2
  293. package/dist/wizard/wizard-context.js.map +1 -1
  294. package/dist/wizard/wizard-step.d.ts +30 -5
  295. package/dist/wizard/wizard-step.js +34 -3
  296. package/dist/wizard/wizard-step.js.map +1 -1
  297. package/dist/wizard.d.ts +50 -3
  298. package/package.json +6 -6
  299. package/src/chart.ts +4 -0
  300. package/src/components/account-settings-labels.ts +190 -0
  301. package/src/components/account-settings.tsx +110 -63
  302. package/src/components/amount-input.tsx +109 -10
  303. package/src/components/authed-image.tsx +190 -0
  304. package/src/components/breadcrumbs.tsx +8 -2
  305. package/src/components/bulk-action-bar.tsx +16 -3
  306. package/src/components/button-group.tsx +7 -2
  307. package/src/components/calendar-heatmap.tsx +105 -10
  308. package/src/components/chart.tsx +19 -8
  309. package/src/components/chip.tsx +14 -4
  310. package/src/components/choice-card.tsx +136 -25
  311. package/src/components/combobox-core.tsx +33 -9
  312. package/src/components/combobox.tsx +33 -9
  313. package/src/components/copy-button.tsx +3 -2
  314. package/src/components/data-table-cells.tsx +119 -0
  315. package/src/components/data-table-filter-popover.tsx +13 -5
  316. package/src/components/data-table-filters.ts +77 -0
  317. package/src/components/data-table-labels.ts +23 -0
  318. package/src/components/data-table.tsx +230 -13
  319. package/src/components/date-picker.tsx +19 -3
  320. package/src/components/description-list.tsx +52 -3
  321. package/src/components/entity-combobox.tsx +25 -7
  322. package/src/components/error-boundary.tsx +640 -0
  323. package/src/components/field-sync.tsx +48 -40
  324. package/src/components/field.tsx +56 -5
  325. package/src/components/floating-panel.tsx +20 -7
  326. package/src/components/form-actions.tsx +191 -0
  327. package/src/components/full-bleed-dialog.tsx +4 -0
  328. package/src/components/hover-menu.tsx +26 -17
  329. package/src/components/image-grid.tsx +181 -0
  330. package/src/components/lightbox.tsx +374 -0
  331. package/src/components/line-items.tsx +385 -0
  332. package/src/components/list.tsx +82 -19
  333. package/src/components/loading-state.tsx +47 -0
  334. package/src/components/menu-item.tsx +7 -2
  335. package/src/components/mini-calendar.tsx +72 -3
  336. package/src/components/modal.tsx +65 -3
  337. package/src/components/month-picker.tsx +181 -26
  338. package/src/components/multi-entity-combobox.tsx +27 -7
  339. package/src/components/nav-pills.tsx +8 -1
  340. package/src/components/number-field.tsx +15 -10
  341. package/src/components/number-input.tsx +17 -1
  342. package/src/components/numpad-sheet.tsx +6 -1
  343. package/src/components/page-header.tsx +42 -5
  344. package/src/components/passkeys-setting.tsx +331 -0
  345. package/src/components/picker-sheet.tsx +10 -1
  346. package/src/components/pie-chart-labels.ts +32 -0
  347. package/src/components/pie-chart.tsx +479 -0
  348. package/src/components/popover.tsx +3 -0
  349. package/src/components/progress-bar.tsx +129 -19
  350. package/src/components/qr-code.tsx +83 -0
  351. package/src/components/search-field.tsx +20 -4
  352. package/src/components/signed-amount.tsx +295 -0
  353. package/src/components/skeleton.tsx +21 -3
  354. package/src/components/stat-tile.tsx +11 -3
  355. package/src/components/swipeable-row.tsx +7 -7
  356. package/src/components/table.tsx +102 -13
  357. package/src/components/text-link.tsx +356 -0
  358. package/src/components/text.tsx +46 -2
  359. package/src/components/toggle-group.tsx +93 -20
  360. package/src/components/toggle-legend.tsx +108 -2
  361. package/src/components/tooltip.tsx +79 -8
  362. package/src/components/ui.tsx +707 -49
  363. package/src/components/use-table-state.ts +265 -33
  364. package/src/data-table.ts +10 -0
  365. package/src/feedback/feedback-attachment.tsx +10 -7
  366. package/src/feedback/feedback-dialog.tsx +49 -7
  367. package/src/feedback/feedback-inbox.tsx +7 -0
  368. package/src/feedback/feedback-thread.tsx +510 -0
  369. package/src/feedback.ts +1 -0
  370. package/src/hooks/use-authed-src.ts +161 -0
  371. package/src/hooks/use-hotkey.ts +172 -0
  372. package/src/hooks/use-search-param-state.ts +187 -0
  373. package/src/i18n/defaults.ts +30 -0
  374. package/src/i18n/kit-labels.tsx +118 -8
  375. package/src/i18n/locales/de.ts +161 -0
  376. package/src/i18n/locales/es.ts +158 -0
  377. package/src/i18n/locales/fr.ts +161 -0
  378. package/src/i18n/locales/hu.ts +159 -0
  379. package/src/i18n/locales/it.ts +159 -0
  380. package/src/i18n/locales/zh.ts +158 -0
  381. package/src/index.ts +59 -0
  382. package/src/lib/format.ts +348 -0
  383. package/src/lib/qr-encode.ts +420 -0
  384. package/src/rhf/fields.tsx +1135 -0
  385. package/src/rhf/line-items.tsx +130 -0
  386. package/src/rhf.ts +6 -0
  387. package/src/search/command-palette.tsx +29 -19
  388. package/src/shell/app-shell.tsx +153 -3
  389. package/src/shell/auth-layout.tsx +190 -0
  390. package/src/shell/top-bar-brand.tsx +76 -0
  391. package/src/shell/topbar-action-menu.tsx +32 -4
  392. package/src/shell.ts +2 -0
  393. package/src/tour/tour.tsx +16 -5
  394. package/src/wizard/use-wizard.ts +8 -4
  395. package/src/wizard/wizard-context.tsx +41 -1
  396. package/src/wizard/wizard-step.tsx +75 -6
  397. package/tokens.css +12 -0
@@ -6,7 +6,8 @@ import { cn } from "../lib/cn.js";
6
6
  import { horizontalStep } from "../lib/direction.js";
7
7
  import { useMediaQuery } from "../hooks/use-media-query.js";
8
8
  import { Tooltip } from "./tooltip.js";
9
- import { DEFAULT_COMMON_LABELS, useKitLabels } from "../i18n/kit-labels.js";
9
+ import { DEFAULT_COMMON_LABELS, useKitLabels, useKitLink } from "../i18n/kit-labels.js";
10
+ import { pickLinkRenderer, replacingClick, routerLinkNavigation } from "./text-link.js";
10
11
  const BUTTON_BASE = "inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 disabled:opacity-50 disabled:cursor-not-allowed";
11
12
  const BUTTON_SIZES = {
12
13
  md: "gap-2 px-3 py-2 text-sm",
@@ -32,6 +33,10 @@ const BUTTON_TONES = {
32
33
  danger: "text-[var(--text-secondary)] hover:text-[var(--danger)] focus:ring-[var(--danger-border)] disabled:hover:text-[var(--text-secondary)]"
33
34
  };
34
35
  const TONED_VARIANTS = /* @__PURE__ */ new Set(["link", "ghost"]);
36
+ const BUTTON_BOXED_DANGER = {
37
+ secondary: "border-[var(--danger-border)] bg-transparent text-[var(--danger)] hover:bg-[var(--danger-bg)] focus:ring-[var(--danger-border)]",
38
+ primary: "border-[var(--danger-border)] bg-[var(--danger-bg)] text-[var(--danger)] hover:border-[var(--danger)] hover:bg-[var(--danger)] hover:text-[var(--danger-contrast)] focus:ring-[var(--danger-border)] disabled:hover:border-[var(--danger-border)] disabled:hover:bg-[var(--danger-bg)] disabled:hover:text-[var(--danger)]"
39
+ };
35
40
  const BUTTON_LINK_PRESSED = "font-medium text-[var(--brand)] hover:text-[var(--brand)] disabled:hover:text-[var(--brand)]";
36
41
  function buttonClasses(variant = "primary", classNameOrOptions) {
37
42
  const { size = "md", className } = typeof classNameOrOptions === "object" ? classNameOrOptions : { className: classNameOrOptions };
@@ -40,49 +45,156 @@ function buttonClasses(variant = "primary", classNameOrOptions) {
40
45
  function hasContent(node) {
41
46
  return node !== void 0 && node !== null && node !== false && node !== "";
42
47
  }
43
- function Button({
48
+ function buttonLook(variant, size, stretch, tone) {
49
+ return cn(
50
+ BUTTON_BASE,
51
+ BUTTON_SIZES[size],
52
+ // In a flex row next to a taller labelled field, `stretch` makes the button
53
+ // fill the field's height so the two line up (self-stretch overrides the row's
54
+ // align-items). No effect outside a flex row / when it's already the tallest.
55
+ stretch && "self-stretch",
56
+ buttonVariantClasses[variant],
57
+ tone !== "default" && TONED_VARIANTS.has(variant) && BUTTON_TONES[tone],
58
+ tone === "danger" && BUTTON_BOXED_DANGER[variant]
59
+ );
60
+ }
61
+ function Button(props) {
62
+ if (props.href !== void 0) return /* @__PURE__ */ jsx(ButtonLink, { ...props });
63
+ return /* @__PURE__ */ jsx(ButtonElement, { ...props });
64
+ }
65
+ function RenderedButtonLink({ render, ...props }) {
66
+ return render(props);
67
+ }
68
+ function ButtonLink({
69
+ href,
70
+ renderLink,
71
+ external,
72
+ replace,
73
+ reloadDocument,
74
+ disabled,
75
+ variant = "primary",
76
+ size = "md",
77
+ stretch,
78
+ tone = "default",
79
+ className,
80
+ children,
81
+ target,
82
+ rel,
83
+ onClick,
84
+ ...rest
85
+ }) {
86
+ const kitLink = useKitLink();
87
+ const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
88
+ const Link = reloadDocument ? void 0 : pickLinkRenderer(renderLink, kitLink, href);
89
+ const newTab = !disabled && (external || target === "_blank");
90
+ const cls = cn(
91
+ buttonLook(variant, size, stretch, tone),
92
+ // `relative` holds the sr-only note (see sr-only-containment.test).
93
+ newTab && "relative",
94
+ // BUTTON_BASE's `disabled:` classes never match an `<a>`; no pointer events also
95
+ // keeps the hover fill from lighting up on something that refuses the click.
96
+ disabled && "pointer-events-none cursor-not-allowed opacity-50",
97
+ className
98
+ );
99
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ children,
101
+ newTab && " ",
102
+ newTab && /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
103
+ "(",
104
+ common.opensInNewTab,
105
+ ")"
106
+ ] })
107
+ ] });
108
+ if (disabled) {
109
+ return /* @__PURE__ */ jsx("a", { ...rest, role: "link", "aria-disabled": "true", className: cls, children: body });
110
+ }
111
+ if (external || !Link) {
112
+ return /* @__PURE__ */ jsx(
113
+ "a",
114
+ {
115
+ ...rest,
116
+ href,
117
+ target: external ? "_blank" : target,
118
+ rel: external ? rel ?? "noopener noreferrer" : rel,
119
+ onClick: external ? onClick : replacingClick(onClick, href, replace, target),
120
+ className: cls,
121
+ children: body
122
+ }
123
+ );
124
+ }
125
+ return /* @__PURE__ */ jsx(
126
+ RenderedButtonLink,
127
+ {
128
+ render: Link,
129
+ ...rest,
130
+ ...routerLinkNavigation(replace),
131
+ href,
132
+ target,
133
+ rel,
134
+ onClick,
135
+ className: cls,
136
+ children: body
137
+ }
138
+ );
139
+ }
140
+ function ButtonElement({
44
141
  variant = "primary",
45
142
  size = "md",
46
143
  stretch,
47
144
  tone = "default",
48
145
  pressed,
49
146
  disabledReason,
147
+ pending,
50
148
  className,
51
149
  onClick,
150
+ children,
151
+ href: _href,
152
+ renderLink: _renderLink,
153
+ external: _external,
154
+ replace: _replace,
155
+ reloadDocument: _reloadDocument,
52
156
  ...rest
53
157
  }) {
54
158
  const reasonId = useId();
55
159
  const locked = hasContent(disabledReason);
160
+ const inert = locked || Boolean(pending);
56
161
  const ownDescribedBy = rest["aria-describedby"];
57
162
  const button = /* @__PURE__ */ jsx(
58
163
  "button",
59
164
  {
60
165
  ...rest,
61
- disabled: locked ? void 0 : rest.disabled,
62
- "aria-disabled": locked || rest["aria-disabled"],
166
+ disabled: inert ? void 0 : rest.disabled,
167
+ "aria-disabled": inert || rest["aria-disabled"],
168
+ "aria-busy": pending || rest["aria-busy"],
63
169
  "aria-describedby": locked ? ownDescribedBy ? `${ownDescribedBy} ${reasonId}` : reasonId : ownDescribedBy,
64
170
  "aria-pressed": pressed ?? rest["aria-pressed"],
65
171
  onClick: (e) => {
66
- if (locked) {
172
+ if (inert) {
67
173
  e.preventDefault();
68
174
  return;
69
175
  }
70
176
  onClick?.(e);
71
177
  },
72
178
  className: cn(
73
- BUTTON_BASE,
74
- BUTTON_SIZES[size],
75
- // In a flex row next to a taller labelled field, `stretch` makes the button
76
- // fill the field's height so the two line up (self-stretch overrides the row's
77
- // align-items). No effect outside a flex row / when it's already the tallest.
78
- stretch && "self-stretch",
79
- buttonVariantClasses[variant],
80
- tone !== "default" && TONED_VARIANTS.has(variant) && BUTTON_TONES[tone],
179
+ buttonLook(variant, size, stretch, tone),
81
180
  pressed && (variant === "link" ? BUTTON_LINK_PRESSED : ICON_BUTTON_PRESSED),
82
181
  // The disabled look for the focusable kind of disabled.
83
182
  locked && "cursor-not-allowed opacity-50",
183
+ // No dimming while pending: the spinner IS the state, and at half opacity it
184
+ // would be the faintest thing on the button. `relative` anchors it.
185
+ pending && "relative cursor-progress",
84
186
  className
85
- )
187
+ ),
188
+ children: pending ? /* @__PURE__ */ jsxs(Fragment, { children: [
189
+ /* @__PURE__ */ jsx("span", { className: "inline-flex items-center justify-center gap-[inherit] opacity-0", children }),
190
+ /* @__PURE__ */ jsx(
191
+ Spinner,
192
+ {
193
+ label: null,
194
+ className: "absolute inset-0 m-auto size-4 border-current/30 border-t-current"
195
+ }
196
+ )
197
+ ] }) : children
86
198
  }
87
199
  );
88
200
  if (!locked) return button;
@@ -99,6 +211,9 @@ function Button({
99
211
  }
100
212
  const ICON_BUTTON_BASE = "inline-flex items-center justify-center rounded-md transition-colors focus:outline-none focus:ring-2 disabled:opacity-50 disabled:cursor-not-allowed";
101
213
  const ICON_BUTTON_SIZES = {
214
+ // 64px with a 28px glyph: a camera's shutter (keksdose invoices/camera-capture.tsx:248,
215
+ // `size-16` by hand) — the one control of a full-screen capture view, thumb-sized.
216
+ "2xl": "size-16 [&_svg]:size-7",
102
217
  // 48px with a 24px glyph: the one primary action of a phone screen or sheet, a step
103
218
  // past the 44px minimum rather than on it.
104
219
  xl: "size-12 [&_svg]:size-6",
@@ -111,6 +226,7 @@ const ICON_BUTTON_SIZES = {
111
226
  "2xs": "size-6 rounded [&_svg]:size-3.5"
112
227
  };
113
228
  const ICON_BUTTON_STRETCH_SIZES = {
229
+ "2xl": "w-16 min-h-16 self-stretch [&_svg]:size-7",
114
230
  xl: "w-12 min-h-12 self-stretch [&_svg]:size-6",
115
231
  lg: "w-11 min-h-11 self-stretch [&_svg]:size-5",
116
232
  md: "w-9 min-h-9 self-stretch [&_svg]:size-5",
@@ -165,12 +281,168 @@ const ICON_BUTTON_DISABLED_REST = {
165
281
  danger: "disabled:hover:bg-[var(--danger)]",
166
282
  brand: "disabled:hover:bg-[var(--brand)]",
167
283
  link: "disabled:hover:bg-transparent disabled:hover:no-underline",
168
- overlay: "disabled:hover:bg-[color-mix(in_srgb,var(--bg-inverse)_60%,transparent)]"
284
+ overlay: "disabled:hover:bg-[color-mix(in_srgb,var(--bg-inverse)_60%,transparent)]",
285
+ shutter: "disabled:hover:bg-[var(--media-scrim)]"
169
286
  };
170
287
  const ICON_BUTTON_QUIET_DISABLED_REST = "disabled:hover:text-[var(--text-placeholder)]";
171
288
  const ICON_BUTTON_PRESSED = "bg-[var(--brand-bg)] text-[var(--brand)] hover:bg-[var(--brand-bg-hover)] hover:text-[var(--brand)] disabled:hover:bg-[var(--brand-bg)] disabled:hover:text-[var(--brand)]";
172
289
  const ICON_BUTTON_OVERLAY = "rounded-full bg-[color-mix(in_srgb,var(--bg-inverse)_60%,transparent)] text-[var(--text-inverse)] backdrop-blur-sm hover:bg-[color-mix(in_srgb,var(--bg-inverse)_75%,transparent)] focus:ring-[var(--text-inverse)]";
173
- const IconButton = forwardRef(function IconButton2({
290
+ const ICON_BUTTON_SHUTTER = "rounded-full border-4 border-[var(--media-ink)] bg-[var(--media-scrim)] text-[var(--media-ink)] backdrop-blur-sm hover:bg-[var(--media-scrim-hover)] focus:ring-[var(--media-ink)] focus:ring-offset-2 focus:ring-offset-[var(--media-scrim-hover)]";
291
+ const ICON_BUTTON_GLYPH_SIZES = {
292
+ 12: "[&_svg]:size-3",
293
+ 14: "[&_svg]:size-3.5",
294
+ 16: "[&_svg]:size-4",
295
+ 20: "[&_svg]:size-5",
296
+ 24: "[&_svg]:size-6",
297
+ 28: "[&_svg]:size-7"
298
+ };
299
+ const ICON_BUTTON_TONE_PAIR = "[--icon-button-tone:var(--icon-button-tone-light)] dark:[--icon-button-tone:var(--icon-button-tone-dark)]";
300
+ function toneColorStyle(toneColor, style) {
301
+ if (toneColor === void 0) return style;
302
+ const vars = typeof toneColor === "string" ? { "--icon-button-tone": toneColor } : { "--icon-button-tone-light": toneColor.light, "--icon-button-tone-dark": toneColor.dark };
303
+ return { ...style, ...vars };
304
+ }
305
+ function iconButtonLook({
306
+ variant,
307
+ size,
308
+ stretch,
309
+ glyphSize,
310
+ shape,
311
+ tone,
312
+ quiet,
313
+ toneColor
314
+ }) {
315
+ return cn(
316
+ ICON_BUTTON_BASE,
317
+ stretch ? ICON_BUTTON_STRETCH_SIZES[size] : ICON_BUTTON_SIZES[size],
318
+ glyphSize !== void 0 && ICON_BUTTON_GLYPH_SIZES[glyphSize],
319
+ // After the size, so the overlay's `rounded-full` beats the small sizes' `rounded`.
320
+ variant === "overlay" ? ICON_BUTTON_OVERLAY : variant === "shutter" ? ICON_BUTTON_SHUTTER : buttonVariantClasses[variant],
321
+ shape === "round" && "rounded-full",
322
+ ICON_BUTTON_DISABLED_REST[variant],
323
+ iconButtonToneClass(tone, quiet),
324
+ toneColor !== void 0 && typeof toneColor !== "string" && ICON_BUTTON_TONE_PAIR
325
+ );
326
+ }
327
+ function withIconButtonBadge(control, badge, stretch) {
328
+ if (!hasContent(badge)) return control;
329
+ return /* @__PURE__ */ jsxs("span", { className: cn("relative inline-flex shrink-0", stretch && "self-stretch"), children: [
330
+ control,
331
+ /* @__PURE__ */ jsx(
332
+ "span",
333
+ {
334
+ "aria-hidden": true,
335
+ "data-slot": "icon-button-badge",
336
+ className: "pointer-events-none absolute -end-0.5 -bottom-0.5 inline-flex rounded-full bg-[var(--bg-surface)] [&_svg]:size-3",
337
+ children: badge
338
+ }
339
+ )
340
+ ] });
341
+ }
342
+ function IconButton(props) {
343
+ if (props.href !== void 0) return /* @__PURE__ */ jsx(IconButtonLink, { ...props });
344
+ return /* @__PURE__ */ jsx(IconButtonElement, { ...props });
345
+ }
346
+ IconButton.displayName = "IconButton";
347
+ function IconButtonLink({
348
+ href,
349
+ renderLink,
350
+ external,
351
+ replace,
352
+ reloadDocument,
353
+ disabled,
354
+ variant = "ghost",
355
+ size = "md",
356
+ tone: toneProp,
357
+ quiet,
358
+ stopPropagation,
359
+ stretch,
360
+ shape = "square",
361
+ toneColor,
362
+ label,
363
+ tooltip = true,
364
+ tooltipSide,
365
+ tooltipPortal,
366
+ glyphSize,
367
+ badge,
368
+ className,
369
+ style,
370
+ target,
371
+ rel,
372
+ onClick,
373
+ onKeyDown,
374
+ children,
375
+ ref,
376
+ ...rest
377
+ }) {
378
+ const kitLink = useKitLink();
379
+ const common = useKitLabels("common", DEFAULT_COMMON_LABELS);
380
+ const tone = toneProp ?? (toneColor !== void 0 ? "custom" : "default");
381
+ const Link = reloadDocument ? void 0 : pickLinkRenderer(renderLink, kitLink, href);
382
+ const newTab = !disabled && (external || target === "_blank");
383
+ const name = rest["aria-label"] ?? label;
384
+ const ariaLabel = name !== void 0 && newTab ? `${name} (${common.opensInNewTab})` : name;
385
+ const handleClick = (e) => {
386
+ if (stopPropagation) e.stopPropagation();
387
+ onClick?.(e);
388
+ };
389
+ const handleKeyDown = (e) => {
390
+ if (stopPropagation && e.key === "Enter") e.stopPropagation();
391
+ onKeyDown?.(e);
392
+ };
393
+ const cls = cn(
394
+ iconButtonLook({ variant, size, stretch, glyphSize, shape, tone, quiet, toneColor }),
395
+ // BASE's `disabled:` classes never match an `<a>` — Button's disabled link look.
396
+ disabled && "pointer-events-none cursor-not-allowed opacity-50",
397
+ className
398
+ );
399
+ const look = { style: toneColorStyle(toneColor, style), className: cls };
400
+ let control;
401
+ if (disabled) {
402
+ control = /* @__PURE__ */ jsx("a", { ...rest, ...look, ref, role: "link", "aria-disabled": "true", "aria-label": ariaLabel, children });
403
+ } else if (external || !Link) {
404
+ control = /* @__PURE__ */ jsx(
405
+ "a",
406
+ {
407
+ ...rest,
408
+ ...look,
409
+ ref,
410
+ href,
411
+ "aria-label": ariaLabel,
412
+ target: external ? "_blank" : target,
413
+ rel: external ? rel ?? "noopener noreferrer" : rel,
414
+ onClick: external ? handleClick : replacingClick(handleClick, href, replace, target),
415
+ onKeyDown: handleKeyDown,
416
+ children
417
+ }
418
+ );
419
+ } else {
420
+ control = /* @__PURE__ */ jsx(
421
+ RenderedButtonLink,
422
+ {
423
+ render: Link,
424
+ ...rest,
425
+ ...look,
426
+ ...routerLinkNavigation(replace),
427
+ ref,
428
+ href,
429
+ "aria-label": ariaLabel,
430
+ target,
431
+ rel,
432
+ onClick: handleClick,
433
+ onKeyDown: handleKeyDown,
434
+ children
435
+ }
436
+ );
437
+ }
438
+ control = withIconButtonBadge(control, badge, stretch);
439
+ if (!tooltip || label === void 0 || label === "") return control;
440
+ return (
441
+ // A fragment, as on the button: the bubble says what `aria-label` already does.
442
+ /* @__PURE__ */ jsx(Tooltip, { label, side: tooltipSide, portal: tooltipPortal, className: stretch ? "self-stretch" : void 0, children: /* @__PURE__ */ jsx(Fragment, { children: control }) })
443
+ );
444
+ }
445
+ function IconButtonElement({
174
446
  variant = "ghost",
175
447
  size = "md",
176
448
  tone: toneProp,
@@ -185,13 +457,23 @@ const IconButton = forwardRef(function IconButton2({
185
457
  tooltipSide,
186
458
  tooltipPortal,
187
459
  disabledReason,
460
+ glyphSize,
461
+ badge,
462
+ disabledStyle = "dim",
188
463
  className,
189
464
  style,
190
465
  onClick,
191
466
  onKeyDown,
467
+ href: _href,
468
+ renderLink: _renderLink,
469
+ external: _external,
470
+ replace: _replace,
471
+ reloadDocument: _reloadDocument,
472
+ ref,
192
473
  ...rest
193
- }, ref) {
474
+ }) {
194
475
  const tone = toneProp ?? (toneColor !== void 0 ? "custom" : "default");
476
+ const keep = disabledStyle === "keep";
195
477
  const reasonId = useId();
196
478
  const locked = hasContent(disabledReason);
197
479
  const ownDescribedBy = rest["aria-describedby"];
@@ -205,7 +487,7 @@ const IconButton = forwardRef(function IconButton2({
205
487
  "aria-describedby": locked ? ownDescribedBy ? `${ownDescribedBy} ${reasonId}` : reasonId : ownDescribedBy,
206
488
  "aria-label": rest["aria-label"] ?? label,
207
489
  "aria-pressed": pressed ?? rest["aria-pressed"],
208
- style: toneColor !== void 0 ? { ...style, ["--icon-button-tone"]: toneColor } : style,
490
+ style: toneColorStyle(toneColor, style),
209
491
  onClick: (e) => {
210
492
  if (stopPropagation) e.stopPropagation();
211
493
  if (locked) {
@@ -219,20 +501,16 @@ const IconButton = forwardRef(function IconButton2({
219
501
  onKeyDown?.(e);
220
502
  },
221
503
  className: cn(
222
- ICON_BUTTON_BASE,
223
- stretch ? ICON_BUTTON_STRETCH_SIZES[size] : ICON_BUTTON_SIZES[size],
224
- // After the size, so the overlay's `rounded-full` beats the small sizes' `rounded`.
225
- variant === "overlay" ? ICON_BUTTON_OVERLAY : buttonVariantClasses[variant],
226
- shape === "round" && "rounded-full",
227
- ICON_BUTTON_DISABLED_REST[variant],
228
- iconButtonToneClass(tone, quiet),
504
+ iconButtonLook({ variant, size, stretch, glyphSize, shape, tone, quiet, toneColor }),
229
505
  pressed && ICON_BUTTON_PRESSED,
230
506
  // The disabled look for the focusable kind of disabled, as on Button.
231
- locked && "cursor-not-allowed opacity-50",
507
+ locked && (keep ? "cursor-default" : "cursor-not-allowed opacity-50"),
508
+ keep && "disabled:cursor-default disabled:opacity-100",
232
509
  className
233
510
  )
234
511
  }
235
512
  );
513
+ const control = withIconButtonBadge(button, badge, stretch);
236
514
  if (locked) {
237
515
  return (
238
516
  // Button's shape: the button and the hidden reason in a FRAGMENT, so Tooltip does
@@ -245,21 +523,20 @@ const IconButton = forwardRef(function IconButton2({
245
523
  portal: tooltipPortal,
246
524
  className: stretch ? "self-stretch" : void 0,
247
525
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
248
- button,
526
+ control,
249
527
  /* @__PURE__ */ jsx("span", { id: reasonId, hidden: true, children: disabledReason })
250
528
  ] })
251
529
  }
252
530
  )
253
531
  );
254
532
  }
255
- if (!tooltip || label === void 0 || label === "") return button;
533
+ if (!tooltip || label === void 0 || label === "") return control;
256
534
  return (
257
535
  // A fragment, so Tooltip leaves the button's description alone: the bubble says
258
536
  // exactly what `aria-label` already does.
259
- /* @__PURE__ */ jsx(Tooltip, { label, side: tooltipSide, portal: tooltipPortal, className: stretch ? "self-stretch" : void 0, children: /* @__PURE__ */ jsx(Fragment, { children: button }) })
537
+ /* @__PURE__ */ jsx(Tooltip, { label, side: tooltipSide, portal: tooltipPortal, className: stretch ? "self-stretch" : void 0, children: /* @__PURE__ */ jsx(Fragment, { children: control }) })
260
538
  );
261
- });
262
- IconButton.displayName = "IconButton";
539
+ }
263
540
  const FIELD_BASE = "block w-full rounded-md border border-[var(--border)] bg-[var(--bg-surface)] px-3 py-2 text-sm text-[var(--text-primary)] shadow-sm placeholder:text-[var(--text-placeholder)] focus:border-[var(--brand)] focus:ring-[var(--brand)] disabled:cursor-default disabled:bg-[var(--bg-surface-2)] disabled:text-[var(--text-muted)] [&[readonly]]:bg-[var(--bg-surface-2)] [&[readonly]]:text-[var(--text-muted)]";
264
541
  const FIELD_WRITABLE_LOOK = "[&[readonly]]:bg-[var(--bg-surface)] [&[readonly]]:text-[var(--text-primary)]";
265
542
  const FIELD_FLOATING_PAD = "pt-4 pb-1";
@@ -627,19 +904,55 @@ const Textarea = forwardRef(function Textarea2({ className, label, id, placehold
627
904
  ) }) });
628
905
  });
629
906
  Textarea.displayName = "Textarea";
630
- function Card({ className, children, flush, variant = "default", ...rest }) {
907
+ const CARD_TONES = {
908
+ warning: {
909
+ border: "border-[var(--warning-border)]",
910
+ fill: "bg-[var(--warning-bg)]",
911
+ title: "[&_[data-slot=card-title]]:text-[var(--warning)]"
912
+ },
913
+ danger: {
914
+ border: "border-[var(--danger-border)]",
915
+ fill: "bg-[var(--danger-bg)]",
916
+ title: "[&_[data-slot=card-title]]:text-[var(--danger)]"
917
+ },
918
+ info: {
919
+ border: "border-[var(--info-border)]",
920
+ fill: "bg-[var(--info-bg)]",
921
+ title: "[&_[data-slot=card-title]]:text-[var(--info)]"
922
+ },
923
+ success: {
924
+ border: "border-[var(--success-border)]",
925
+ fill: "bg-[var(--success-bg)]",
926
+ title: "[&_[data-slot=card-title]]:text-[var(--success)]"
927
+ }
928
+ };
929
+ const CARD_PADDING = {
930
+ none: "p-0",
931
+ sm: "p-3",
932
+ md: "p-4"
933
+ };
934
+ function Card({ className, children, flush, variant = "default", tone, padding, ...rest }) {
935
+ const toned = tone ? CARD_TONES[tone] : void 0;
936
+ const bordered = variant !== "inset";
631
937
  return /* @__PURE__ */ jsx(
632
938
  "div",
633
939
  {
940
+ "data-tone": tone,
634
941
  ...rest,
635
942
  className: cn(
636
- variant === "inset" ? "rounded-md bg-[var(--bg-surface-2)] p-3" : cn(
943
+ variant === "inset" ? "rounded-md bg-[var(--bg-surface-2)] p-3" : variant === "outline" ? (
944
+ // No shadow and no `flush`: it sits on a surface that already has both.
945
+ "rounded-lg border border-[var(--border)] bg-[var(--bg-surface)] p-4"
946
+ ) : cn(
637
947
  // Surface + border are theme tokens so the palette switcher (feedback
638
948
  // #307) can re-skin every card; a caller's own bg-*/border-* override
639
949
  // still wins via tailwind-merge.
640
950
  "bg-[var(--bg-surface)]",
641
951
  flush ? "border-y border-[var(--border)] md:rounded-lg md:border md:shadow-sm" : "rounded-lg border border-[var(--border)] shadow-sm"
642
952
  ),
953
+ toned && (bordered ? toned.border : toned.fill),
954
+ toned?.title,
955
+ padding && CARD_PADDING[padding],
643
956
  className
644
957
  ),
645
958
  children
@@ -704,7 +1017,7 @@ function CardFooter({ className, ...props }) {
704
1017
  }
705
1018
  );
706
1019
  }
707
- function Spinner({ className, label, ...rest }) {
1020
+ function Spinner({ className, label, showLabel, labelPosition = "end", ...rest }) {
708
1021
  const common = useKitLabels("common", DEFAULT_COMMON_LABELS, {
709
1022
  loading: label ?? void 0
710
1023
  });
@@ -713,6 +1026,23 @@ function Spinner({ className, label, ...rest }) {
713
1026
  className
714
1027
  );
715
1028
  if (label === null) return /* @__PURE__ */ jsx("span", { "aria-hidden": true, ...rest, className: ring });
1029
+ if (showLabel) {
1030
+ return /* @__PURE__ */ jsxs(
1031
+ "span",
1032
+ {
1033
+ role: "status",
1034
+ ...rest,
1035
+ className: cn(
1036
+ "inline-flex items-center text-sm text-[var(--text-secondary)]",
1037
+ labelPosition === "below" ? "flex-col gap-2 text-center" : "gap-2"
1038
+ ),
1039
+ children: [
1040
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: ring }),
1041
+ /* @__PURE__ */ jsx("span", { children: common.loading })
1042
+ ]
1043
+ }
1044
+ );
1045
+ }
716
1046
  return /* @__PURE__ */ jsx("span", { role: "status", ...rest, className: ring, children: /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
717
1047
  common.loading,
718
1048
  " "