@krizaka/ui 2.3.0 → 2.5.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 (280) hide show
  1. package/README.md +16 -1
  2. package/dist/audio-player.d.ts +113 -0
  3. package/dist/audio-player.js +207 -0
  4. package/dist/audio-player.js.map +1 -0
  5. package/dist/chunk-2USC2YT6.js +17 -0
  6. package/dist/chunk-2USC2YT6.js.map +1 -0
  7. package/dist/chunk-EUPTXKH7.js +95 -0
  8. package/dist/chunk-EUPTXKH7.js.map +1 -0
  9. package/dist/chunk-RUPRYJ45.js +82 -0
  10. package/dist/chunk-RUPRYJ45.js.map +1 -0
  11. package/dist/chunk-XUMJA5ZI.js +283 -0
  12. package/dist/chunk-XUMJA5ZI.js.map +1 -0
  13. package/dist/chunk-YH4LMWRU.js +92 -0
  14. package/dist/chunk-YH4LMWRU.js.map +1 -0
  15. package/dist/chunk-YX6CNVJA.js +94 -0
  16. package/dist/chunk-YX6CNVJA.js.map +1 -0
  17. package/dist/chunk-ZIXB33X7.js +95 -0
  18. package/dist/chunk-ZIXB33X7.js.map +1 -0
  19. package/dist/combobox.d.ts +188 -0
  20. package/dist/combobox.js +16 -0
  21. package/dist/combobox.js.map +1 -0
  22. package/dist/data-table.d.ts +246 -0
  23. package/dist/data-table.js +290 -0
  24. package/dist/data-table.js.map +1 -0
  25. package/dist/date-picker.d.ts +288 -0
  26. package/dist/date-picker.js +364 -0
  27. package/dist/date-picker.js.map +1 -0
  28. package/dist/file-upload.d.ts +238 -0
  29. package/dist/file-upload.js +437 -0
  30. package/dist/file-upload.js.map +1 -0
  31. package/dist/filter-bar.d.ts +139 -0
  32. package/dist/filter-bar.js +155 -0
  33. package/dist/filter-bar.js.map +1 -0
  34. package/dist/image-cropper.d.ts +115 -0
  35. package/dist/image-cropper.js +166 -0
  36. package/dist/image-cropper.js.map +1 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/media-capture.d.ts +155 -0
  39. package/dist/media-capture.js +242 -0
  40. package/dist/media-capture.js.map +1 -0
  41. package/dist/native/media-capture.d.ts +49 -0
  42. package/dist/native/media-capture.js +113 -0
  43. package/dist/native/media-capture.js.map +1 -0
  44. package/dist/native/video-player.d.ts +50 -0
  45. package/dist/native/video-player.js +69 -0
  46. package/dist/native/video-player.js.map +1 -0
  47. package/dist/native.d.ts +94 -3
  48. package/dist/native.js +195 -73
  49. package/dist/native.js.map +1 -1
  50. package/dist/pagination.d.ts +141 -0
  51. package/dist/pagination.js +165 -0
  52. package/dist/pagination.js.map +1 -0
  53. package/dist/search-field.d.ts +100 -0
  54. package/dist/search-field.js +167 -0
  55. package/dist/search-field.js.map +1 -0
  56. package/dist/tag-input.d.ts +44 -0
  57. package/dist/tag-input.js +67 -0
  58. package/dist/tag-input.js.map +1 -0
  59. package/dist/video-player.d.ts +204 -0
  60. package/dist/video-player.js +371 -0
  61. package/dist/video-player.js.map +1 -0
  62. package/dist/video-trimmer.d.ts +142 -0
  63. package/dist/video-trimmer.js +193 -0
  64. package/dist/video-trimmer.js.map +1 -0
  65. package/package.json +233 -5
  66. package/registry/alert.json +1 -1
  67. package/registry/audio-player.json +282 -0
  68. package/registry/avatar.json +1 -1
  69. package/registry/badge.json +1 -1
  70. package/registry/button.json +1 -1
  71. package/registry/card.json +1 -1
  72. package/registry/checkbox.json +1 -1
  73. package/registry/chip-link.json +1 -1
  74. package/registry/chip.json +1 -1
  75. package/registry/combobox.json +475 -0
  76. package/registry/command.json +1 -1
  77. package/registry/confirm-button.json +1 -1
  78. package/registry/countdown.json +1 -1
  79. package/registry/data-table.json +500 -0
  80. package/registry/date-picker.json +978 -0
  81. package/registry/dialog.json +1 -1
  82. package/registry/dropdown-menu.json +1 -1
  83. package/registry/empty-state.json +1 -1
  84. package/registry/examples/audio-player/podcast.d.ts +4 -0
  85. package/registry/examples/audio-player/podcast.js +22 -0
  86. package/registry/examples/audio-player/podcast.tsx +19 -0
  87. package/registry/examples/audio-player/voice-note.d.ts +4 -0
  88. package/registry/examples/audio-player/voice-note.js +12 -0
  89. package/registry/examples/audio-player/voice-note.tsx +12 -0
  90. package/registry/examples/combobox/async.d.ts +4 -0
  91. package/registry/examples/combobox/async.js +23 -0
  92. package/registry/examples/combobox/async.tsx +22 -0
  93. package/registry/examples/combobox/creatable.d.ts +4 -0
  94. package/registry/examples/combobox/creatable.js +32 -0
  95. package/registry/examples/combobox/creatable.tsx +28 -0
  96. package/registry/examples/combobox/invalid.d.ts +4 -0
  97. package/registry/examples/combobox/invalid.js +23 -0
  98. package/registry/examples/combobox/invalid.tsx +17 -0
  99. package/registry/examples/combobox/multiple.d.ts +4 -0
  100. package/registry/examples/combobox/multiple.js +29 -0
  101. package/registry/examples/combobox/multiple.tsx +26 -0
  102. package/registry/examples/data-table/cards.d.ts +4 -0
  103. package/registry/examples/data-table/cards.js +21 -0
  104. package/registry/examples/data-table/cards.tsx +20 -0
  105. package/registry/examples/data-table/empty.d.ts +4 -0
  106. package/registry/examples/data-table/empty.js +26 -0
  107. package/registry/examples/data-table/empty.tsx +21 -0
  108. package/registry/examples/data-table/error.d.ts +4 -0
  109. package/registry/examples/data-table/error.js +28 -0
  110. package/registry/examples/data-table/error.tsx +29 -0
  111. package/registry/examples/data-table/jobs.d.ts +4 -0
  112. package/registry/examples/data-table/jobs.js +37 -0
  113. package/registry/examples/data-table/jobs.tsx +36 -0
  114. package/registry/examples/data-table/loading.d.ts +4 -0
  115. package/registry/examples/data-table/loading.js +16 -0
  116. package/registry/examples/data-table/loading.tsx +12 -0
  117. package/registry/examples/data-table/virtualized.d.ts +4 -0
  118. package/registry/examples/data-table/virtualized.js +21 -0
  119. package/registry/examples/data-table/virtualized.tsx +20 -0
  120. package/registry/examples/date-picker/calendar.d.ts +4 -0
  121. package/registry/examples/date-picker/calendar.js +14 -0
  122. package/registry/examples/date-picker/calendar.tsx +16 -0
  123. package/registry/examples/date-picker/french.d.ts +4 -0
  124. package/registry/examples/date-picker/french.js +20 -0
  125. package/registry/examples/date-picker/french.tsx +14 -0
  126. package/registry/examples/date-picker/open.d.ts +4 -0
  127. package/registry/examples/date-picker/open.js +11 -0
  128. package/registry/examples/date-picker/open.tsx +8 -0
  129. package/registry/examples/date-picker/range.d.ts +4 -0
  130. package/registry/examples/date-picker/range.js +29 -0
  131. package/registry/examples/date-picker/range.tsx +25 -0
  132. package/registry/examples/date-picker/schedule.d.ts +4 -0
  133. package/registry/examples/date-picker/schedule.js +26 -0
  134. package/registry/examples/date-picker/schedule.tsx +22 -0
  135. package/registry/examples/file-upload/images.d.ts +4 -0
  136. package/registry/examples/file-upload/images.js +32 -0
  137. package/registry/examples/file-upload/images.tsx +25 -0
  138. package/registry/examples/file-upload/states.d.ts +4 -0
  139. package/registry/examples/file-upload/states.js +28 -0
  140. package/registry/examples/file-upload/states.tsx +23 -0
  141. package/registry/examples/file-upload/tus.d.ts +4 -0
  142. package/registry/examples/file-upload/tus.js +23 -0
  143. package/registry/examples/file-upload/tus.tsx +26 -0
  144. package/registry/examples/file-upload/video.d.ts +4 -0
  145. package/registry/examples/file-upload/video.js +39 -0
  146. package/registry/examples/file-upload/video.tsx +36 -0
  147. package/registry/examples/filter-bar/address.d.ts +4 -0
  148. package/registry/examples/filter-bar/address.js +29 -0
  149. package/registry/examples/filter-bar/address.tsx +27 -0
  150. package/registry/examples/filter-bar/jobs.d.ts +4 -0
  151. package/registry/examples/filter-bar/jobs.js +37 -0
  152. package/registry/examples/filter-bar/jobs.tsx +37 -0
  153. package/registry/examples/filter-bar/menu.d.ts +4 -0
  154. package/registry/examples/filter-bar/menu.js +27 -0
  155. package/registry/examples/filter-bar/menu.tsx +23 -0
  156. package/registry/examples/image-cropper/avatar.d.ts +4 -0
  157. package/registry/examples/image-cropper/avatar.js +13 -0
  158. package/registry/examples/image-cropper/avatar.tsx +14 -0
  159. package/registry/examples/image-cropper/banner.d.ts +4 -0
  160. package/registry/examples/image-cropper/banner.js +11 -0
  161. package/registry/examples/image-cropper/banner.tsx +10 -0
  162. package/registry/examples/image-cropper/vertical-video.d.ts +4 -0
  163. package/registry/examples/image-cropper/vertical-video.js +12 -0
  164. package/registry/examples/image-cropper/vertical-video.tsx +16 -0
  165. package/registry/examples/media-capture/clip.d.ts +4 -0
  166. package/registry/examples/media-capture/clip.js +20 -0
  167. package/registry/examples/media-capture/clip.tsx +18 -0
  168. package/registry/examples/media-capture/native/photo.d.ts +4 -0
  169. package/registry/examples/media-capture/native/photo.dark.png +0 -0
  170. package/registry/examples/media-capture/native/photo.js +27 -0
  171. package/registry/examples/media-capture/native/photo.light.png +0 -0
  172. package/registry/examples/media-capture/native/photo.tsx +20 -0
  173. package/registry/examples/media-capture/profile-photo.d.ts +4 -0
  174. package/registry/examples/media-capture/profile-photo.js +24 -0
  175. package/registry/examples/media-capture/profile-photo.tsx +20 -0
  176. package/registry/examples/pagination/cursor.d.ts +4 -0
  177. package/registry/examples/pagination/cursor.js +24 -0
  178. package/registry/examples/pagination/cursor.tsx +20 -0
  179. package/registry/examples/pagination/links.d.ts +4 -0
  180. package/registry/examples/pagination/links.js +11 -0
  181. package/registry/examples/pagination/links.tsx +6 -0
  182. package/registry/examples/pagination/native/cursor.d.ts +4 -0
  183. package/registry/examples/pagination/native/cursor.dark.png +0 -0
  184. package/registry/examples/pagination/native/cursor.js +19 -0
  185. package/registry/examples/pagination/native/cursor.light.png +0 -0
  186. package/registry/examples/pagination/native/cursor.tsx +13 -0
  187. package/registry/examples/pagination/native/pages.d.ts +4 -0
  188. package/registry/examples/pagination/native/pages.dark.png +0 -0
  189. package/registry/examples/pagination/native/pages.js +21 -0
  190. package/registry/examples/pagination/native/pages.light.png +0 -0
  191. package/registry/examples/pagination/native/pages.tsx +14 -0
  192. package/registry/examples/pagination/results.d.ts +4 -0
  193. package/registry/examples/pagination/results.js +23 -0
  194. package/registry/examples/pagination/results.tsx +19 -0
  195. package/registry/examples/pagination/table-footer.d.ts +4 -0
  196. package/registry/examples/pagination/table-footer.js +31 -0
  197. package/registry/examples/pagination/table-footer.tsx +27 -0
  198. package/registry/examples/search-field/global.d.ts +4 -0
  199. package/registry/examples/search-field/global.js +19 -0
  200. package/registry/examples/search-field/global.tsx +15 -0
  201. package/registry/examples/search-field/native/default.d.ts +4 -0
  202. package/registry/examples/search-field/native/default.dark.png +0 -0
  203. package/registry/examples/search-field/native/default.js +13 -0
  204. package/registry/examples/search-field/native/default.light.png +0 -0
  205. package/registry/examples/search-field/native/default.tsx +7 -0
  206. package/registry/examples/search-field/suggestions.d.ts +4 -0
  207. package/registry/examples/search-field/suggestions.js +30 -0
  208. package/registry/examples/search-field/suggestions.tsx +27 -0
  209. package/registry/examples/search-field/toolbar.d.ts +4 -0
  210. package/registry/examples/search-field/toolbar.js +17 -0
  211. package/registry/examples/search-field/toolbar.tsx +21 -0
  212. package/registry/examples/tag-input/recipients.d.ts +4 -0
  213. package/registry/examples/tag-input/recipients.js +23 -0
  214. package/registry/examples/tag-input/recipients.tsx +20 -0
  215. package/registry/examples/tag-input/video-tags.d.ts +4 -0
  216. package/registry/examples/tag-input/video-tags.js +26 -0
  217. package/registry/examples/tag-input/video-tags.tsx +22 -0
  218. package/registry/examples/video-player/default.d.ts +4 -0
  219. package/registry/examples/video-player/default.js +12 -0
  220. package/registry/examples/video-player/default.tsx +8 -0
  221. package/registry/examples/video-player/gated.d.ts +4 -0
  222. package/registry/examples/video-player/gated.js +26 -0
  223. package/registry/examples/video-player/gated.tsx +23 -0
  224. package/registry/examples/video-player/native/default.d.ts +4 -0
  225. package/registry/examples/video-player/native/default.dark.png +0 -0
  226. package/registry/examples/video-player/native/default.js +18 -0
  227. package/registry/examples/video-player/native/default.light.png +0 -0
  228. package/registry/examples/video-player/native/default.tsx +12 -0
  229. package/registry/examples/video-player/signed-source.d.ts +4 -0
  230. package/registry/examples/video-player/signed-source.js +16 -0
  231. package/registry/examples/video-player/signed-source.tsx +15 -0
  232. package/registry/examples/video-player/vertical.d.ts +4 -0
  233. package/registry/examples/video-player/vertical.js +12 -0
  234. package/registry/examples/video-player/vertical.tsx +12 -0
  235. package/registry/examples/video-trimmer/custom.d.ts +4 -0
  236. package/registry/examples/video-trimmer/custom.js +24 -0
  237. package/registry/examples/video-trimmer/custom.tsx +26 -0
  238. package/registry/examples/video-trimmer/filmstrip.d.ts +4 -0
  239. package/registry/examples/video-trimmer/filmstrip.js +15 -0
  240. package/registry/examples/video-trimmer/filmstrip.tsx +13 -0
  241. package/registry/examples/video-trimmer/playhead.d.ts +4 -0
  242. package/registry/examples/video-trimmer/playhead.js +15 -0
  243. package/registry/examples/video-trimmer/playhead.tsx +13 -0
  244. package/registry/field.json +1 -1
  245. package/registry/file-upload.json +471 -0
  246. package/registry/filter-bar.json +347 -0
  247. package/registry/glow-card.json +1 -1
  248. package/registry/image-cropper.json +313 -0
  249. package/registry/index.json +255 -1
  250. package/registry/iso.json +1 -1
  251. package/registry/kbd.json +1 -1
  252. package/registry/loader.json +1 -1
  253. package/registry/marquee.json +1 -1
  254. package/registry/mascots.json +1 -1
  255. package/registry/media-capture.json +347 -0
  256. package/registry/meter.json +3 -3
  257. package/registry/nav-bar.json +1 -1
  258. package/registry/number-ticker.json +1 -1
  259. package/registry/page-header.json +1 -1
  260. package/registry/pagination.json +475 -0
  261. package/registry/popover.json +1 -1
  262. package/registry/progress.json +5 -5
  263. package/registry/radio-group.json +1 -1
  264. package/registry/search-field.json +436 -0
  265. package/registry/section-backdrop.json +1 -1
  266. package/registry/separator.json +1 -1
  267. package/registry/skeleton.json +1 -1
  268. package/registry/slider.json +1 -1
  269. package/registry/slot.json +1 -1
  270. package/registry/spinner.json +1 -1
  271. package/registry/stat.json +1 -1
  272. package/registry/stepper.json +1 -1
  273. package/registry/switch.json +1 -1
  274. package/registry/tabs.json +1 -1
  275. package/registry/tag-input.json +363 -0
  276. package/registry/theme.json +1 -1
  277. package/registry/toast.json +1 -1
  278. package/registry/tooltip.json +1 -1
  279. package/registry/video-player.json +598 -0
  280. package/registry/video-trimmer.json +385 -0
