@lerianstudio/sindarian-ui 2.0.0-beta.24 → 2.0.0-beta.26

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 (337) hide show
  1. package/dist/charts/chart.js +4 -231
  2. package/dist/charts/index.js +1 -11
  3. package/dist/components/breadcrumb/get-breadcrumb-paths.js +1 -18
  4. package/dist/components/breadcrumb/index.js +1 -37
  5. package/dist/components/card/account-card/index.js +1 -69
  6. package/dist/components/card/basic-card/index.js +1 -20
  7. package/dist/components/card/dashboard-card/index.js +1 -20
  8. package/dist/components/card/entity-card/index.js +1 -68
  9. package/dist/components/card/index.js +1 -20
  10. package/dist/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  11. package/dist/components/dialog/confirmation-dialog/index.js +1 -96
  12. package/dist/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -55
  13. package/dist/components/dialog/index.js +1 -19
  14. package/dist/components/dialog/large-dialog/index.d.ts +2 -2
  15. package/dist/components/dialog/large-dialog/index.d.ts.map +1 -1
  16. package/dist/components/dialog/large-dialog/index.js +1 -21
  17. package/dist/components/entity-box/index.js +1 -67
  18. package/dist/components/entity-data-table/index.js +1 -20
  19. package/dist/components/form/combo-box-field/index.js +1 -35
  20. package/dist/components/form/country-field/index.js +1 -11
  21. package/dist/components/form/date-picker-field/index.js +1 -83
  22. package/dist/components/form/date-range-field/index.js +1 -58
  23. package/dist/components/form/date-time-picker-field/index.js +1 -114
  24. package/dist/components/form/file-upload-field/index.js +1 -69
  25. package/dist/components/form/index.js +1 -31
  26. package/dist/components/form/input-field/index.js +1 -96
  27. package/dist/components/form/otp-field/index.js +1 -19
  28. package/dist/components/form/pagination-limit-field/index.js +1 -10
  29. package/dist/components/form/password-field/index.d.ts.map +1 -1
  30. package/dist/components/form/password-field/index.js +1 -16
  31. package/dist/components/form/radio-group-field/index.js +1 -36
  32. package/dist/components/form/renderable-label.js +1 -57
  33. package/dist/components/form/select-field/index.js +1 -68
  34. package/dist/components/form/state-field/index.js +1 -42
  35. package/dist/components/form/switch-field/index.js +1 -16
  36. package/dist/components/form/textarea-field/index.js +1 -23
  37. package/dist/components/page/index.js +1 -20
  38. package/dist/components/page-header/index.js +1 -80
  39. package/dist/components/pagination/index.js +1 -10
  40. package/dist/components/table/id-table-cell.js +1 -109
  41. package/dist/components/table/index.js +1 -19
  42. package/dist/components/table/locked-table-actions.js +1 -41
  43. package/dist/components/table/name-table-cell.js +1 -58
  44. package/dist/components/ui/accordion/index.js +1 -62
  45. package/dist/components/ui/alert/index.js +1 -45
  46. package/dist/components/ui/alert-dialog/index.js +1 -84
  47. package/dist/components/ui/autocomplete/index.js +1 -440
  48. package/dist/components/ui/autosize-textarea/index.js +1 -89
  49. package/dist/components/ui/avatar/index.js +1 -51
  50. package/dist/components/ui/badge/index.js +1 -83
  51. package/dist/components/ui/breadcrumb/index.js +1 -35
  52. package/dist/components/ui/button/index.js +1 -65
  53. package/dist/components/ui/button/styles.css +2 -1
  54. package/dist/components/ui/calendar/index.js +1 -118
  55. package/dist/components/ui/card/index.js +1 -32
  56. package/dist/components/ui/checkbox/index.js +1 -44
  57. package/dist/components/ui/collapsible/index.js +1 -50
  58. package/dist/components/ui/command/index.js +1 -95
  59. package/dist/components/ui/copy-field/index.js +1 -163
  60. package/dist/components/ui/dialog/index.d.ts +4 -1
  61. package/dist/components/ui/dialog/index.d.ts.map +1 -1
  62. package/dist/components/ui/dialog/index.js +1 -80
  63. package/dist/components/ui/dialog/styles.css +2 -1
  64. package/dist/components/ui/dropdown-menu/index.js +1 -110
  65. package/dist/components/ui/field/index.js +1 -82
  66. package/dist/components/ui/file-upload/index.js +1 -574
  67. package/dist/components/ui/form.js +1 -162
  68. package/dist/components/ui/hover-card/index.js +1 -51
  69. package/dist/components/ui/icon-button/index.js +1 -35
  70. package/dist/components/ui/input/adornment.js +1 -21
  71. package/dist/components/ui/input/index.js +1 -99
  72. package/dist/components/ui/input/styles.css +29 -12
  73. package/dist/components/ui/label/index.js +1 -45
  74. package/dist/components/ui/lerian-wordmark/index.js +1 -7
  75. package/dist/components/ui/loading-button/index.js +1 -9
  76. package/dist/components/ui/multiple-select/index.js +1 -235
  77. package/dist/components/ui/otp-input/index.js +1 -62
  78. package/dist/components/ui/paper/index.js +1 -8
  79. package/dist/components/ui/paper-collapsible/index.js +1 -24
  80. package/dist/components/ui/popover/index.js +1 -55
  81. package/dist/components/ui/progress/index.js +1 -66
  82. package/dist/components/ui/qr-code/index.js +1 -27
  83. package/dist/components/ui/radio-group/index.js +1 -48
  84. package/dist/components/ui/scroll-area/index.js +1 -49
  85. package/dist/components/ui/select/index.js +1 -119
  86. package/dist/components/ui/select/styles.css +6 -3
  87. package/dist/components/ui/separator/index.js +1 -43
  88. package/dist/components/ui/sheet/index.d.ts +7 -2
  89. package/dist/components/ui/sheet/index.d.ts.map +1 -1
  90. package/dist/components/ui/sheet/index.js +1 -136
  91. package/dist/components/ui/sidebar/index.js +1 -27
  92. package/dist/components/ui/sidebar/next-router.cjs +1 -119
  93. package/dist/components/ui/sidebar/sidebar-back-button.js +1 -8
  94. package/dist/components/ui/sidebar/sidebar-components.js +1 -23
  95. package/dist/components/ui/sidebar/sidebar-expand-button.js +1 -49
  96. package/dist/components/ui/sidebar/sidebar-item-button.js +1 -21
  97. package/dist/components/ui/sidebar/sidebar-item-collapsible.js +1 -52
  98. package/dist/components/ui/sidebar/sidebar-item-icon-button.js +1 -18
  99. package/dist/components/ui/sidebar/sidebar-item.js +1 -44
  100. package/dist/components/ui/sidebar/sidebar-provider.js +1 -201
  101. package/dist/components/ui/sidebar/sidebar-root.d.ts +3 -1
  102. package/dist/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  103. package/dist/components/ui/sidebar/sidebar-root.js +1 -130
  104. package/dist/components/ui/sidebar/sidebar-router.js +1 -126
  105. package/dist/components/ui/sidebar/sidebar-trigger.js +1 -57
  106. package/dist/components/ui/skeleton/index.js +1 -8
  107. package/dist/components/ui/stepper/index.js +1 -29
  108. package/dist/components/ui/switch/index.js +1 -43
  109. package/dist/components/ui/table/index.js +1 -56
  110. package/dist/components/ui/tabs/index.js +1 -55
  111. package/dist/components/ui/textarea/index.js +1 -8
  112. package/dist/components/ui/time-picker/index.js +1 -85
  113. package/dist/components/ui/toast/index.js +1 -3
  114. package/dist/components/ui/toast/toaster.js +1 -16
  115. package/dist/components/ui/toggle-group/index.js +1 -156
  116. package/dist/components/ui/tooltip/index.js +1 -81
  117. package/dist/domain/blotter/index.js +1 -20
  118. package/dist/domain/delinquency-aging/aging-buckets.js +1 -120
  119. package/dist/domain/delinquency-aging/index.js +1 -222
  120. package/dist/domain/figure/index.js +1 -19
  121. package/dist/domain/format.js +1 -137
  122. package/dist/domain/index.js +1 -43
  123. package/dist/domain/key-id/index.js +1 -174
  124. package/dist/domain/ledger-sheet/index.js +1 -28
  125. package/dist/domain/money-diff.js +1 -48
  126. package/dist/domain/money-math.js +1 -104
  127. package/dist/domain/money-text/index.js +1 -123
  128. package/dist/domain/section-label/index.js +1 -17
  129. package/dist/domain/status-rail/index.js +1 -76
  130. package/dist/domain/threshold-gauge/index.js +1 -161
  131. package/dist/enterprise/alert-banner/index.js +1 -24
  132. package/dist/enterprise/app-shell/index.js +1 -87
  133. package/dist/enterprise/cursor-pager/index.js +1 -26
  134. package/dist/enterprise/data-table/column-size.js +1 -103
  135. package/dist/enterprise/data-table/index.d.ts.map +1 -1
  136. package/dist/enterprise/data-table/index.js +1 -345
  137. package/dist/enterprise/date-range-picker/index.js +1 -115
  138. package/dist/enterprise/detail-panel/index.js +1 -20
  139. package/dist/enterprise/empty-state/index.d.ts +6 -1
  140. package/dist/enterprise/empty-state/index.d.ts.map +1 -1
  141. package/dist/enterprise/empty-state/index.js +1 -13
  142. package/dist/enterprise/index.js +1 -39
  143. package/dist/enterprise/number-input/index.js +1 -252
  144. package/dist/enterprise/search-input/index.js +1 -121
  145. package/dist/enterprise/stat-card/index.js +1 -75
  146. package/dist/enterprise/status-badge/index.js +1 -120
  147. package/dist/enterprise/use-is-mobile.js +1 -68
  148. package/dist/enterprise/virtualized-table/index.js +1 -141
  149. package/dist/esm/charts/chart.js +4 -190
  150. package/dist/esm/charts/index.js +1 -3
  151. package/dist/esm/components/breadcrumb/get-breadcrumb-paths.js +1 -12
  152. package/dist/esm/components/breadcrumb/index.js +1 -30
  153. package/dist/esm/components/card/account-card/index.js +1 -53
  154. package/dist/esm/components/card/basic-card/index.js +1 -14
  155. package/dist/esm/components/card/dashboard-card/index.js +1 -14
  156. package/dist/esm/components/card/entity-card/index.js +1 -52
  157. package/dist/esm/components/card/index.js +1 -4
  158. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  159. package/dist/esm/components/dialog/confirmation-dialog/index.js +1 -60
  160. package/dist/esm/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -49
  161. package/dist/esm/components/dialog/index.js +1 -3
  162. package/dist/esm/components/dialog/large-dialog/index.d.ts +2 -2
  163. package/dist/esm/components/dialog/large-dialog/index.d.ts.map +1 -1
  164. package/dist/esm/components/dialog/large-dialog/index.js +1 -16
  165. package/dist/esm/components/entity-box/index.js +1 -56
  166. package/dist/esm/components/entity-data-table/index.js +1 -17
  167. package/dist/esm/components/form/combo-box-field/index.js +1 -28
  168. package/dist/esm/components/form/country-field/index.js +1 -7
  169. package/dist/esm/components/form/date-picker-field/index.js +1 -43
  170. package/dist/esm/components/form/date-range-field/index.js +1 -18
  171. package/dist/esm/components/form/date-time-picker-field/index.js +1 -74
  172. package/dist/esm/components/form/file-upload-field/index.js +1 -65
  173. package/dist/esm/components/form/index.js +1 -15
  174. package/dist/esm/components/form/input-field/index.js +1 -92
  175. package/dist/esm/components/form/otp-field/index.js +1 -15
  176. package/dist/esm/components/form/pagination-limit-field/index.js +1 -6
  177. package/dist/esm/components/form/password-field/index.d.ts.map +1 -1
  178. package/dist/esm/components/form/password-field/index.js +1 -10
  179. package/dist/esm/components/form/radio-group-field/index.js +1 -32
  180. package/dist/esm/components/form/renderable-label.js +1 -54
  181. package/dist/esm/components/form/select-field/index.js +1 -64
  182. package/dist/esm/components/form/state-field/index.js +1 -35
  183. package/dist/esm/components/form/switch-field/index.js +1 -12
  184. package/dist/esm/components/form/textarea-field/index.js +1 -19
  185. package/dist/esm/components/page/index.js +1 -15
  186. package/dist/esm/components/page-header/index.js +1 -71
  187. package/dist/esm/components/pagination/index.js +1 -6
  188. package/dist/esm/components/table/id-table-cell.js +1 -105
  189. package/dist/esm/components/table/index.js +1 -3
  190. package/dist/esm/components/table/locked-table-actions.js +1 -37
  191. package/dist/esm/components/table/name-table-cell.js +1 -54
  192. package/dist/esm/components/ui/accordion/index.js +1 -24
  193. package/dist/esm/components/ui/alert/index.js +1 -38
  194. package/dist/esm/components/ui/alert-dialog/index.js +1 -39
  195. package/dist/esm/components/ui/autocomplete/index.js +1 -392
  196. package/dist/esm/components/ui/autosize-textarea/index.js +1 -51
  197. package/dist/esm/components/ui/avatar/index.js +1 -14
  198. package/dist/esm/components/ui/badge/index.js +1 -79
  199. package/dist/esm/components/ui/breadcrumb/index.js +1 -27
  200. package/dist/esm/components/ui/button/index.js +1 -60
  201. package/dist/esm/components/ui/calendar/index.js +1 -82
  202. package/dist/esm/components/ui/card/index.js +1 -24
  203. package/dist/esm/components/ui/checkbox/index.js +1 -9
  204. package/dist/esm/components/ui/collapsible/index.js +1 -13
  205. package/dist/esm/components/ui/command/index.js +1 -51
  206. package/dist/esm/components/ui/copy-field/index.js +1 -127
  207. package/dist/esm/components/ui/dialog/index.d.ts +4 -1
  208. package/dist/esm/components/ui/dialog/index.d.ts.map +1 -1
  209. package/dist/esm/components/ui/dialog/index.js +1 -36
  210. package/dist/esm/components/ui/dropdown-menu/index.js +1 -60
  211. package/dist/esm/components/ui/field/index.js +1 -71
  212. package/dist/esm/components/ui/file-upload/index.js +1 -536
  213. package/dist/esm/components/ui/form.js +1 -118
  214. package/dist/esm/components/ui/hover-card/index.js +1 -14
  215. package/dist/esm/components/ui/icon-button/index.js +1 -31
  216. package/dist/esm/components/ui/input/adornment.js +1 -17
  217. package/dist/esm/components/ui/input/index.js +1 -60
  218. package/dist/esm/components/ui/label/index.js +1 -10
  219. package/dist/esm/components/ui/lerian-wordmark/index.js +1 -4
  220. package/dist/esm/components/ui/loading-button/index.js +1 -7
  221. package/dist/esm/components/ui/multiple-select/index.js +1 -196
  222. package/dist/esm/components/ui/otp-input/index.js +1 -21
  223. package/dist/esm/components/ui/paper/index.js +1 -5
  224. package/dist/esm/components/ui/paper-collapsible/index.js +1 -19
  225. package/dist/esm/components/ui/popover/index.js +1 -17
  226. package/dist/esm/components/ui/progress/index.js +1 -31
  227. package/dist/esm/components/ui/qr-code/index.js +1 -24
  228. package/dist/esm/components/ui/radio-group/index.js +1 -12
  229. package/dist/esm/components/ui/scroll-area/index.js +1 -13
  230. package/dist/esm/components/ui/select/index.js +1 -74
  231. package/dist/esm/components/ui/separator/index.js +1 -8
  232. package/dist/esm/components/ui/sheet/index.d.ts +7 -2
  233. package/dist/esm/components/ui/sheet/index.d.ts.map +1 -1
  234. package/dist/esm/components/ui/sheet/index.js +1 -92
  235. package/dist/esm/components/ui/sidebar/index.js +1 -11
  236. package/dist/esm/components/ui/sidebar/next-router.cjs +1 -119
  237. package/dist/esm/components/ui/sidebar/sidebar-back-button.js +1 -5
  238. package/dist/esm/components/ui/sidebar/sidebar-components.js +1 -15
  239. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +1 -42
  240. package/dist/esm/components/ui/sidebar/sidebar-item-button.js +1 -18
  241. package/dist/esm/components/ui/sidebar/sidebar-item-collapsible.js +1 -44
  242. package/dist/esm/components/ui/sidebar/sidebar-item-icon-button.js +1 -14
  243. package/dist/esm/components/ui/sidebar/sidebar-item.js +1 -40
  244. package/dist/esm/components/ui/sidebar/sidebar-provider.js +1 -193
  245. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts +3 -1
  246. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  247. package/dist/esm/components/ui/sidebar/sidebar-root.js +1 -126
  248. package/dist/esm/components/ui/sidebar/sidebar-router.js +1 -89
  249. package/dist/esm/components/ui/sidebar/sidebar-trigger.js +1 -53
  250. package/dist/esm/components/ui/skeleton/index.js +1 -6
  251. package/dist/esm/components/ui/stepper/index.js +1 -20
  252. package/dist/esm/components/ui/switch/index.js +1 -8
  253. package/dist/esm/components/ui/table/index.js +1 -44
  254. package/dist/esm/components/ui/tabs/index.js +1 -17
  255. package/dist/esm/components/ui/textarea/index.js +1 -6
  256. package/dist/esm/components/ui/time-picker/index.js +1 -49
  257. package/dist/esm/components/ui/toast/index.js +1 -2
  258. package/dist/esm/components/ui/toast/toaster.js +1 -13
  259. package/dist/esm/components/ui/toggle-group/index.js +1 -120
  260. package/dist/esm/components/ui/tooltip/index.js +1 -43
  261. package/dist/esm/domain/blotter/index.js +1 -16
  262. package/dist/esm/domain/delinquency-aging/aging-buckets.js +1 -115
  263. package/dist/esm/domain/delinquency-aging/index.js +1 -218
  264. package/dist/esm/domain/figure/index.js +1 -15
  265. package/dist/esm/domain/format.js +1 -128
  266. package/dist/esm/domain/index.js +1 -19
  267. package/dist/esm/domain/key-id/index.js +1 -169
  268. package/dist/esm/domain/ledger-sheet/index.js +1 -24
  269. package/dist/esm/domain/money-diff.js +1 -45
  270. package/dist/esm/domain/money-math.js +1 -98
  271. package/dist/esm/domain/money-text/index.js +1 -118
  272. package/dist/esm/domain/section-label/index.js +1 -14
  273. package/dist/esm/domain/status-rail/index.js +1 -71
  274. package/dist/esm/domain/threshold-gauge/index.js +1 -157
  275. package/dist/esm/enterprise/alert-banner/index.js +1 -21
  276. package/dist/esm/enterprise/app-shell/index.js +1 -51
  277. package/dist/esm/enterprise/cursor-pager/index.js +1 -23
  278. package/dist/esm/enterprise/data-table/column-size.js +1 -97
  279. package/dist/esm/enterprise/data-table/index.d.ts.map +1 -1
  280. package/dist/esm/enterprise/data-table/index.js +1 -342
  281. package/dist/esm/enterprise/date-range-picker/index.js +1 -112
  282. package/dist/esm/enterprise/detail-panel/index.js +1 -17
  283. package/dist/esm/enterprise/empty-state/index.d.ts +6 -1
  284. package/dist/esm/enterprise/empty-state/index.d.ts.map +1 -1
  285. package/dist/esm/enterprise/empty-state/index.js +1 -10
  286. package/dist/esm/enterprise/index.js +1 -22
  287. package/dist/esm/enterprise/number-input/index.js +1 -214
  288. package/dist/esm/enterprise/search-input/index.js +1 -85
  289. package/dist/esm/enterprise/stat-card/index.js +1 -72
  290. package/dist/esm/enterprise/status-badge/index.js +1 -116
  291. package/dist/esm/enterprise/use-is-mobile.js +1 -31
  292. package/dist/esm/enterprise/virtualized-table/index.js +1 -138
  293. package/dist/esm/hooks/use-click-away.js +1 -22
  294. package/dist/esm/hooks/use-pagination.js +1 -38
  295. package/dist/esm/hooks/use-stepper.js +1 -22
  296. package/dist/esm/hooks/use-time.js +1 -13
  297. package/dist/esm/hooks/use-toast.js +1 -107
  298. package/dist/esm/index.js +1 -77
  299. package/dist/esm/lib/storage/get-storage-object.js +1 -17
  300. package/dist/esm/lib/storage/get-storage.js +1 -14
  301. package/dist/esm/lib/storage/index.js +1 -2
  302. package/dist/esm/lib/typography.js +1 -31
  303. package/dist/esm/lib/utils.js +1 -41
  304. package/dist/esm/theme/get-theme-script.js +1 -41
  305. package/dist/esm/theme/index.js +1 -4
  306. package/dist/esm/theme/mode-toggle.js +1 -45
  307. package/dist/esm/theme/theme-provider.js +1 -122
  308. package/dist/esm/toast/helpers.js +1 -36
  309. package/dist/esm/toast/index.js +1 -4
  310. package/dist/esm/types/metadata-type.js +1 -1
  311. package/dist/esm/utils/countries.cjs +1 -17
  312. package/dist/esm/utils/country-utils.js +1 -18
  313. package/dist/esm/utils/currency-codes.js +1 -181
  314. package/dist/globals.css +1 -0
  315. package/dist/hooks/use-click-away.js +1 -29
  316. package/dist/hooks/use-pagination.js +1 -41
  317. package/dist/hooks/use-stepper.js +1 -26
  318. package/dist/hooks/use-time.js +1 -20
  319. package/dist/hooks/use-toast.js +1 -111
  320. package/dist/index.js +1 -96
  321. package/dist/lib/storage/get-storage-object.js +1 -23
  322. package/dist/lib/storage/get-storage.js +1 -17
  323. package/dist/lib/storage/index.js +1 -18
  324. package/dist/lib/typography.js +1 -34
  325. package/dist/lib/utils.js +1 -45
  326. package/dist/theme/get-theme-script.js +1 -44
  327. package/dist/theme/index.js +1 -11
  328. package/dist/theme/mode-toggle.js +1 -48
  329. package/dist/theme/theme-provider.js +1 -160
  330. package/dist/toast/helpers.js +1 -41
  331. package/dist/toast/index.js +1 -10
  332. package/dist/tokens.css +7 -4
  333. package/dist/types/metadata-type.js +1 -2
  334. package/dist/utils/countries.cjs +1 -17
  335. package/dist/utils/country-utils.js +1 -25
  336. package/dist/utils/currency-codes.js +1 -184
  337. package/package.json +4 -3