@@ -0,0 +1,290 @@
1
+ "use client";
2
+ import {
3
+ useControllable
4
+ } from "./chunk-EUPTXKH7.js";
5
+ import {
6
+ SortGlyph
7
+ } from "./chunk-YX6CNVJA.js";
8
+
9
+ // src/data-table/data-table.tsx
10
+ import * as React from "react";
11
+ import { tv as tv2 } from "tailwind-variants";
12
+
13
+ // src/checkbox/checkbox.tsx
14
+ import { Checkbox as CheckboxPrimitive } from "radix-ui";
15
+ import { tv } from "tailwind-variants";
16
+ import { jsx, jsxs } from "react/jsx-runtime";
17
+ var checkbox = tv({
18
+ slots: {
19
+ root: "peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-border-strong bg-surface-1 text-on-accent transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=indeterminate]:border-accent data-[state=indeterminate]:bg-accent aria-invalid:border-danger aria-invalid:ring-danger/30",
20
+ indicator: "flex items-center justify-center",
21
+ label: "flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-60"
22
+ }
23
+ });
24
+ function Check() {
25
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
26
+ }
27
+ function Dash() {
28
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M5 12h14" }) });
29
+ }
30
+ function Checkbox({ invalid, className, children, ...props }) {
31
+ const s = checkbox();
32
+ const box = /* @__PURE__ */ jsx(
33
+ CheckboxPrimitive.Root,
34
+ {
35
+ "aria-invalid": invalid || void 0,
36
+ "data-invalid": invalid ? "" : void 0,
37
+ className: s.root({ className: children ? "mt-0.5" : className }),
38
+ ...props,
39
+ children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: s.indicator(), children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx(Dash, {}) : /* @__PURE__ */ jsx(Check, {}) })
40
+ }
41
+ );
42
+ if (!children) return box;
43
+ return /* @__PURE__ */ jsxs("label", { className: s.label({ className }), children: [
44
+ box,
45
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children })
46
+ ] });
47
+ }
48
+
49
+ // src/data-table/data-table.tsx
50
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
51
+ var dataTable = tv2({
52
+ slots: {
53
+ root: "@container w-full overflow-hidden rounded-xl border border-border-default bg-surface-1",
54
+ scroller: "w-full overflow-x-auto",
55
+ table: "w-full border-collapse text-left text-sm text-fg",
56
+ caption: "px-4 pt-4 pb-2 text-left text-sm font-semibold text-fg",
57
+ thead: "bg-surface-2/60",
58
+ headRow: "border-b border-border-default",
59
+ th: "whitespace-nowrap px-4 py-3 text-xs font-semibold text-fg-secondary",
60
+ sortButton: "-mx-1.5 inline-flex items-center gap-1 rounded-md px-1.5 py-1 hover:bg-surface-3 hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[pressed=true]:text-fg",
61
+ tbody: "",
62
+ tr: "border-b border-border-subtle transition-colors last:border-b-0 hover:bg-surface-2/50 data-[state=selected]:bg-accent-soft",
63
+ td: "px-4 py-3 align-middle",
64
+ select: "w-10",
65
+ message: "px-4 py-10 text-center text-sm text-fg-secondary",
66
+ skeleton: "h-4 w-full max-w-40 animate-pulse rounded bg-surface-3 motion-reduce:animate-none",
67
+ footer: "border-t border-border-default px-4 py-3"
68
+ },
69
+ variants: {
70
+ layout: {
71
+ table: {},
72
+ // Below 36rem of container: cards. The sortable headers stay, as a row of sort buttons above the cards.
73
+ auto: {
74
+ table: "@max-xl:block",
75
+ caption: "@max-xl:block",
76
+ thead: "@max-xl:sr-only @max-xl:bg-transparent @max-xl:has-[[data-keep]]:not-sr-only @max-xl:has-[[data-keep]]:block",
77
+ headRow: "@max-xl:flex @max-xl:flex-wrap @max-xl:items-center @max-xl:gap-2 @max-xl:px-3 @max-xl:py-2",
78
+ th: "@max-xl:sr-only @max-xl:data-[keep]:not-sr-only @max-xl:data-[keep]:block @max-xl:p-0",
79
+ tbody: "@max-xl:grid @max-xl:gap-3 @max-xl:p-3",
80
+ tr: "@max-xl:relative @max-xl:grid @max-xl:gap-1.5 @max-xl:rounded-xl @max-xl:border @max-xl:border-border-default @max-xl:bg-surface-0 @max-xl:p-4 @max-xl:last:border-b",
81
+ td: "@max-xl:flex @max-xl:items-baseline @max-xl:justify-between @max-xl:gap-4 @max-xl:p-0 @max-xl:text-right @max-xl:before:shrink-0 @max-xl:before:text-xs @max-xl:before:font-semibold @max-xl:before:text-fg-secondary @max-xl:before:content-[attr(data-label)] @max-xl:data-[card=title]:order-first @max-xl:data-[card=title]:pr-8 @max-xl:data-[card=title]:text-left @max-xl:data-[card=title]:text-base @max-xl:data-[card=title]:font-semibold @max-xl:data-[card=title]:before:content-none @max-xl:data-[card=hidden]:hidden @max-xl:data-[card=message]:block @max-xl:data-[card=message]:text-center @max-xl:data-[card=message]:before:content-none",
82
+ select: "@max-xl:absolute @max-xl:right-3 @max-xl:top-3 @max-xl:w-auto @max-xl:before:content-none"
83
+ },
84
+ cards: {
85
+ table: "block",
86
+ caption: "block",
87
+ thead: "sr-only bg-transparent has-[[data-keep]]:not-sr-only has-[[data-keep]]:block",
88
+ headRow: "flex flex-wrap items-center gap-2 px-3 py-2",
89
+ th: "sr-only p-0 data-[keep]:not-sr-only data-[keep]:block",
90
+ tbody: "grid gap-3 p-3",
91
+ tr: "relative grid gap-1.5 rounded-xl border border-border-default bg-surface-0 p-4 last:border-b",
92
+ td: "flex items-baseline justify-between gap-4 p-0 text-right before:shrink-0 before:text-xs before:font-semibold before:text-fg-secondary before:content-[attr(data-label)] data-[card=title]:order-first data-[card=title]:pr-8 data-[card=title]:text-left data-[card=title]:text-base data-[card=title]:font-semibold data-[card=title]:before:content-none data-[card=hidden]:hidden data-[card=message]:block data-[card=message]:text-center data-[card=message]:before:content-none",
93
+ select: "absolute right-3 top-3 w-auto before:content-none"
94
+ }
95
+ },
96
+ density: {
97
+ comfortable: {},
98
+ compact: { th: "py-2", td: "py-1.5" }
99
+ }
100
+ },
101
+ defaultVariants: { layout: "auto", density: "comfortable" }
102
+ });
103
+ var dataTableLabels = {
104
+ selectAll: "Select all rows",
105
+ selectRow: (name) => `Select ${name}`,
106
+ loading: "Loading",
107
+ empty: "Nothing to show"
108
+ };
109
+ function compare(a, b) {
110
+ if (a == null || a === "") return b == null || b === "" ? 0 : 1;
111
+ if (b == null || b === "") return -1;
112
+ if (a instanceof Date || b instanceof Date) return Number(a) - Number(b);
113
+ if (typeof a === "number" && typeof b === "number") return a - b;
114
+ return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
115
+ }
116
+ var nextSort = (sort, column) => sort?.column !== column ? { column, direction: "ascending" } : sort.direction === "ascending" ? { column, direction: "descending" } : null;
117
+ var ALIGN = { start: "text-left", center: "text-center", end: "text-right" };
118
+ function DataTable({
119
+ rows,
120
+ columns,
121
+ getRowId,
122
+ caption,
123
+ showCaption,
124
+ sort: sortProp,
125
+ defaultSort = null,
126
+ onSortChange,
127
+ manualSort,
128
+ selectable,
129
+ selected: selectedProp,
130
+ defaultSelected = [],
131
+ onSelectedChange,
132
+ rowLabel,
133
+ loading,
134
+ loadingRows = 5,
135
+ error,
136
+ empty,
137
+ layout = "auto",
138
+ density,
139
+ virtualize,
140
+ footer,
141
+ labels: given,
142
+ className
143
+ }) {
144
+ const labels = { ...dataTableLabels, ...given };
145
+ const s = dataTable({ layout: virtualize ? "table" : layout, density });
146
+ const [sort, setSort] = useControllable(sortProp, defaultSort, onSortChange);
147
+ const [selected, setSelected] = useControllable(selectedProp, defaultSelected, onSelectedChange);
148
+ const [scrollTop, setScrollTop] = React.useState(0);
149
+ const valueOf = (column, row) => column.value ? column.value(row) : row[column.id];
150
+ const sorted = React.useMemo(() => {
151
+ const column = sort && columns.find((c) => c.id === sort.column);
152
+ if (!column || manualSort) return rows;
153
+ const factor = sort.direction === "ascending" ? 1 : -1;
154
+ return [...rows].sort((a, b) => factor * compare(valueOf(column, a), valueOf(column, b)));
155
+ }, [rows, columns, sort, manualSort]);
156
+ const ids = sorted.map(getRowId);
157
+ const chosen = new Set(selected);
158
+ const allChosen = ids.length > 0 && ids.every((id) => chosen.has(id));
159
+ const someChosen = ids.some((id) => chosen.has(id));
160
+ const toggleAll = () => setSelected(allChosen ? selected.filter((id) => !ids.includes(id)) : [.../* @__PURE__ */ new Set([...selected, ...ids])]);
161
+ const toggle = (id) => setSelected(chosen.has(id) ? selected.filter((x) => x !== id) : [...selected, id]);
162
+ const span = columns.length + (selectable ? 1 : 0);
163
+ let windowed = sorted;
164
+ let before = 0;
165
+ let after = 0;
166
+ let offset = 0;
167
+ if (virtualize && !loading) {
168
+ const overscan = virtualize.overscan ?? 6;
169
+ const start = Math.max(0, Math.floor(scrollTop / virtualize.rowHeight) - overscan);
170
+ const end = Math.min(sorted.length, Math.ceil((scrollTop + virtualize.height) / virtualize.rowHeight) + overscan);
171
+ windowed = sorted.slice(start, end);
172
+ before = start * virtualize.rowHeight;
173
+ after = (sorted.length - end) * virtualize.rowHeight;
174
+ offset = start;
175
+ }
176
+ const message = (content, alert) => /* @__PURE__ */ jsx2("tr", { role: "row", className: s.tr({ className: "hover:bg-transparent" }), children: /* @__PURE__ */ jsx2("td", { role: "cell", colSpan: span, "data-card": "message", className: s.td({ className: s.message() }), children: alert ? /* @__PURE__ */ jsx2("div", { role: "alert", children: content }) : content }) });
177
+ let body;
178
+ if (loading) {
179
+ body = Array.from({ length: loadingRows }, (_, i) => /* @__PURE__ */ jsxs2("tr", { role: "row", "aria-hidden": true, className: s.tr(), children: [
180
+ selectable && /* @__PURE__ */ jsx2("td", { role: "cell", className: s.td({ className: s.select() }) }),
181
+ columns.map((column) => /* @__PURE__ */ jsx2("td", { role: "cell", "data-card": column.card === "title" ? "title" : column.card === "hidden" ? "hidden" : void 0, className: s.td(), children: /* @__PURE__ */ jsx2("div", { className: s.skeleton() }) }, column.id))
182
+ ] }, `loading-${i}`));
183
+ } else if (error) body = message(error, true);
184
+ else if (sorted.length === 0) body = message(empty ?? labels.empty);
185
+ else {
186
+ body = windowed.map((row, i) => {
187
+ const id = getRowId(row);
188
+ const isChosen = chosen.has(id);
189
+ return /* @__PURE__ */ jsxs2(
190
+ "tr",
191
+ {
192
+ role: "row",
193
+ "aria-rowindex": virtualize ? offset + i + 2 : void 0,
194
+ "data-state": isChosen ? "selected" : void 0,
195
+ className: s.tr(),
196
+ style: virtualize ? { height: virtualize.rowHeight } : void 0,
197
+ children: [
198
+ selectable && /* @__PURE__ */ jsx2("td", { role: "cell", className: s.td({ className: s.select() }), children: /* @__PURE__ */ jsx2(Checkbox, { checked: isChosen, onCheckedChange: () => toggle(id), "aria-label": labels.selectRow(rowLabel ? rowLabel(row) : id) }) }),
199
+ columns.map((column) => /* @__PURE__ */ jsx2(
200
+ "td",
201
+ {
202
+ role: "cell",
203
+ "data-label": column.header,
204
+ "data-card": column.card === "title" ? "title" : column.card === "hidden" ? "hidden" : void 0,
205
+ className: s.td({ className: ALIGN[column.align ?? "start"] }),
206
+ children: column.cell ? column.cell(row) : String(valueOf(column, row) ?? "")
207
+ },
208
+ column.id
209
+ ))
210
+ ]
211
+ },
212
+ id
213
+ );
214
+ });
215
+ }
216
+ const table = /* @__PURE__ */ jsxs2(
217
+ "table",
218
+ {
219
+ role: "table",
220
+ "aria-busy": loading || void 0,
221
+ "aria-rowcount": virtualize ? sorted.length + 1 : void 0,
222
+ className: s.table(),
223
+ children: [
224
+ /* @__PURE__ */ jsxs2("caption", { className: showCaption ? s.caption() : "sr-only", children: [
225
+ caption,
226
+ loading ? /* @__PURE__ */ jsx2("span", { className: "sr-only", children: ` \u2014 ${labels.loading}` }) : null
227
+ ] }),
228
+ /* @__PURE__ */ jsx2("thead", { role: "rowgroup", className: s.thead({ className: virtualize ? "sticky top-0 z-10 bg-surface-2" : void 0 }), children: /* @__PURE__ */ jsxs2("tr", { role: "row", "aria-rowindex": virtualize ? 1 : void 0, className: s.headRow(), children: [
229
+ selectable && /* @__PURE__ */ jsx2("th", { role: "columnheader", scope: "col", "data-keep": "", className: s.th({ className: s.select() }), children: /* @__PURE__ */ jsx2(
230
+ Checkbox,
231
+ {
232
+ checked: allChosen ? true : someChosen ? "indeterminate" : false,
233
+ onCheckedChange: toggleAll,
234
+ disabled: loading || ids.length === 0,
235
+ "aria-label": labels.selectAll
236
+ }
237
+ ) }),
238
+ columns.map((column) => {
239
+ const direction = sort?.column === column.id ? sort.direction : void 0;
240
+ return /* @__PURE__ */ jsx2(
241
+ "th",
242
+ {
243
+ role: "columnheader",
244
+ scope: "col",
245
+ "aria-sort": column.sortable ? direction ?? "none" : void 0,
246
+ "data-keep": column.sortable ? "" : void 0,
247
+ className: s.th({ className: ALIGN[column.align ?? "start"] }),
248
+ style: column.width ? { width: column.width } : void 0,
249
+ children: column.sortable ? /* @__PURE__ */ jsxs2("button", { type: "button", "aria-pressed": Boolean(direction), className: s.sortButton(), onClick: () => setSort(nextSort(sort, column.id)), children: [
250
+ column.header,
251
+ /* @__PURE__ */ jsx2(SortGlyph, { direction, className: "h-3.5 w-3.5" })
252
+ ] }) : column.headerHidden ? /* @__PURE__ */ jsx2("span", { className: "sr-only", children: column.header }) : column.header
253
+ },
254
+ column.id
255
+ );
256
+ })
257
+ ] }) }),
258
+ /* @__PURE__ */ jsxs2("tbody", { role: "rowgroup", className: s.tbody(), children: [
259
+ before > 0 && /* @__PURE__ */ jsx2("tr", { "aria-hidden": true, style: { height: before }, children: /* @__PURE__ */ jsx2("td", { colSpan: span }) }),
260
+ body,
261
+ after > 0 && /* @__PURE__ */ jsx2("tr", { "aria-hidden": true, style: { height: after }, children: /* @__PURE__ */ jsx2("td", { colSpan: span }) })
262
+ ] })
263
+ ]
264
+ }
265
+ );
266
+ return /* @__PURE__ */ jsxs2("div", { className: s.root({ className }), children: [
267
+ virtualize ? (
268
+ // A scrolling region the keyboard can reach: Tab lands on it, the arrows scroll it.
269
+ /* @__PURE__ */ jsx2(
270
+ "div",
271
+ {
272
+ tabIndex: 0,
273
+ role: "region",
274
+ "aria-label": caption,
275
+ className: s.scroller({ className: "overflow-y-auto focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring" }),
276
+ style: { height: virtualize.height },
277
+ onScroll: (event) => setScrollTop(event.currentTarget.scrollTop),
278
+ children: table
279
+ }
280
+ )
281
+ ) : /* @__PURE__ */ jsx2("div", { className: s.scroller(), children: table }),
282
+ footer ? /* @__PURE__ */ jsx2("div", { className: s.footer(), children: footer }) : null
283
+ ] });
284
+ }
285
+ export {
286
+ DataTable,
287
+ dataTable,
288
+ dataTableLabels
289
+ };
290
+ //# sourceMappingURL=data-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data-table/data-table.tsx","../src/checkbox/checkbox.tsx"],"sourcesContent":["// Client (sort and selection state, the windowing of long lists). A real `<table>` with a caption and column headers\n// (`scope=\"col\"`, `aria-sort` on the sorted one) that turns into a stack of cards in a narrow container — one DOM, the\n// roles written out so that the change of `display` never loses the table's semantics. Selection through\n// `@krizaka/ui/checkbox`; loading, empty and error states in the body; optional windowing for thousands of rows.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { Checkbox } from \"../checkbox\";\nimport { SortGlyph } from \"../glyphs\";\nimport { useControllable } from \"../media\";\n\nexport const dataTable = tv({\n slots: {\n root: \"@container w-full overflow-hidden rounded-xl border border-border-default bg-surface-1\",\n scroller: \"w-full overflow-x-auto\",\n table: \"w-full border-collapse text-left text-sm text-fg\",\n caption: \"px-4 pt-4 pb-2 text-left text-sm font-semibold text-fg\",\n thead: \"bg-surface-2/60\",\n headRow: \"border-b border-border-default\",\n th: \"whitespace-nowrap px-4 py-3 text-xs font-semibold text-fg-secondary\",\n sortButton:\n \"-mx-1.5 inline-flex items-center gap-1 rounded-md px-1.5 py-1 hover:bg-surface-3 hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[pressed=true]:text-fg\",\n tbody: \"\",\n tr: \"border-b border-border-subtle transition-colors last:border-b-0 hover:bg-surface-2/50 data-[state=selected]:bg-accent-soft\",\n td: \"px-4 py-3 align-middle\",\n select: \"w-10\",\n message: \"px-4 py-10 text-center text-sm text-fg-secondary\",\n skeleton: \"h-4 w-full max-w-40 animate-pulse rounded bg-surface-3 motion-reduce:animate-none\",\n footer: \"border-t border-border-default px-4 py-3\",\n },\n variants: {\n layout: {\n table: {},\n // Below 36rem of container: cards. The sortable headers stay, as a row of sort buttons above the cards.\n auto: {\n table: \"@max-xl:block\",\n caption: \"@max-xl:block\",\n thead: \"@max-xl:sr-only @max-xl:bg-transparent @max-xl:has-[[data-keep]]:not-sr-only @max-xl:has-[[data-keep]]:block\",\n headRow: \"@max-xl:flex @max-xl:flex-wrap @max-xl:items-center @max-xl:gap-2 @max-xl:px-3 @max-xl:py-2\",\n th: \"@max-xl:sr-only @max-xl:data-[keep]:not-sr-only @max-xl:data-[keep]:block @max-xl:p-0\",\n tbody: \"@max-xl:grid @max-xl:gap-3 @max-xl:p-3\",\n tr: \"@max-xl:relative @max-xl:grid @max-xl:gap-1.5 @max-xl:rounded-xl @max-xl:border @max-xl:border-border-default @max-xl:bg-surface-0 @max-xl:p-4 @max-xl:last:border-b\",\n td:\n \"@max-xl:flex @max-xl:items-baseline @max-xl:justify-between @max-xl:gap-4 @max-xl:p-0 @max-xl:text-right \" +\n \"@max-xl:before:shrink-0 @max-xl:before:text-xs @max-xl:before:font-semibold @max-xl:before:text-fg-secondary @max-xl:before:content-[attr(data-label)] \" +\n \"@max-xl:data-[card=title]:order-first @max-xl:data-[card=title]:pr-8 @max-xl:data-[card=title]:text-left @max-xl:data-[card=title]:text-base @max-xl:data-[card=title]:font-semibold @max-xl:data-[card=title]:before:content-none \" +\n \"@max-xl:data-[card=hidden]:hidden @max-xl:data-[card=message]:block @max-xl:data-[card=message]:text-center @max-xl:data-[card=message]:before:content-none\",\n select: \"@max-xl:absolute @max-xl:right-3 @max-xl:top-3 @max-xl:w-auto @max-xl:before:content-none\",\n },\n cards: {\n table: \"block\",\n caption: \"block\",\n thead: \"sr-only bg-transparent has-[[data-keep]]:not-sr-only has-[[data-keep]]:block\",\n headRow: \"flex flex-wrap items-center gap-2 px-3 py-2\",\n th: \"sr-only p-0 data-[keep]:not-sr-only data-[keep]:block\",\n tbody: \"grid gap-3 p-3\",\n tr: \"relative grid gap-1.5 rounded-xl border border-border-default bg-surface-0 p-4 last:border-b\",\n td:\n \"flex items-baseline justify-between gap-4 p-0 text-right before:shrink-0 before:text-xs before:font-semibold before:text-fg-secondary before:content-[attr(data-label)] \" +\n \"data-[card=title]:order-first data-[card=title]:pr-8 data-[card=title]:text-left data-[card=title]:text-base data-[card=title]:font-semibold data-[card=title]:before:content-none \" +\n \"data-[card=hidden]:hidden data-[card=message]:block data-[card=message]:text-center data-[card=message]:before:content-none\",\n select: \"absolute right-3 top-3 w-auto before:content-none\",\n },\n },\n density: {\n comfortable: {},\n compact: { th: \"py-2\", td: \"py-1.5\" },\n },\n },\n defaultVariants: { layout: \"auto\", density: \"comfortable\" },\n});\n\nexport type SortDirection = \"ascending\" | \"descending\";\nexport type DataTableSort = { column: string; direction: SortDirection } | null;\ntype Sortable = string | number | boolean | Date | null | undefined;\n\nexport type DataTableColumn<T> = {\n /** A key of the column (and of the row, for the default cell and sort). */\n id: string;\n /** The column's name, passed translated: the header, and the label of the value in a card. */\n header: string;\n /** What a cell shows. Default: `value(row)`, or `row[id]`. */\n cell?: (row: T) => React.ReactNode;\n /** The value sorted on (and shown by default): a string, a number, a date. Default `row[id]`. */\n value?: (row: T) => Sortable;\n /** The header becomes a sort button (ascending → descending → none). */\n sortable?: boolean;\n /** Text alignment: `end` for amounts and counts. */\n align?: \"start\" | \"center\" | \"end\";\n /** A CSS width (`\"8rem\"`, `\"30%\"`). */\n width?: string;\n /** In a card: `title` (the heading of the card), `label` (default: \"Header value\"), `hidden`. */\n card?: \"title\" | \"label\" | \"hidden\";\n /** Hides the header visually (an actions column), keeping it for screen readers. */\n headerHidden?: boolean;\n};\n\nexport type DataTableLabels = {\n /** The checkbox of the header (\"Select all rows\"). */\n selectAll: string;\n /** The checkbox of a row: `(name) => \"Select \" + name`, the name from `rowLabel`. */\n selectRow: (name: string) => string;\n /** Read while the rows load (\"Loading\"). */\n loading: string;\n /** The default empty state (\"Nothing to show\"). */\n empty: string;\n};\n\nexport const dataTableLabels: DataTableLabels = {\n selectAll: \"Select all rows\",\n selectRow: (name) => `Select ${name}`,\n loading: \"Loading\",\n empty: \"Nothing to show\",\n};\n\nexport type DataTableProps<T> = {\n /** The rows, in the order the server gave (sorted here unless `manualSort`). */\n rows: readonly T[];\n /** The columns, in order. */\n columns: readonly DataTableColumn<T>[];\n /** A stable id per row: the React key and the selection's value. */\n getRowId: (row: T) => string;\n /** What the table lists (\"Jobs\", \"Your videos\"): its `<caption>`, hidden unless `showCaption`. */\n caption: string;\n /** Shows the caption above the table. */\n showCaption?: boolean;\n /** The sorted column (controlled), `null` for none. */\n sort?: DataTableSort;\n /** The sort at first, uncontrolled. */\n defaultSort?: DataTableSort;\n /** Called when a header asks for a new sort. */\n onSortChange?: (sort: DataTableSort) => void;\n /** The server sorts (`onSortChange` fetches): the rows are shown as given. */\n manualSort?: boolean;\n /** Adds a checkbox per row and one in the header. */\n selectable?: boolean;\n /** The ids selected (controlled). */\n selected?: readonly string[];\n /** The ids selected at first, uncontrolled. */\n defaultSelected?: readonly string[];\n /** Called with the new selection. */\n onSelectedChange?: (selected: string[]) => void;\n /** The name of a row in its checkbox's label (default: its id). */\n rowLabel?: (row: T) => string;\n /** Rows are loading: skeleton rows (`loadingRows` of them) and `aria-busy`. */\n loading?: boolean;\n /** How many skeleton rows while loading. Default 5. */\n loadingRows?: number;\n /** A failure, shown in place of the rows (an `Alert`, a retry button); announced. */\n error?: React.ReactNode;\n /** Shown when there is no row (an `EmptyState`). Default: `labels.empty`. */\n empty?: React.ReactNode;\n /** `auto` (default): a table, cards below 36rem of container width. `table` or `cards` to force one. */\n layout?: \"auto\" | \"table\" | \"cards\";\n /** comfortable (default) · compact. */\n density?: \"comfortable\" | \"compact\";\n /** Renders only the rows in view (fixed `rowHeight`, a scrolling body of `height` px). Forces the table layout. */\n virtualize?: { rowHeight: number; height: number; overscan?: number };\n /** Under the table: a `Pagination`, a total. */\n footer?: React.ReactNode;\n /** The words, passed translated; English by default. */\n labels?: Partial<DataTableLabels>;\n /** Classes merged on the root. */\n className?: string;\n};\n\nfunction compare(a: Sortable, b: Sortable): number {\n if (a == null || a === \"\") return b == null || b === \"\" ? 0 : 1;\n if (b == null || b === \"\") return -1;\n if (a instanceof Date || b instanceof Date) return Number(a) - Number(b);\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n return String(a).localeCompare(String(b), undefined, { numeric: true, sensitivity: \"base\" });\n}\n\nconst nextSort = (sort: DataTableSort, column: string): DataTableSort =>\n sort?.column !== column ? { column, direction: \"ascending\" } : sort.direction === \"ascending\" ? { column, direction: \"descending\" } : null;\n\nconst ALIGN = { start: \"text-left\", center: \"text-center\", end: \"text-right\" } as const;\n\n/** A table of records: sort, selection, loading / empty / error, cards on a phone, windowing for long lists. */\nexport function DataTable<T>({\n rows,\n columns,\n getRowId,\n caption,\n showCaption,\n sort: sortProp,\n defaultSort = null,\n onSortChange,\n manualSort,\n selectable,\n selected: selectedProp,\n defaultSelected = [],\n onSelectedChange,\n rowLabel,\n loading,\n loadingRows = 5,\n error,\n empty,\n layout = \"auto\",\n density,\n virtualize,\n footer,\n labels: given,\n className,\n}: DataTableProps<T>) {\n const labels = { ...dataTableLabels, ...given };\n const s = dataTable({ layout: virtualize ? \"table\" : layout, density });\n const [sort, setSort] = useControllable<DataTableSort>(sortProp, defaultSort, onSortChange);\n const [selected, setSelected] = useControllable<readonly string[]>(selectedProp, defaultSelected, onSelectedChange as (next: readonly string[]) => void);\n const [scrollTop, setScrollTop] = React.useState(0);\n\n const valueOf = (column: DataTableColumn<T>, row: T): Sortable =>\n column.value ? column.value(row) : ((row as Record<string, unknown>)[column.id] as Sortable);\n\n const sorted = React.useMemo(() => {\n const column = sort && columns.find((c) => c.id === sort.column);\n if (!column || manualSort) return rows;\n const factor = sort.direction === \"ascending\" ? 1 : -1;\n return [...rows].sort((a, b) => factor * compare(valueOf(column, a), valueOf(column, b)));\n // eslint-disable-next-line react-hooks/exhaustive-deps -- valueOf only reads `column`\n }, [rows, columns, sort, manualSort]);\n\n const ids = sorted.map(getRowId);\n const chosen = new Set(selected);\n const allChosen = ids.length > 0 && ids.every((id) => chosen.has(id));\n const someChosen = ids.some((id) => chosen.has(id));\n const toggleAll = () => setSelected(allChosen ? selected.filter((id) => !ids.includes(id)) : [...new Set([...selected, ...ids])]);\n const toggle = (id: string) => setSelected(chosen.has(id) ? selected.filter((x) => x !== id) : [...selected, id]);\n\n const span = columns.length + (selectable ? 1 : 0);\n let windowed = sorted;\n let before = 0;\n let after = 0;\n let offset = 0;\n if (virtualize && !loading) {\n const overscan = virtualize.overscan ?? 6;\n const start = Math.max(0, Math.floor(scrollTop / virtualize.rowHeight) - overscan);\n const end = Math.min(sorted.length, Math.ceil((scrollTop + virtualize.height) / virtualize.rowHeight) + overscan);\n windowed = sorted.slice(start, end);\n before = start * virtualize.rowHeight;\n after = (sorted.length - end) * virtualize.rowHeight;\n offset = start;\n }\n\n const message = (content: React.ReactNode, alert?: boolean) => (\n <tr role=\"row\" className={s.tr({ className: \"hover:bg-transparent\" })}>\n <td role=\"cell\" colSpan={span} data-card=\"message\" className={s.td({ className: s.message() })}>\n {alert ? <div role=\"alert\">{content}</div> : content}\n </td>\n </tr>\n );\n\n let body: React.ReactNode;\n if (loading) {\n body = Array.from({ length: loadingRows }, (_, i) => (\n <tr role=\"row\" key={`loading-${i}`} aria-hidden className={s.tr()}>\n {selectable && <td role=\"cell\" className={s.td({ className: s.select() })} />}\n {columns.map((column) => (\n <td role=\"cell\" key={column.id} data-card={column.card === \"title\" ? \"title\" : column.card === \"hidden\" ? \"hidden\" : undefined} className={s.td()}>\n <div className={s.skeleton()} />\n </td>\n ))}\n </tr>\n ));\n } else if (error) body = message(error, true);\n else if (sorted.length === 0) body = message(empty ?? labels.empty);\n else {\n body = windowed.map((row, i) => {\n const id = getRowId(row);\n const isChosen = chosen.has(id);\n return (\n <tr\n role=\"row\"\n key={id}\n aria-rowindex={virtualize ? offset + i + 2 : undefined}\n data-state={isChosen ? \"selected\" : undefined}\n className={s.tr()}\n style={virtualize ? { height: virtualize.rowHeight } : undefined}\n >\n {selectable && (\n <td role=\"cell\" className={s.td({ className: s.select() })}>\n <Checkbox checked={isChosen} onCheckedChange={() => toggle(id)} aria-label={labels.selectRow(rowLabel ? rowLabel(row) : id)} />\n </td>\n )}\n {columns.map((column) => (\n <td\n role=\"cell\"\n key={column.id}\n data-label={column.header}\n data-card={column.card === \"title\" ? \"title\" : column.card === \"hidden\" ? \"hidden\" : undefined}\n className={s.td({ className: ALIGN[column.align ?? \"start\"] })}\n >\n {column.cell ? column.cell(row) : String(valueOf(column, row) ?? \"\")}\n </td>\n ))}\n </tr>\n );\n });\n }\n\n const table = (\n <table\n role=\"table\"\n aria-busy={loading || undefined}\n aria-rowcount={virtualize ? sorted.length + 1 : undefined}\n className={s.table()}\n >\n <caption className={showCaption ? s.caption() : \"sr-only\"}>\n {caption}\n {loading ? <span className=\"sr-only\">{` — ${labels.loading}`}</span> : null}\n </caption>\n <thead role=\"rowgroup\" className={s.thead({ className: virtualize ? \"sticky top-0 z-10 bg-surface-2\" : undefined })}>\n <tr role=\"row\" aria-rowindex={virtualize ? 1 : undefined} className={s.headRow()}>\n {selectable && (\n <th role=\"columnheader\" scope=\"col\" data-keep=\"\" className={s.th({ className: s.select() })}>\n <Checkbox\n checked={allChosen ? true : someChosen ? \"indeterminate\" : false}\n onCheckedChange={toggleAll}\n disabled={loading || ids.length === 0}\n aria-label={labels.selectAll}\n />\n </th>\n )}\n {columns.map((column) => {\n const direction = sort?.column === column.id ? sort.direction : undefined;\n return (\n <th\n role=\"columnheader\"\n scope=\"col\"\n key={column.id}\n aria-sort={column.sortable ? (direction ?? \"none\") : undefined}\n data-keep={column.sortable ? \"\" : undefined}\n className={s.th({ className: ALIGN[column.align ?? \"start\"] })}\n style={column.width ? { width: column.width } : undefined}\n >\n {column.sortable ? (\n <button type=\"button\" aria-pressed={Boolean(direction)} className={s.sortButton()} onClick={() => setSort(nextSort(sort, column.id))}>\n {column.header}\n <SortGlyph direction={direction} className=\"h-3.5 w-3.5\" />\n </button>\n ) : column.headerHidden ? (\n <span className=\"sr-only\">{column.header}</span>\n ) : (\n column.header\n )}\n </th>\n );\n })}\n </tr>\n </thead>\n <tbody role=\"rowgroup\" className={s.tbody()}>\n {before > 0 && (\n <tr aria-hidden style={{ height: before }}>\n <td colSpan={span} />\n </tr>\n )}\n {body}\n {after > 0 && (\n <tr aria-hidden style={{ height: after }}>\n <td colSpan={span} />\n </tr>\n )}\n </tbody>\n </table>\n );\n\n return (\n <div className={s.root({ className })}>\n {virtualize ? (\n // A scrolling region the keyboard can reach: Tab lands on it, the arrows scroll it.\n <div\n tabIndex={0}\n role=\"region\"\n aria-label={caption}\n className={s.scroller({ className: \"overflow-y-auto focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\" })}\n style={{ height: virtualize.height }}\n onScroll={(event) => setScrollTop(event.currentTarget.scrollTop)}\n >\n {table}\n </div>\n ) : (\n <div className={s.scroller()}>{table}</div>\n )}\n {footer ? <div className={s.footer()}>{footer}</div> : null}\n </div>\n );\n}\n","// Client. Radix Checkbox: role=\"checkbox\", aria-checked (true · false · mixed), Space toggles, a hidden input inside a\n// form. It sits in a `Field` like the other controls: `<Field.Label htmlFor={id}>`, `invalid`, aria-describedby.\nimport { Checkbox as CheckboxPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const checkbox = tv({\n slots: {\n root:\n \"peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-border-strong bg-surface-1 text-on-accent transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=indeterminate]:border-accent data-[state=indeterminate]:bg-accent \" +\n \"aria-invalid:border-danger aria-invalid:ring-danger/30\",\n indicator: \"flex items-center justify-center\",\n label: \"flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-60\",\n },\n});\n\nfunction Check() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\nfunction Dash() {\n return (\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M5 12h14\" />\n </svg>\n );\n}\n\nexport type CheckboxProps = Omit<React.ComponentProps<typeof CheckboxPrimitive.Root>, \"children\"> & {\n /** Marks it invalid: aria-invalid and data-invalid (pair it with a `Field.Error` in aria-describedby). */\n invalid?: boolean;\n /** The text next to the box, clickable: the box and its words in one `<label>`. Otherwise name it with\n * `Field.Label htmlFor` or `aria-label`. */\n children?: React.ReactNode;\n};\n\n/** A checkbox: `checked`/`defaultChecked` (`true` · `false` · `\"indeterminate\"`) + `onCheckedChange`. */\nexport function Checkbox({ invalid, className, children, ...props }: CheckboxProps) {\n const s = checkbox();\n const box = (\n <CheckboxPrimitive.Root\n aria-invalid={invalid || undefined}\n data-invalid={invalid ? \"\" : undefined}\n className={s.root({ className: children ? \"mt-0.5\" : className })}\n {...props}\n >\n <CheckboxPrimitive.Indicator className={s.indicator()}>\n {props.checked === \"indeterminate\" ? <Dash /> : <Check />}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n );\n if (!children) return box;\n return (\n <label className={s.label({ className })}>\n {box}\n <span className=\"min-w-0\">{children}</span>\n </label>\n );\n}\n"],"mappings":"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","names":["tv","jsx","jsxs","tv"]}
@@ -0,0 +1,288 @@
1
+ import * as tailwind_variants from 'tailwind-variants';
2
+ import * as React from 'react';
3
+
4
+ /** A calendar date, `YYYY-MM-DD`. */
5
+ type IsoDate = string;
6
+ /** A range of calendar dates; `end` is `null` while the second date is not chosen. */
7
+ type DateRange = {
8
+ start: IsoDate;
9
+ end: IsoDate | null;
10
+ };
11
+ declare const calendar: tailwind_variants.TVReturnType<{
12
+ [key: string]: {
13
+ [key: string]: tailwind_variants.ClassValue | {
14
+ root?: tailwind_variants.ClassValue;
15
+ header?: tailwind_variants.ClassValue;
16
+ title?: tailwind_variants.ClassValue;
17
+ grid?: tailwind_variants.ClassValue;
18
+ weekday?: tailwind_variants.ClassValue;
19
+ cell?: tailwind_variants.ClassValue;
20
+ nav?: tailwind_variants.ClassValue;
21
+ day?: tailwind_variants.ClassValue;
22
+ };
23
+ };
24
+ } | {
25
+ [x: string]: {
26
+ [x: string]: tailwind_variants.ClassValue | {
27
+ root?: tailwind_variants.ClassValue;
28
+ header?: tailwind_variants.ClassValue;
29
+ title?: tailwind_variants.ClassValue;
30
+ grid?: tailwind_variants.ClassValue;
31
+ weekday?: tailwind_variants.ClassValue;
32
+ cell?: tailwind_variants.ClassValue;
33
+ nav?: tailwind_variants.ClassValue;
34
+ day?: tailwind_variants.ClassValue;
35
+ };
36
+ };
37
+ } | {}, {
38
+ root: string;
39
+ header: string;
40
+ title: string;
41
+ nav: string;
42
+ grid: string;
43
+ weekday: string;
44
+ cell: string;
45
+ day: string;
46
+ }, undefined, {
47
+ [key: string]: {
48
+ [key: string]: tailwind_variants.ClassValue | {
49
+ root?: tailwind_variants.ClassValue;
50
+ header?: tailwind_variants.ClassValue;
51
+ title?: tailwind_variants.ClassValue;
52
+ grid?: tailwind_variants.ClassValue;
53
+ weekday?: tailwind_variants.ClassValue;
54
+ cell?: tailwind_variants.ClassValue;
55
+ nav?: tailwind_variants.ClassValue;
56
+ day?: tailwind_variants.ClassValue;
57
+ };
58
+ };
59
+ } | {}, {
60
+ root: string;
61
+ header: string;
62
+ title: string;
63
+ nav: string;
64
+ grid: string;
65
+ weekday: string;
66
+ cell: string;
67
+ day: string;
68
+ }, tailwind_variants.TVReturnTypeLike<unknown, {
69
+ root: string;
70
+ header: string;
71
+ title: string;
72
+ nav: string;
73
+ grid: string;
74
+ weekday: string;
75
+ cell: string;
76
+ day: string;
77
+ }>>;
78
+ /** A local `Date` at midnight for an ISO date (for formatting). */
79
+ declare const toLocalDate: (iso: IsoDate) => Date;
80
+ /** The ISO date of a local `Date`. */
81
+ declare const toIsoDate: (date: Date) => IsoDate;
82
+ declare const addDays: (iso: IsoDate, days: number) => string;
83
+ declare const addMonths: (iso: IsoDate, months: number) => string;
84
+ /** The first day of the week for a locale (0 = Sunday … 6 = Saturday), from `Intl.Locale` week info; Monday otherwise. */
85
+ declare function weekStartOf(locale: string): number;
86
+ type CalendarLabels = {
87
+ /** The previous-month button ("Previous month"). */
88
+ previousMonth: string;
89
+ /** The next-month button ("Next month"). */
90
+ nextMonth: string;
91
+ };
92
+ declare const calendarLabels: CalendarLabels;
93
+ type CalendarProps = {
94
+ /** The BCP 47 locale of the month and day names (`"en-US"`, `"fr-CA"`): always explicit. */
95
+ locale: string;
96
+ /** The chosen date (one-date mode). */
97
+ value?: IsoDate | null;
98
+ /** The chosen range (range mode): its ends are marked, the days between tinted. */
99
+ range?: DateRange | null;
100
+ /** Called with the day picked. */
101
+ onSelect?: (date: IsoDate) => void;
102
+ /** The month shown, any day of it (controlled). */
103
+ month?: IsoDate;
104
+ /** The month shown at first. Default: the value's, or today's. */
105
+ defaultMonth?: IsoDate;
106
+ /** Called when the month shown changes. */
107
+ onMonthChange?: (month: IsoDate) => void;
108
+ /** The earliest date that can be picked. */
109
+ min?: IsoDate;
110
+ /** The latest date that can be picked. */
111
+ max?: IsoDate;
112
+ /** Refuses some dates (`(d) => isWeekend(d)`). */
113
+ isDateDisabled?: (date: IsoDate) => boolean;
114
+ /** The first day of the week, 0 = Sunday. Default: the locale's. */
115
+ weekStartsOn?: number;
116
+ /** Today (marked): inject it for a stable server render or a test. Default: the device's date. */
117
+ today?: IsoDate;
118
+ /** Moves the focus to the active day when it mounts (inside a popover). */
119
+ autoFocus?: boolean;
120
+ /** The words, passed translated; English by default. */
121
+ labels?: Partial<CalendarLabels>;
122
+ /** Classes merged on the root. */
123
+ className?: string;
124
+ };
125
+ /** A month grid to pick a date or the ends of a range, with the full keyboard of the APG date picker. */
126
+ declare function Calendar({ locale, value, range, onSelect, month: monthProp, defaultMonth, onMonthChange, min, max, isDateDisabled, weekStartsOn, today: todayProp, autoFocus, labels: given, className, }: CalendarProps): React.JSX.Element;
127
+
128
+ declare const datePicker: tailwind_variants.TVReturnType<{
129
+ [key: string]: {
130
+ [key: string]: tailwind_variants.ClassValue | {
131
+ root?: tailwind_variants.ClassValue;
132
+ label?: tailwind_variants.ClassValue;
133
+ row?: tailwind_variants.ClassValue;
134
+ content?: tailwind_variants.ClassValue;
135
+ hint?: tailwind_variants.ClassValue;
136
+ icon?: tailwind_variants.ClassValue;
137
+ layout?: tailwind_variants.ClassValue;
138
+ presets?: tailwind_variants.ClassValue;
139
+ error?: tailwind_variants.ClassValue;
140
+ trigger?: tailwind_variants.ClassValue;
141
+ clear?: tailwind_variants.ClassValue;
142
+ preset?: tailwind_variants.ClassValue;
143
+ };
144
+ };
145
+ } | {
146
+ [x: string]: {
147
+ [x: string]: tailwind_variants.ClassValue | {
148
+ root?: tailwind_variants.ClassValue;
149
+ label?: tailwind_variants.ClassValue;
150
+ row?: tailwind_variants.ClassValue;
151
+ content?: tailwind_variants.ClassValue;
152
+ hint?: tailwind_variants.ClassValue;
153
+ icon?: tailwind_variants.ClassValue;
154
+ layout?: tailwind_variants.ClassValue;
155
+ presets?: tailwind_variants.ClassValue;
156
+ error?: tailwind_variants.ClassValue;
157
+ trigger?: tailwind_variants.ClassValue;
158
+ clear?: tailwind_variants.ClassValue;
159
+ preset?: tailwind_variants.ClassValue;
160
+ };
161
+ };
162
+ } | {}, {
163
+ root: string;
164
+ label: string;
165
+ row: string;
166
+ trigger: string;
167
+ icon: string;
168
+ clear: string;
169
+ content: string;
170
+ layout: string;
171
+ presets: string;
172
+ preset: string;
173
+ hint: string;
174
+ error: string;
175
+ }, undefined, {
176
+ [key: string]: {
177
+ [key: string]: tailwind_variants.ClassValue | {
178
+ root?: tailwind_variants.ClassValue;
179
+ label?: tailwind_variants.ClassValue;
180
+ row?: tailwind_variants.ClassValue;
181
+ content?: tailwind_variants.ClassValue;
182
+ hint?: tailwind_variants.ClassValue;
183
+ icon?: tailwind_variants.ClassValue;
184
+ layout?: tailwind_variants.ClassValue;
185
+ presets?: tailwind_variants.ClassValue;
186
+ error?: tailwind_variants.ClassValue;
187
+ trigger?: tailwind_variants.ClassValue;
188
+ clear?: tailwind_variants.ClassValue;
189
+ preset?: tailwind_variants.ClassValue;
190
+ };
191
+ };
192
+ } | {}, {
193
+ root: string;
194
+ label: string;
195
+ row: string;
196
+ trigger: string;
197
+ icon: string;
198
+ clear: string;
199
+ content: string;
200
+ layout: string;
201
+ presets: string;
202
+ preset: string;
203
+ hint: string;
204
+ error: string;
205
+ }, tailwind_variants.TVReturnTypeLike<unknown, {
206
+ root: string;
207
+ label: string;
208
+ row: string;
209
+ trigger: string;
210
+ icon: string;
211
+ clear: string;
212
+ content: string;
213
+ layout: string;
214
+ presets: string;
215
+ preset: string;
216
+ hint: string;
217
+ error: string;
218
+ }>>;
219
+ type DatePickerLabels = CalendarLabels & {
220
+ /** The clear button ("Clear date"). */
221
+ clear: string;
222
+ };
223
+ declare const datePickerLabels: DatePickerLabels;
224
+ type Shared = Pick<CalendarProps, "locale" | "min" | "max" | "isDateDisabled" | "weekStartsOn" | "today"> & {
225
+ /** The visible label, passed translated (also the button's accessible name, with the value). */
226
+ label: string;
227
+ /** Shown while nothing is chosen ("Pick a date"), passed translated. */
228
+ placeholder?: string;
229
+ /** `short` · `medium` (default) · `long`: how the button writes the date. */
230
+ format?: "short" | "medium" | "long";
231
+ /** Adds a button that empties the value. */
232
+ clearable?: boolean;
233
+ /** A help text under the field. */
234
+ hint?: string;
235
+ /** An error under the field: marks it invalid and is read with it. */
236
+ error?: string;
237
+ /** Not available. */
238
+ disabled?: boolean;
239
+ /** The name of a hidden input holding the ISO value, for a plain `<form>` post. */
240
+ name?: string;
241
+ /** Opens the calendar at first (a story, a test). */
242
+ defaultOpen?: boolean;
243
+ /** The words, passed translated; English by default. */
244
+ labels?: Partial<DatePickerLabels>;
245
+ /** Classes merged on the root. */
246
+ className?: string;
247
+ };
248
+ type DatePickerProps = Shared & {
249
+ /** The chosen date, ISO (controlled); `null` for none. */
250
+ value?: IsoDate | null;
251
+ /** The chosen date at first, uncontrolled. */
252
+ defaultValue?: IsoDate | null;
253
+ /** Called with the date picked, or `null` when cleared. */
254
+ onValueChange?: (value: IsoDate | null) => void;
255
+ };
256
+ /** A date field: a button showing the date in the locale's format, a calendar in a popover, an ISO value. */
257
+ declare function DatePicker({ value: valueProp, defaultValue, onValueChange, defaultOpen, ...shared }: DatePickerProps): React.JSX.Element;
258
+ type DateRangePreset = {
259
+ /** Its name, passed translated ("Last 7 days"). */
260
+ label: string;
261
+ /** The first day, ISO. */
262
+ start: IsoDate;
263
+ /** The last day, ISO. */
264
+ end: IsoDate;
265
+ };
266
+ type DateRangePickerProps = Shared & {
267
+ /** The chosen range (controlled); `null` for none. `end` is never `null` in a committed value. */
268
+ value?: {
269
+ start: IsoDate;
270
+ end: IsoDate;
271
+ } | null;
272
+ /** The range at first, uncontrolled. */
273
+ defaultValue?: {
274
+ start: IsoDate;
275
+ end: IsoDate;
276
+ } | null;
277
+ /** Called once both ends are chosen (or with `null` when cleared). */
278
+ onValueChange?: (value: {
279
+ start: IsoDate;
280
+ end: IsoDate;
281
+ } | null) => void;
282
+ /** Ranges one click away ("Last 7 days", "This month"), beside the calendar. */
283
+ presets?: readonly DateRangePreset[];
284
+ };
285
+ /** A period field: two clicks on one calendar (the days between tinted as you hover), optional presets. */
286
+ declare function DateRangePicker({ value: valueProp, defaultValue, onValueChange, presets, defaultOpen, ...shared }: DateRangePickerProps): React.JSX.Element;
287
+
288
+ export { Calendar, type CalendarLabels, type CalendarProps, DatePicker, type DatePickerLabels, type DatePickerProps, type DateRange, DateRangePicker, type DateRangePickerProps, type DateRangePreset, type IsoDate, addDays, addMonths, calendar, calendarLabels, datePicker, datePickerLabels, toIsoDate, toLocalDate, weekStartOf };