@@ -1,97 +1 @@
1
- /**
2
- * The column sizing a ColumnDef actually DECLARED, or `undefined` when it
3
- * declared none. This is VirtualizedTable's reading: flex rows honour all
4
- * three, so `size`, `minSize` and `maxSize` all PIN. DataTable's `<th>`/`<td>`
5
- * path reads the same declaration through {@link readPreferredColumnSize},
6
- * which drops the ceiling CSS auto table layout cannot enforce.
7
- *
8
- * Reading the raw `columnDef` is only honest because both tables pass
9
- * `defaultColumn: { size: undefined, minSize: undefined, maxSize: undefined }`
10
- * to `useReactTable`. TanStack builds every columnDef as
11
- * `{ ...featureDefaults, ...table.options.defaultColumn, ...userDef }`, so
12
- * those three overrides blank out the `defaultColumnSizing` the ColumnSizing
13
- * feature would otherwise stamp on every column (150 / 20 / MAX_SAFE_INTEGER).
14
- * Without them a column asking for nothing reports `size: 150` and a column
15
- * asking for exactly 150 is indistinguishable from it. `column.getSize()` is
16
- * unaffected: it falls back to `defaultColumnSizing` with `??`, so column
17
- * offsets and the table's total size are byte-identical either way.
18
- *
19
- * Width comes from `getSize()` rather than the raw `size` so it lands already
20
- * clamped by the column's own min/max.
21
- */
22
- export function readDeclaredColumnSize(column) {
23
- const { size, minSize, maxSize } = column.columnDef;
24
- const width = size === undefined ? undefined : column.getSize();
25
- if (width === undefined && minSize === undefined && maxSize === undefined) {
26
- return undefined;
27
- }
28
- return { width, minWidth: minSize, maxWidth: maxSize };
29
- }
30
- /**
31
- * A GROUP header cell is exactly as wide as the leaf columns it spans, so it
32
- * can only be pinned when every one of them is: a group whose leaves are
33
- * partly sized has no honest fixed width, and keeps its colSpan flex share so
34
- * the header rule still tracks the cells beneath it. Reading the group's own
35
- * ColumnDef instead would size the header against a declaration its body cells
36
- * never see.
37
- *
38
- * Every dimension the leaves agree on carries up, CEILING INCLUDED. This is
39
- * VirtualizedTable's path, where flex rows honour `maxSize` on a leaf — so a
40
- * group of capped leaves whose header carried no `maxWidth` was free to grow
41
- * past every column it names, which is the same header-vs-cells drift the
42
- * width sum exists to prevent. Each dimension is decided on its own: a group
43
- * can be uncapped and still have a floor.
44
- */
45
- export function readDeclaredGroupSize(leaves) {
46
- if (leaves.length === 0)
47
- return undefined;
48
- const sizes = leaves.map(readDeclaredColumnSize);
49
- const width = sum(sizes, 'width');
50
- const minWidth = sum(sizes, 'minWidth');
51
- const maxWidth = sum(sizes, 'maxWidth');
52
- if (width === undefined && minWidth === undefined && maxWidth === undefined) {
53
- return undefined;
54
- }
55
- return { width, minWidth, maxWidth };
56
- }
57
- /**
58
- * The total of one dimension, or `undefined` unless EVERY leaf declared it. One
59
- * leaf short and the group has no honest total: an unsized leaf flexes, an
60
- * unfloored one can shrink, and an uncapped one grows without limit.
61
- */
62
- function sum(sizes, key) {
63
- let total = 0;
64
- for (const size of sizes) {
65
- const value = size?.[key];
66
- if (value === undefined)
67
- return undefined;
68
- total += value;
69
- }
70
- return total;
71
- }
72
- /**
73
- * The same declaration as {@link readDeclaredColumnSize}, minus `maxWidth`.
74
- *
75
- * DataTable renders real `<th>`/`<td>` under CSS AUTO table layout, where
76
- * Chrome and Firefox ignore `max-width` on a cell. Emitting it would advertise
77
- * a ceiling that never holds, so this path keeps only what the layout obeys:
78
- * `size` as a PREFERRED width and `minSize` as a floor. A column that must not
79
- * grow past a width belongs in VirtualizedTable.
80
- */
81
- export function readPreferredColumnSize(column) {
82
- const { width, minWidth } = readDeclaredColumnSize(column) ?? {};
83
- if (width === undefined && minWidth === undefined) {
84
- return undefined;
85
- }
86
- return { width, minWidth };
87
- }
88
- /**
89
- * Blanks out the `defaultColumnSizing` TanStack stamps onto every ColumnDef, so
90
- * `columnDef.size` / `minSize` / `maxSize` mean "the consumer asked for this"
91
- * and nothing else. Both tables pass it to `useReactTable`.
92
- */
93
- export const UNSIZED_DEFAULT_COLUMN = {
94
- size: undefined,
95
- minSize: undefined,
96
- maxSize: undefined
97
- };
1
+ export function readDeclaredColumnSize(i){const{size:n,minSize:e,maxSize:t}=i.columnDef;const d=n===void 0?void 0:i.getSize();if(d===void 0&&e===void 0&&t===void 0){return void 0}return{width:d,minWidth:e,maxWidth:t}}export function readDeclaredGroupSize(i){if(i.length===0)return void 0;const n=i.map(readDeclaredColumnSize);const e=u(n,"width");const t=u(n,"minWidth");const d=u(n,"maxWidth");if(e===void 0&&t===void 0&&d===void 0){return void 0}return{width:e,minWidth:t,maxWidth:d}}function u(i,n){let e=0;for(const t of i){const d=t?.[n];if(d===void 0)return void 0;e+=d}return e}export function readPreferredColumnSize(i){const{width:n,minWidth:e}=readDeclaredColumnSize(i)??{};if(n===void 0&&e===void 0){return void 0}return{width:n,minWidth:e}}export const UNSIZED_DEFAULT_COLUMN={size:void 0,minSize:void 0,maxSize:void 0};
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/data-table/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/data-table/index.tsx"],"names":[],"mappings":"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"}
@@ -1,342 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- /**
4
- * DataTable — a typed, generic wrapper over TanStack Table v8.
5
- *
6
- * Pairs with CursorPager (server-driven pagination): pass the page's `items`
7
- * as `data`; this component does no client-side paging or sorting by default.
8
- * It owns the three render states the list screens need:
9
- * - loading → header + skeleton rows
10
- * - empty → EmptyState (data resolved, zero rows)
11
- * - data → semantic table rows; cells own any links/actions
12
- *
13
- * Column heads speak the kit's LABEL_VOICE_CLASS; `headClassName` overrides it
14
- * per table. An optional `footer` node renders in a `tfoot` for footed totals.
15
- *
16
- * Columns are standard TanStack `ColumnDef<T>`; cells receive the row's
17
- * `original` value, so screens compose money / date / status cells directly in
18
- * their column `cell` renderers.
19
- *
20
- * Declared column sizing (see `./column-size`) does NOT mean the same thing in
21
- * the kit's two table paths, because their layouts differ:
22
- * - DataTable renders real `<th>`/`<td>` under CSS AUTO table layout (the
23
- * `Table` primitive sets no `table-fixed`). There, `size` is a PREFERRED
24
- * width the browser may exceed to fit content, `minSize` acts as a floor,
25
- * and `maxSize` is ignored outright — Chrome and Firefox do not apply
26
- * `max-width` to table cells. A column declaring none keeps auto width.
27
- * - VirtualizedTable renders flex rows, where all three PIN: `size`,
28
- * `minSize` and `maxSize` are honoured exactly as declared.
29
- * So a column that must not grow past a width belongs in VirtualizedTable, or
30
- * in a cell renderer that truncates its own content.
31
- *
32
- * Row selection is opt-in and controlled: pass `enableRowSelection` plus
33
- * `rowSelection` / `onRowSelectionChange` (TanStack-native types). When
34
- * enabled, a checkbox column is prepended — header checkbox selects the
35
- * page (indeterminate for partial), checkbox-cell clicks never bubble to
36
- * row-level handlers. With the flag off (the default), nothing changes.
37
- *
38
- * Sorting is opt-in and controlled too: pass `enableSorting` plus `sorting` /
39
- * `onSortingChange`. Rows are never reordered client-side (`manualSorting`, no
40
- * sorted row model); what the flag buys is `aria-sort` on each sortable `th`.
41
- * With the flag off (the default), no header carries the attribute.
42
- *
43
- * Keyboard navigation is opt-in via `onRowActivate`: when present, rows get
44
- * a roving tabindex (Tab enters the table once at the anchor row; the next
45
- * Tab moves to the row's first tabbable child if it has one, otherwise out
46
- * of the table — no trap), ArrowUp/Down move row focus clamped to the page,
47
- * Home/End jump to the page edges, Enter activates the row through the
48
- * callback, and Space toggles selection when `enableRowSelection` is on.
49
- * Cmd/Ctrl+Enter opens the row's destination in a new tab when the optional
50
- * `rowHref` builder is provided (window.open with noopener,noreferrer);
51
- * without it, modified Enter stays a deliberate no-op — never a same-tab
52
- * activation. Keydown events originating from interactive children (links,
53
- * buttons, checkboxes, form fields) are never hijacked.
54
- */
55
- import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
56
- import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';
57
- import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from '../../components/ui/table/index.js';
58
- import { Skeleton } from '../../components/ui/skeleton/index.js';
59
- import { LABEL_VOICE_CLASS } from '../../lib/typography.js';
60
- import { cn } from '../../lib/utils.js';
61
- import { EmptyState } from '../empty-state/index.js';
62
- import { readPreferredColumnSize, UNSIZED_DEFAULT_COLUMN } from './column-size.js';
63
- const SELECTION_COLUMN_ID = '__select__';
64
- const CHECKBOX_CLASS = 'accent-primary block size-4';
65
- /** Figure treatment for `meta: { numeric: true }` columns; the alignment half
66
- * lives in ALIGN_CELL_CLASS so `meta.align` can override one without the other. */
67
- const NUMERIC_FIGURE_CLASS = 'font-mono tabular-nums';
68
- /**
69
- * Body-cell alignment, one class per direction rather than a single string with
70
- * `text-right` baked in: an explicit `meta.align` has to beat `numeric` by
71
- * choosing the class, not by out-ordering it — tailwind-merge resolving two
72
- * conflicting alignment utilities by source order is not a contract worth
73
- * relying on.
74
- */
75
- const ALIGN_CELL_CLASS = {
76
- left: 'text-left',
77
- center: 'text-center',
78
- right: 'text-right'
79
- };
80
- /**
81
- * Keydown events whose target sits inside one of these are never hijacked
82
- * by the row-level keyboard handler — Space in a checkbox and Enter on an
83
- * in-cell link keep their native behavior.
84
- */
85
- const INTERACTIVE_CHILD_SELECTOR = 'a, button, input, select, textarea, [role="checkbox"]';
86
- /**
87
- * Inset focus outline for keyboard-navigable rows. Outline, not Tailwind
88
- * ring: ring is box-shadow, which renders unreliably on display: table-row.
89
- * `focus-visible`-gated, so mouse users (and visual baselines) see nothing.
90
- */
91
- const ROW_FOCUS_CLASS = 'focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring';
92
- function stopPropagation(event) {
93
- event.stopPropagation();
94
- }
95
- /**
96
- * ARIA sort state for one header cell. `undefined` (attribute omitted) on a
97
- * column that cannot sort, which covers both sorting-off tables and columns
98
- * that opted out, so the attribute never claims a control the user does not
99
- * have.
100
- */
101
- function ariaSortFor(column) {
102
- if (!column.getCanSort())
103
- return undefined;
104
- const sorted = column.getIsSorted();
105
- if (sorted === 'asc')
106
- return 'ascending';
107
- if (sorted === 'desc')
108
- return 'descending';
109
- return 'none';
110
- }
111
- function SelectAllCheckbox({ table }) {
112
- const allSelected = table.getIsAllPageRowsSelected();
113
- const someSelected = table.getIsSomePageRowsSelected();
114
- return (_jsx("input", { type: "checkbox", className: CHECKBOX_CLASS, "aria-label": "Select all rows on this page", checked: allSelected, ref: (el) => {
115
- if (el)
116
- el.indeterminate = !allSelected && someSelected;
117
- }, onChange: table.getToggleAllPageRowsSelectedHandler() }));
118
- }
119
- function RowSelectionCheckbox({ row, getLabel }) {
120
- return (_jsx("input", { type: "checkbox", className: CHECKBOX_CLASS, "aria-label": getLabel ? getLabel(row.original) : `Select row ${row.id}`, checked: row.getIsSelected(), disabled: !row.getCanSelect(), onChange: row.getToggleSelectedHandler() }));
121
- }
122
- function createSelectionColumn(getLabel) {
123
- return {
124
- id: SELECTION_COLUMN_ID,
125
- header: ({ table }) => _jsx(SelectAllCheckbox, { table: table }),
126
- cell: ({ row }) => _jsx(RowSelectionCheckbox, { row: row, getLabel: getLabel })
127
- };
128
- }
129
- export function DataTable({ columns, data, loading = false, skeletonRows = 8, loadingLabel = 'Loading table rows', empty, getRowId, flush = false, density = 'comfortable', enableRowSelection = false, rowSelection, onRowSelectionChange, getRowSelectionLabel, enableSorting = false, sorting, onSortingChange, columnVisibility, onColumnVisibilityChange, onRowActivate, rowHref, className, headClassName, footer }) {
130
- const tableColumns = useMemo(() => enableRowSelection
131
- ? [createSelectionColumn(getRowSelectionLabel), ...columns]
132
- : columns, [columns, enableRowSelection, getRowSelectionLabel]);
133
- const table = useReactTable({
134
- data,
135
- columns: tableColumns,
136
- // Keeps `columnDef.size`/`minSize`/`maxSize` meaning "declared" — see
137
- // ./column-size. `getSize()` is unaffected; it falls back to the library
138
- // defaults itself.
139
- defaultColumn: UNSIZED_DEFAULT_COLUMN,
140
- getCoreRowModel: getCoreRowModel(),
141
- getRowId,
142
- enableRowSelection,
143
- // Controlled-only, exactly as sindarian-x shipped it: this component holds
144
- // no selection state. The `?? {}` is the JS-consumer safety net; the prop
145
- // types make the TS path require the controlled pair whenever selection is
146
- // enabled, so the dead-checkbox configuration is now unrepresentable.
147
- onRowSelectionChange: enableRowSelection ? onRowSelectionChange : undefined,
148
- // Controlled-only as well, and deliberately without `getSortedRowModel`:
149
- // `manualSorting` tells TanStack the rows arrive in the order the consumer
150
- // already chose, so enabling sorting changes what the header ANNOUNCES,
151
- // never what the body shows.
152
- manualSorting: true,
153
- enableSorting,
154
- onSortingChange: enableSorting ? onSortingChange : undefined,
155
- // ⛔ EACH VISIBILITY ENTRY IS GUARDED ON ITS OWN PROP, NEVER ON THE OTHER.
156
- //
157
- // TanStack merges options as `{...defaultOptions, ...options}` and state as
158
- // `{...internalState, ...options.state}`, both plain spreads — so a key
159
- // present and holding `undefined` OVERWRITES what it was meant to leave
160
- // alone. `onColumnVisibilityChange: undefined` replaces the feature's own
161
- // `makeStateUpdater`, and `setColumnVisibility` reads
162
- // `options.onColumnVisibilityChange == null ? void 0 : ...`, so it (and
163
- // every `column.toggleVisibility` behind it) becomes a silent no-op.
164
- // `columnVisibility: undefined` replaces the table's initial `{}`, so a
165
- // consumer reading the slice gets `undefined` instead of an empty object.
166
- //
167
- // Guarding the UPDATER on the STATE put that `undefined` back for the
168
- // union's first arm — state with no updater, which is the shipped console
169
- // usage, where a separate dropdown owns the state. A table that passes
170
- // neither prop is uncontrolled, exactly as before.
171
- ...(onColumnVisibilityChange !== undefined && { onColumnVisibilityChange }),
172
- state: {
173
- rowSelection: enableRowSelection ? (rowSelection ?? {}) : undefined,
174
- sorting: enableSorting ? (sorting ?? []) : undefined,
175
- ...(columnVisibility !== undefined && { columnVisibility })
176
- }
177
- });
178
- // Visible, not declared: the skeleton grid and the empty row's colSpan have
179
- // to match the header the table actually rendered, and a hidden column is in
180
- // `tableColumns` but in no `<th>`.
181
- const colCount = table.getVisibleLeafColumns().length;
182
- const dataRows = table.getRowModel().rows;
183
- const rowCount = dataRows.length;
184
- // Compact density overrides only THIS table's cell padding (tailwind-merge
185
- // lets the later utility win over TableHead/TableCell's defaults).
186
- // Comfortable passes nothing, so the default render is unchanged.
187
- const compact = density === 'compact';
188
- const headDensityClass = compact ? 'h-8 px-2' : undefined;
189
- const cellDensityClass = compact ? 'px-2 py-1.5' : undefined;
190
- // --- Roving row focus (active only when onRowActivate is provided) ---
191
- const keyboardNav = onRowActivate !== undefined;
192
- const [focusedIndex, setFocusedIndex] = useState(0);
193
- // ponytail: rowRefs is keyed by render index, while rows are id-keyed
194
- // (`key={row.id}`). This holds only because DataTable is server-driven with
195
- // no in-place client reorder, and React 19's per-render ref cleanup defuses
196
- // stale entries. If client-side reorder is ever added, re-key this Map by
197
- // row.id to keep focus targets aligned with their rows.
198
- const rowRefs = useRef(new Map());
199
- const focusWithinRef = useRef(false);
200
- const containerRef = useRef(null);
201
- // Render-time clamp: exactly one anchor row (tabIndex=0) even on the
202
- // frame where data shrank but state has not caught up yet.
203
- const anchorIndex = rowCount > 0 ? Math.min(focusedIndex, rowCount - 1) : 0;
204
- // Data changes clamp the anchor but never steal focus: DOM focus moves
205
- // only if focus was already inside the table and the focused row vanished
206
- // (e.g. page flip removed it). Never autofocus on mount.
207
- useEffect(() => {
208
- if (!keyboardNav)
209
- return;
210
- // Clamp the focus target ONCE and drive both the state setter and the
211
- // .focus() call from the same value — reading `focusedIndex` separately
212
- // after the functional update would use the stale pre-clamp closure value
213
- // and try to focus an unmounted row, dropping focus to <body>.
214
- const max = Math.max(rowCount - 1, 0);
215
- const target = Math.min(focusedIndex, max);
216
- setFocusedIndex(target);
217
- if (!focusWithinRef.current)
218
- return;
219
- const active = document.activeElement;
220
- if (active && containerRef.current?.contains(active))
221
- return;
222
- // The target row may have unmounted on a data-shrink frame; walk down to
223
- // the nearest existing lower index, falling back to the container, so
224
- // focus never escapes the table.
225
- for (let i = target; i >= 0; i--) {
226
- const rowEl = rowRefs.current.get(i);
227
- if (rowEl) {
228
- rowEl.focus();
229
- return;
230
- }
231
- }
232
- containerRef.current?.focus();
233
- }, [keyboardNav, rowCount, focusedIndex, data]);
234
- const focusRow = (index) => {
235
- rowRefs.current.get(index)?.focus();
236
- };
237
- const handleRowBlur = (event) => {
238
- const next = event.relatedTarget;
239
- if (!next || !containerRef.current?.contains(next)) {
240
- focusWithinRef.current = false;
241
- }
242
- };
243
- const handleRowKeyDown = (event, row, rowIndex) => {
244
- const target = event.target;
245
- if (target !== event.currentTarget &&
246
- target.closest(INTERACTIVE_CHILD_SELECTOR) !== null) {
247
- return;
248
- }
249
- switch (event.key) {
250
- case 'ArrowDown':
251
- event.preventDefault();
252
- focusRow(Math.min(rowIndex + 1, rowCount - 1));
253
- break;
254
- case 'ArrowUp':
255
- event.preventDefault();
256
- focusRow(Math.max(rowIndex - 1, 0));
257
- break;
258
- case 'Home':
259
- event.preventDefault();
260
- focusRow(0);
261
- break;
262
- case 'End':
263
- event.preventDefault();
264
- focusRow(rowCount - 1);
265
- break;
266
- case 'Enter':
267
- // Modified Enter (Cmd/Ctrl) means "open elsewhere" — a same-tab
268
- // activation would destroy the user's context. With rowHref it
269
- // opens the row's destination in a new tab; without it (sheet-based
270
- // tables), it stays a deliberate no-op.
271
- if (event.metaKey || event.ctrlKey) {
272
- if (rowHref) {
273
- window.open(rowHref(row.original), '_blank', 'noopener,noreferrer');
274
- }
275
- break;
276
- }
277
- onRowActivate?.(row.original);
278
- break;
279
- case ' ':
280
- if (enableRowSelection && row.getCanSelect()) {
281
- event.preventDefault();
282
- row.getToggleSelectedHandler()(event);
283
- }
284
- break;
285
- default:
286
- break;
287
- }
288
- };
289
- return (_jsxs("div", { ref: containerRef,
290
- // tabIndex={-1} (keyboard-nav only) makes the container programmatically
291
- // focusable so the focus-restoration fallback can land here when every
292
- // row has unmounted, keeping focus inside the table rather than on <body>.
293
- tabIndex: keyboardNav ? -1 : undefined, className: cn(!flush &&
294
- 'border-border bg-card text-card-foreground rounded-lg border', className), children: [_jsx("span", { className: "sr-only", role: "status", children: loading
295
- ? loadingLabel
296
- : rowCount === 0
297
- ? 'No rows'
298
- : `${rowCount} rows` }), _jsxs(Table, { "aria-busy": loading ? 'true' : undefined, children: [_jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: "hover:bg-transparent", children: headerGroup.headers.map((header) => {
299
- const meta = header.column.columnDef.meta;
300
- return (_jsx(TableHead, { align: meta?.align ?? (meta?.numeric ? 'right' : undefined), "aria-sort": header.isPlaceholder
301
- ? undefined
302
- : ariaSortFor(header.column),
303
- // Only a column that DECLARED sizing gets an inline width;
304
- // everything else keeps the auto table layout it has today.
305
- style: readPreferredColumnSize(header.column), className: cn(LABEL_VOICE_CLASS, headDensityClass, header.column.id === SELECTION_COLUMN_ID && 'w-10', headClassName, meta?.headerClassName), children: header.isPlaceholder
306
- ? null
307
- : flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
308
- }) }, headerGroup.id))) }), _jsx(TableBody, { children: loading ? (Array.from({ length: skeletonRows }).map((_, rowIndex) => (_jsx(TableRow, { className: "hover:bg-transparent", children: Array.from({ length: colCount }).map((__, cellIndex) => (_jsx(TableCell, { className: cellDensityClass, children: _jsx(Skeleton, { className: "h-4 w-full max-w-[160px]" }) }, `skeleton-${rowIndex}-${cellIndex}`))) }, `skeleton-${rowIndex}`)))) : rowCount === 0 ? (_jsx(TableRow, { className: "hover:bg-transparent", children: _jsx(TableCell, { colSpan: colCount, className: "p-0", children: _jsx(EmptyState, { title: empty?.title ?? 'Nothing here yet', description: empty?.description, icon: empty?.icon, action: empty?.action,
309
- // The DataTable renders the ledger register grammar, so its
310
- // empty surface reads as a ruled page rather than a centered
311
- // void. Callers can still override via `empty.ruled = false`.
312
- ruled: empty?.ruled ?? true }) }) })) : (dataRows.map((row, rowIndex) => (_jsx(TableRow, { ref: keyboardNav
313
- ? (el) => {
314
- if (el)
315
- rowRefs.current.set(rowIndex, el);
316
- else
317
- rowRefs.current.delete(rowIndex);
318
- }
319
- : undefined, tabIndex: keyboardNav ? (rowIndex === anchorIndex ? 0 : -1) : undefined, onFocus: keyboardNav
320
- ? () => {
321
- focusWithinRef.current = true;
322
- setFocusedIndex(rowIndex);
323
- }
324
- : undefined, onBlur: keyboardNav ? handleRowBlur : undefined, onKeyDown: keyboardNav
325
- ? (event) => handleRowKeyDown(event, row, rowIndex)
326
- : undefined, className: keyboardNav ? ROW_FOCUS_CLASS : undefined, "data-state": enableRowSelection && row.getIsSelected()
327
- ? 'selected'
328
- : undefined, children: row.getVisibleCells().map((cell) => {
329
- const meta = cell.column.columnDef.meta;
330
- const content = flexRender(cell.column.columnDef.cell, cell.getContext());
331
- // The column owns its `<td>`: render the consumer's cell bare.
332
- // The kit's selection column is built here and carries no
333
- // meta, so it can never take this path.
334
- if (meta?.renderOwnCell) {
335
- return _jsx(Fragment, { children: content }, cell.id);
336
- }
337
- const align = meta?.align ?? (meta?.numeric ? 'right' : undefined);
338
- return (_jsx(TableCell, { style: readPreferredColumnSize(cell.column), className: cn(meta?.numeric && NUMERIC_FIGURE_CLASS, align && ALIGN_CELL_CLASS[align], cellDensityClass, cell.column.id === SELECTION_COLUMN_ID && 'w-10', meta?.className), onClick: cell.column.id === SELECTION_COLUMN_ID
339
- ? stopPropagation
340
- : undefined, children: content }, cell.id));
341
- }) }, row.id)))) }), footer ? _jsx(TableFooter, { children: footer }) : null] })] }));
342
- }
1
+ "use client";import{jsx as o,jsxs as U}from"react/jsx-runtime";import{Fragment as re,useEffect as oe,useMemo as ae,useRef as k,useState as se}from"react";import{flexRender as v,getCoreRowModel as ce,useReactTable as le}from"@tanstack/react-table";import{Table as ie,TableBody as ue,TableCell as E,TableFooter as de,TableHead as fe,TableHeader as me,TableRow as C}from"../../components/ui/table/index.js";import{Skeleton as ge}from"../../components/ui/skeleton/index.js";import{LABEL_VOICE_CLASS as he}from"../../lib/typography.js";import{cn as D}from"../../lib/utils.js";import{EmptyState as pe}from"../empty-state/index.js";import{readPreferredColumnSize as B,UNSIZED_DEFAULT_COLUMN as Ce}from"./column-size.js";const b="__select__";const K="accent-primary block size-4";const be="font-mono tabular-nums";const Se={left:"text-left",center:"text-center",right:"text-right"};const xe='a, button, input, select, textarea, [role="checkbox"]';const Ne="focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring";function _e(r){r.stopPropagation()}function ke(r){if(!r.getCanSort())return void 0;const a=r.getIsSorted();if(a==="asc")return"ascending";if(a==="desc")return"descending";return"none"}function Ee({table:r}){const a=r.getIsAllPageRowsSelected();const d=r.getIsSomePageRowsSelected();return o("input",{type:"checkbox",className:K,"aria-label":"Select all rows on this page",checked:a,ref:m=>{if(m)m.indeterminate=!a&&d},onChange:r.getToggleAllPageRowsSelectedHandler()})}function De({row:r,getLabel:a}){return o("input",{type:"checkbox",className:K,"aria-label":a?a(r.original):`Select row ${r.id}`,checked:r.getIsSelected(),disabled:!r.getCanSelect(),onChange:r.getToggleSelectedHandler()})}function Te(r){return{id:b,header:({table:a})=>o(Ee,{table:a}),cell:({row:a})=>o(De,{row:a,getLabel:r})}}export function DataTable({columns:r,data:a,loading:d=false,skeletonRows:m=8,loadingLabel:$="Loading table rows",empty:u,getRowId:j,flush:z=false,density:G="comfortable",enableRowSelection:i=false,rowSelection:V,onRowSelectionChange:W,getRowSelectionLabel:T,enableSorting:S=false,sorting:X,onSortingChange:Z,columnVisibility:A,onColumnVisibilityChange:L,onRowActivate:R,rowHref:y,className:q,headClassName:J,footer:I}){const Q=ae(()=>i?[Te(T),...r]:r,[r,i,T]);const x=le({data:a,columns:Q,defaultColumn:Ce,getCoreRowModel:ce(),getRowId:j,enableRowSelection:i,onRowSelectionChange:i?W:void 0,manualSorting:true,enableSorting:S,onSortingChange:S?Z:void 0,...L!==void 0&&{onColumnVisibilityChange:L},state:{rowSelection:i?V??{}:void 0,sorting:S?X??[]:void 0,...A!==void 0&&{columnVisibility:A}}});const w=x.getVisibleLeafColumns().length;const M=x.getRowModel().rows;const c=M.length;const O=G==="compact";const Y=O?"h-8 px-2":void 0;const F=O?"px-2 py-1.5":void 0;const l=R!==void 0;const[N,H]=se(0);const g=k(new Map);const _=k(false);const h=k(null);const ee=c>0?Math.min(N,c-1):0;oe(()=>{if(!l)return;const n=Math.max(c-1,0);const e=Math.min(N,n);H(e);if(!_.current)return;const t=document.activeElement;if(t&&h.current?.contains(t))return;for(let s=e;s>=0;s--){const f=g.current.get(s);if(f){f.focus();return}}h.current?.focus()},[l,c,N,a]);const p=n=>{g.current.get(n)?.focus()};const ne=n=>{const e=n.relatedTarget;if(!e||!h.current?.contains(e)){_.current=false}};const te=(n,e,t)=>{const s=n.target;if(s!==n.currentTarget&&s.closest(xe)!==null){return}switch(n.key){case"ArrowDown":n.preventDefault();p(Math.min(t+1,c-1));break;case"ArrowUp":n.preventDefault();p(Math.max(t-1,0));break;case"Home":n.preventDefault();p(0);break;case"End":n.preventDefault();p(c-1);break;case"Enter":if(n.metaKey||n.ctrlKey){if(y){window.open(y(e.original),"_blank","noopener,noreferrer")}break}R?.(e.original);break;case" ":if(i&&e.getCanSelect()){n.preventDefault();e.getToggleSelectedHandler()(n)}break;default:break}};return U("div",{ref:h,tabIndex:l?-1:void 0,className:D(!z&&"border-border bg-card text-card-foreground rounded-lg border",q),children:[o("span",{className:"sr-only",role:"status",children:d?$:c===0?"No rows":`${c} rows`}),U(ie,{"aria-busy":d?"true":void 0,children:[o(me,{children:x.getHeaderGroups().map(n=>o(C,{className:"hover:bg-transparent",children:n.headers.map(e=>{const t=e.column.columnDef.meta;return o(fe,{align:t?.align??(t?.numeric?"right":void 0),"aria-sort":e.isPlaceholder?void 0:ke(e.column),style:B(e.column),className:D(he,Y,e.column.id===b&&"w-10",J,t?.headerClassName),children:e.isPlaceholder?null:v(e.column.columnDef.header,e.getContext())},e.id)})},n.id))}),o(ue,{children:d?Array.from({length:m}).map((n,e)=>o(C,{className:"hover:bg-transparent",children:Array.from({length:w}).map((t,s)=>o(E,{className:F,children:o(ge,{className:"h-4 w-full max-w-[160px]"})},`skeleton-${e}-${s}`))},`skeleton-${e}`)):c===0?o(C,{className:"hover:bg-transparent",children:o(E,{colSpan:w,className:"p-0",children:o(pe,{title:u?.title??"Nothing here yet",titleAs:u?.titleAs,description:u?.description,icon:u?.icon,action:u?.action,ruled:u?.ruled??true})})}):M.map((n,e)=>o(C,{ref:l?t=>{if(t)g.current.set(e,t);else g.current.delete(e)}:void 0,tabIndex:l?e===ee?0:-1:void 0,onFocus:l?()=>{_.current=true;H(e)}:void 0,onBlur:l?ne:void 0,onKeyDown:l?t=>te(t,n,e):void 0,className:l?Ne:void 0,"data-state":i&&n.getIsSelected()?"selected":void 0,children:n.getVisibleCells().map(t=>{const s=t.column.columnDef.meta;const f=v(t.column.columnDef.cell,t.getContext());if(s?.renderOwnCell){return o(re,{children:f},t.id)}const P=s?.align??(s?.numeric?"right":void 0);return o(E,{style:B(t.column),className:D(s?.numeric&&be,P&&Se[P],F,t.column.id===b&&"w-10",s?.className),onClick:t.column.id===b?_e:void 0,children:f},t.id)})},n.id))}),I?o(de,{children:I}):null]})]})}
@@ -1,112 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- /**
4
- * DateRangePicker — a two-segment popover range control.
5
- *
6
- * Two labelled trigger segments (from / to) each open the SAME two-month
7
- * react-day-picker range calendar over the same range selection. The external
8
- * contract is plain YYYY-MM-DD strings (empty string = unset) so state shapes
9
- * that speak `date_from`/`date_to` stay untouched. The picker guarantees
10
- * from <= to (react-day-picker reorders inverted picks);
11
- * aria-invalid/aria-describedby pass-throughs keep external validation wiring
12
- * alive. i18n is via plain string/locale props.
13
- *
14
- * ONE POPOVER ROOT PER SEGMENT, deliberately. A single `Popover.Root` holds ONE
15
- * trigger ref and ONE open state, so wrapping the whole two-button row in a
16
- * single `PopoverTrigger asChild` put Radix's dialog attributes
17
- * (`aria-haspopup`, `aria-expanded`, `aria-controls`) on a plain, non-focusable
18
- * `div` — an aria-allowed-attr violation, two buttons advertising the same
19
- * expanded state, and focus that Radix could drop on `document.body` when the
20
- * popover closed. Each segment is now a real `PopoverTrigger` button: focusable,
21
- * correctly named, and the element Radix returns focus to on dismissal.
22
- */
23
- import { useEffect, useState } from 'react';
24
- import { CalendarDays } from 'lucide-react';
25
- import { enUS } from 'react-day-picker/locale';
26
- import { Button } from '../../components/ui/button/index.js';
27
- import { Calendar } from '../../components/ui/calendar/index.js';
28
- import { Label } from '../../components/ui/label/index.js';
29
- import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover/index.js';
30
- import { cn } from '../../lib/utils.js';
31
- /** Leading YYYY-MM-DD of an ISO date (or date-time) string. */
32
- const ISO_DAY = /^(\d{4})-(\d{2})-(\d{2})/;
33
- /**
34
- * Parse a YYYY-MM-DD day into a LOCAL-midnight Date — the calendar works in
35
- * local time, so building from parts avoids the UTC shift `new Date(string)`
36
- * applies to date-only input (which can land the picker a day early).
37
- * Rejects impossible calendar days (e.g. 2024-02-31, which would roll over).
38
- */
39
- function parseDay(value) {
40
- const match = ISO_DAY.exec(value);
41
- if (!match)
42
- return undefined;
43
- const year = Number(match[1]);
44
- const month = Number(match[2]);
45
- const day = Number(match[3]);
46
- const parsed = new Date(year, month - 1, day);
47
- return parsed.getFullYear() === year &&
48
- parsed.getMonth() === month - 1 &&
49
- parsed.getDate() === day
50
- ? parsed
51
- : undefined;
52
- }
53
- /** Format a Date back to YYYY-MM-DD in LOCAL time (never via toISOString). */
54
- function toDayString(value) {
55
- if (!value)
56
- return '';
57
- const year = String(value.getFullYear()).padStart(4, '0');
58
- const month = String(value.getMonth() + 1).padStart(2, '0');
59
- const day = String(value.getDate()).padStart(2, '0');
60
- return `${year}-${month}-${day}`;
61
- }
62
- export function DateRangePicker({ value, onValueChange, fromId, toId, fromLabel, toLabel, invalid = false, required = false, errorId, placeholder = 'Any date', ariaLabel = 'Select date range', clearLabel = 'Clear', locale = enUS, disabled = false }) {
63
- // Which segment's popover is open, if any. One root per segment means one open
64
- // state per segment; holding the identity of the open one here keeps them
65
- // mutually exclusive, so clicking "to" while "from" is open swaps the anchor
66
- // instead of stacking two calendars.
67
- const [openSegment, setOpenSegment] = useState(null);
68
- // Suspending the control must FORGET which segment was open, not just hide
69
- // it. The `open` prop below already shuts the popover in the same frame
70
- // `disabled` flips, but a controlled Radix root never calls `onOpenChange`
71
- // for a prop-driven close, so the identity survived: lifting `disabled`
72
- // re-satisfied the same condition and the portaled calendar reopened with no
73
- // user gesture, pulling focus into it.
74
- useEffect(() => {
75
- if (disabled)
76
- setOpenSegment(null);
77
- }, [disabled]);
78
- const fromDate = parseDay(value.from);
79
- const toDate = parseDay(value.to);
80
- const selected = fromDate || toDate ? { from: fromDate, to: toDate } : undefined;
81
- // Derived from the RAW strings, not the parsed dates: a value the calendar
82
- // cannot parse still needs to be clearable, and gating Clear on `fromDate`
83
- // would strand the field holding text the user can no longer remove.
84
- const hasValue = value.from !== '' || value.to !== '';
85
- const onSelect = (range) => {
86
- onValueChange({
87
- from: toDayString(range?.from),
88
- to: toDayString(range?.to)
89
- });
90
- };
91
- const triggerClass = cn(
92
- // border-input-border, not border-input: `--input` is a SURFACE token and
93
- // is white in the light theme, so the trigger had no visible edge next to
94
- // the Input and Select it sits with. font-sans, not font-mono: the dates are
95
- // figures in the body face with tabular figures, like every other figure in
96
- // the console.
97
- 'border-input-border bg-card hover:bg-secondary focus-visible:ring-ring flex h-9 items-center gap-2 rounded-md border px-3 text-left font-sans text-sm tabular-nums transition-colors duration-150 ease-out focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:outline-none sm:w-40', invalid && 'border-destructive',
98
- // Conditional rather than `disabled:` variants, matching how this file
99
- // already applies `border-destructive`: with the prop absent the class
100
- // string stays byte-identical to what consumers render today.
101
- disabled && 'cursor-not-allowed opacity-50');
102
- // The one calendar, rendered inside whichever segment's popover is open. Both
103
- // segments read and write the SAME range selection, so which one you opened
104
- // changes only the anchor, never the state.
105
- const calendar = (_jsxs(_Fragment, { children: [_jsx(Calendar, { mode: "range", numberOfMonths: 2, defaultMonth: fromDate ?? toDate ?? new Date(), selected: selected, onSelect: onSelect, locale: locale }), _jsx("div", { className: "border-border flex items-center justify-end border-t px-3 py-2", children: _jsx(Button, { type: "button", variant: "plain", size: "small", disabled: !hasValue, onClick: () => onValueChange({ from: '', to: '' }), children: clearLabel }) })] }));
106
- const renderSegment = (segment, id, label, dateValue) => (_jsxs(Popover, {
107
- // A disabled trigger cannot open a popover, but a surface that suspends
108
- // itself WHILE one is open (a filter bar flipping to "show all") would
109
- // otherwise leave the portaled calendar on screen with no way back to it.
110
- open: !disabled && openSegment === segment, onOpenChange: (next) => setOpenSegment(next ? segment : null), children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs(Label, { htmlFor: id, children: [label, required ? ' *' : ''] }), _jsxs(PopoverTrigger, { type: "button", id: id, className: triggerClass, disabled: disabled, "aria-invalid": invalid || undefined, "aria-describedby": invalid ? errorId : undefined, children: [_jsx(CalendarDays, { className: "text-muted-foreground size-4 shrink-0", "aria-hidden": true }), dateValue ? (_jsx("span", { children: dateValue })) : (_jsx("span", { className: "text-muted-foreground", children: placeholder }))] })] }), _jsx(PopoverContent, { align: "start", className: "w-auto p-0", "aria-label": ariaLabel, children: calendar })] }, segment));
111
- return (_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-end", children: [renderSegment('from', fromId, fromLabel, value.from), renderSegment('to', toId, toLabel, value.to)] }));
112
- }
1
+ "use client";import{jsx as r,Fragment as Y,jsxs as i}from"react/jsx-runtime";import{useEffect as $,useState as z}from"react";import{CalendarDays as A}from"lucide-react";import{enUS as B}from"react-day-picker/locale";import{Button as E}from"../../components/ui/button/index.js";import{Calendar as I}from"../../components/ui/calendar/index.js";import{Label as L}from"../../components/ui/label/index.js";import{Popover as R,PopoverContent as T,PopoverTrigger as U}from"../../components/ui/popover/index.js";import{cn as q}from"../../lib/utils.js";const G=/^(\d{4})-(\d{2})-(\d{2})/;function b(e){const t=G.exec(e);if(!t)return void 0;const n=Number(t[1]);const o=Number(t[2]);const d=Number(t[3]);const s=new Date(n,o-1,d);return s.getFullYear()===n&&s.getMonth()===o-1&&s.getDate()===d?s:void 0}function x(e){if(!e)return"";const t=String(e.getFullYear()).padStart(4,"0");const n=String(e.getMonth()+1).padStart(2,"0");const o=String(e.getDate()).padStart(2,"0");return`${t}-${n}-${o}`}export function DateRangePicker({value:e,onValueChange:t,fromId:n,toId:o,fromLabel:d,toLabel:s,invalid:l=false,required:S=false,errorId:y,placeholder:D="Any date",ariaLabel:N="Select date range",clearLabel:w="Clear",locale:C=B,disabled:c=false}){const[j,u]=z(null);$(()=>{if(c)u(null)},[c]);const m=b(e.from);const f=b(e.to);const F=m||f?{from:m,to:f}:void 0;const v=e.from!==""||e.to!=="";const M=a=>{t({from:x(a?.from),to:x(a?.to)})};const O=q("border-input-border bg-card hover:bg-secondary focus-visible:ring-ring flex h-9 items-center gap-2 rounded-md border px-3 text-left font-sans text-sm tabular-nums transition-colors duration-150 ease-out focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:outline-none sm:w-40",l&&"border-destructive",c&&"cursor-not-allowed opacity-50");const P=i(Y,{children:[r(I,{mode:"range",numberOfMonths:2,defaultMonth:m??f??new Date,selected:F,onSelect:M,locale:C}),r("div",{className:"border-border flex items-center justify-end border-t px-3 py-2",children:r(E,{type:"button",variant:"plain",size:"small",disabled:!v,onClick:()=>t({from:"",to:""}),children:w})})]});const p=(a,g,_,h)=>i(R,{open:!c&&j===a,onOpenChange:k=>u(k?a:null),children:[i("div",{className:"flex flex-col gap-1.5",children:[i(L,{htmlFor:g,children:[_,S?" *":""]}),i(U,{type:"button",id:g,className:O,disabled:c,"aria-invalid":l||void 0,"aria-describedby":l?y:void 0,children:[r(A,{className:"text-muted-foreground size-4 shrink-0","aria-hidden":true}),h?r("span",{children:h}):r("span",{className:"text-muted-foreground",children:D})]})]}),r(T,{align:"start",className:"w-auto p-0","aria-label":N,children:P})]},a);return i("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-end",children:[p("from",n,d,e.from),p("to",o,s,e.to)]})}
@@ -1,17 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { X } from 'lucide-react';
4
- import { Sheet, SheetClose, SheetContent, SheetTitle } from '../../components/ui/sheet/index.js';
5
- import { cn } from '../../lib/utils.js';
6
- /**
7
- * The slide-over inspector. The header and footer stay pinned; only the body
8
- * scrolls. Sheet already renders an overlay, focus trap, and Esc/overlay
9
- * dismissal — we suppress its built-in corner close button (`[&>button.absolute]`)
10
- * and provide our own inside the header so the layout stays deliberate.
11
- */
12
- export function DetailPanel({ open, onOpenChange, title, side = 'right', actions, footer, closeLabel = 'Close', children, className }) {
13
- return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, children: _jsxs(SheetContent, { side: side, className: cn(
14
- // Reset Sheet's padding/gap and hide its built-in close button; we
15
- // own the three-slot layout and the header close affordance here.
16
- 'flex flex-col gap-0 overflow-hidden p-0', '[&>button.absolute]:hidden', className), children: [_jsxs("header", { className: "border-border bg-card sticky top-0 z-10 flex shrink-0 items-start justify-between gap-3 border-b px-6 py-4", children: [_jsx(SheetTitle, { className: "min-w-0 flex-1 truncate text-base font-semibold tracking-tight", children: title }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [actions, _jsx(SheetClose, { "data-slot": "detail-panel-close", className: "ring-offset-background focus:ring-ring rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:outline-none disabled:pointer-events-none", "aria-label": closeLabel, children: _jsx(X, { className: "size-4", "aria-hidden": true }) })] })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx("div", { className: "px-6 py-5", children: children }) }), footer ? (_jsx("footer", { className: "border-border bg-card sticky bottom-0 z-10 flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-4 sm:flex-row sm:justify-end", children: footer })) : null] }) }));
17
- }
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{X as m}from"lucide-react";import{Sheet as h,SheetClose as f,SheetContent as p,SheetTitle as b}from"../../components/ui/sheet/index.js";import{cn as x}from"../../lib/utils.js";export function DetailPanel({open:t,onOpenChange:i,title:n,side:o="right",actions:a,footer:s,closeLabel:l="Close",children:c,className:d}){return e(h,{open:t,onOpenChange:i,children:r(p,{side:o,className:x("flex flex-col gap-0 overflow-hidden p-0","[&>button.absolute]:hidden",d),children:[r("header",{className:"border-border bg-card sticky top-0 z-10 flex shrink-0 items-start justify-between gap-3 border-b px-6 py-4",children:[e(b,{className:"min-w-0 flex-1 truncate text-base font-semibold tracking-tight",children:n}),r("div",{className:"flex shrink-0 items-center gap-1.5",children:[a,e(f,{"data-slot":"detail-panel-close",className:"ring-offset-background focus:ring-ring rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:outline-none disabled:pointer-events-none","aria-label":l,children:e(m,{className:"size-4","aria-hidden":true})})]})]}),e("div",{className:"min-h-0 flex-1 overflow-y-auto",children:e("div",{className:"px-6 py-5",children:c})}),s?e("footer",{className:"border-border bg-card sticky bottom-0 z-10 flex shrink-0 flex-col-reverse gap-2 border-t px-6 py-4 sm:flex-row sm:justify-end",children:s}):null]})})}
@@ -26,7 +26,12 @@ export type EmptyStateProps = {
26
26
  * a void. Pairs with the app-side pre-ruled empty-rows fill. Default off.
27
27
  */
28
28
  ruled?: boolean;
29
+ /**
30
+ * Renders the title as this heading element, so screen-reader heading
31
+ * navigation reaches the empty state. Omit to keep today's plain text.
32
+ */
33
+ titleAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
29
34
  className?: string;
30
35
  };
31
- export declare function EmptyState({ icon: Icon, title, description, action, ruled, className }: EmptyStateProps): import("react").JSX.Element;
36
+ export declare function EmptyState({ icon: Icon, title, description, action, ruled, titleAs, className }: EmptyStateProps): import("react").JSX.Element;
32
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/empty-state/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EAAE,IAAY,EAClB,KAAK,EACL,WAAW,EACX,MAAM,EACN,KAAa,EACb,SAAS,EACV,EAAE,eAAe,+BA6CjB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/enterprise/empty-state/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,eAAe,GAAG;IAC5B,gDAAgD;IAChD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EAAE,IAAY,EAClB,KAAK,EACL,WAAW,EACX,MAAM,EACN,KAAa,EACb,OAAO,EACP,SAAS,EACV,EAAE,eAAe,+BA+CjB"}