@lerianstudio/sindarian-ui 2.0.0-beta.25 → 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 (305) 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.js +1 -96
  11. package/dist/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -55
  12. package/dist/components/dialog/index.js +1 -19
  13. package/dist/components/dialog/large-dialog/index.js +1 -21
  14. package/dist/components/entity-box/index.js +1 -67
  15. package/dist/components/entity-data-table/index.js +1 -20
  16. package/dist/components/form/combo-box-field/index.js +1 -35
  17. package/dist/components/form/country-field/index.js +1 -11
  18. package/dist/components/form/date-picker-field/index.js +1 -83
  19. package/dist/components/form/date-range-field/index.js +1 -58
  20. package/dist/components/form/date-time-picker-field/index.js +1 -114
  21. package/dist/components/form/file-upload-field/index.js +1 -69
  22. package/dist/components/form/index.js +1 -31
  23. package/dist/components/form/input-field/index.js +1 -96
  24. package/dist/components/form/otp-field/index.js +1 -19
  25. package/dist/components/form/pagination-limit-field/index.js +1 -10
  26. package/dist/components/form/password-field/index.js +1 -16
  27. package/dist/components/form/radio-group-field/index.js +1 -36
  28. package/dist/components/form/renderable-label.js +1 -57
  29. package/dist/components/form/select-field/index.js +1 -68
  30. package/dist/components/form/state-field/index.js +1 -42
  31. package/dist/components/form/switch-field/index.js +1 -16
  32. package/dist/components/form/textarea-field/index.js +1 -23
  33. package/dist/components/page/index.js +1 -20
  34. package/dist/components/page-header/index.js +1 -80
  35. package/dist/components/pagination/index.js +1 -10
  36. package/dist/components/table/id-table-cell.js +1 -109
  37. package/dist/components/table/index.js +1 -19
  38. package/dist/components/table/locked-table-actions.js +1 -41
  39. package/dist/components/table/name-table-cell.js +1 -58
  40. package/dist/components/ui/accordion/index.js +1 -62
  41. package/dist/components/ui/alert/index.js +1 -45
  42. package/dist/components/ui/alert-dialog/index.js +1 -84
  43. package/dist/components/ui/autocomplete/index.js +1 -440
  44. package/dist/components/ui/autosize-textarea/index.js +1 -89
  45. package/dist/components/ui/avatar/index.js +1 -51
  46. package/dist/components/ui/badge/index.js +1 -83
  47. package/dist/components/ui/breadcrumb/index.js +1 -35
  48. package/dist/components/ui/button/index.js +1 -65
  49. package/dist/components/ui/calendar/index.js +1 -118
  50. package/dist/components/ui/card/index.js +1 -32
  51. package/dist/components/ui/checkbox/index.js +1 -44
  52. package/dist/components/ui/collapsible/index.js +1 -50
  53. package/dist/components/ui/command/index.js +1 -95
  54. package/dist/components/ui/copy-field/index.js +1 -163
  55. package/dist/components/ui/dialog/index.js +1 -80
  56. package/dist/components/ui/dropdown-menu/index.js +1 -110
  57. package/dist/components/ui/field/index.js +1 -82
  58. package/dist/components/ui/file-upload/index.js +1 -574
  59. package/dist/components/ui/form.js +1 -162
  60. package/dist/components/ui/hover-card/index.js +1 -51
  61. package/dist/components/ui/icon-button/index.js +1 -35
  62. package/dist/components/ui/input/adornment.js +1 -21
  63. package/dist/components/ui/input/index.js +1 -99
  64. package/dist/components/ui/label/index.js +1 -45
  65. package/dist/components/ui/lerian-wordmark/index.js +1 -7
  66. package/dist/components/ui/loading-button/index.js +1 -9
  67. package/dist/components/ui/multiple-select/index.js +1 -235
  68. package/dist/components/ui/otp-input/index.js +1 -62
  69. package/dist/components/ui/paper/index.js +1 -8
  70. package/dist/components/ui/paper-collapsible/index.js +1 -24
  71. package/dist/components/ui/popover/index.js +1 -55
  72. package/dist/components/ui/progress/index.js +1 -66
  73. package/dist/components/ui/qr-code/index.js +1 -27
  74. package/dist/components/ui/radio-group/index.js +1 -48
  75. package/dist/components/ui/scroll-area/index.js +1 -49
  76. package/dist/components/ui/select/index.js +1 -119
  77. package/dist/components/ui/separator/index.js +1 -43
  78. package/dist/components/ui/sheet/index.js +1 -136
  79. package/dist/components/ui/sidebar/index.js +1 -27
  80. package/dist/components/ui/sidebar/next-router.cjs +1 -119
  81. package/dist/components/ui/sidebar/sidebar-back-button.js +1 -8
  82. package/dist/components/ui/sidebar/sidebar-components.js +1 -23
  83. package/dist/components/ui/sidebar/sidebar-expand-button.js +1 -49
  84. package/dist/components/ui/sidebar/sidebar-item-button.js +1 -21
  85. package/dist/components/ui/sidebar/sidebar-item-collapsible.js +1 -52
  86. package/dist/components/ui/sidebar/sidebar-item-icon-button.js +1 -18
  87. package/dist/components/ui/sidebar/sidebar-item.js +1 -44
  88. package/dist/components/ui/sidebar/sidebar-provider.js +1 -201
  89. package/dist/components/ui/sidebar/sidebar-root.js +1 -130
  90. package/dist/components/ui/sidebar/sidebar-router.js +1 -126
  91. package/dist/components/ui/sidebar/sidebar-trigger.js +1 -57
  92. package/dist/components/ui/skeleton/index.js +1 -8
  93. package/dist/components/ui/stepper/index.js +1 -29
  94. package/dist/components/ui/switch/index.js +1 -43
  95. package/dist/components/ui/table/index.js +1 -56
  96. package/dist/components/ui/tabs/index.js +1 -55
  97. package/dist/components/ui/textarea/index.js +1 -8
  98. package/dist/components/ui/time-picker/index.js +1 -85
  99. package/dist/components/ui/toast/index.js +1 -3
  100. package/dist/components/ui/toast/toaster.js +1 -16
  101. package/dist/components/ui/toggle-group/index.js +1 -156
  102. package/dist/components/ui/tooltip/index.js +1 -81
  103. package/dist/domain/blotter/index.js +1 -20
  104. package/dist/domain/delinquency-aging/aging-buckets.js +1 -120
  105. package/dist/domain/delinquency-aging/index.js +1 -222
  106. package/dist/domain/figure/index.js +1 -19
  107. package/dist/domain/format.js +1 -137
  108. package/dist/domain/index.js +1 -43
  109. package/dist/domain/key-id/index.js +1 -174
  110. package/dist/domain/ledger-sheet/index.js +1 -28
  111. package/dist/domain/money-diff.js +1 -48
  112. package/dist/domain/money-math.js +1 -104
  113. package/dist/domain/money-text/index.js +1 -123
  114. package/dist/domain/section-label/index.js +1 -17
  115. package/dist/domain/status-rail/index.js +1 -76
  116. package/dist/domain/threshold-gauge/index.js +1 -161
  117. package/dist/enterprise/alert-banner/index.js +1 -24
  118. package/dist/enterprise/app-shell/index.js +1 -87
  119. package/dist/enterprise/cursor-pager/index.js +1 -26
  120. package/dist/enterprise/data-table/column-size.js +1 -103
  121. package/dist/enterprise/data-table/index.js +1 -345
  122. package/dist/enterprise/date-range-picker/index.js +1 -115
  123. package/dist/enterprise/detail-panel/index.js +1 -20
  124. package/dist/enterprise/empty-state/index.js +1 -14
  125. package/dist/enterprise/index.js +1 -39
  126. package/dist/enterprise/number-input/index.js +1 -252
  127. package/dist/enterprise/search-input/index.js +1 -121
  128. package/dist/enterprise/stat-card/index.js +1 -75
  129. package/dist/enterprise/status-badge/index.js +1 -120
  130. package/dist/enterprise/use-is-mobile.js +1 -68
  131. package/dist/enterprise/virtualized-table/index.js +1 -141
  132. package/dist/esm/charts/chart.js +4 -190
  133. package/dist/esm/charts/index.js +1 -3
  134. package/dist/esm/components/breadcrumb/get-breadcrumb-paths.js +1 -12
  135. package/dist/esm/components/breadcrumb/index.js +1 -30
  136. package/dist/esm/components/card/account-card/index.js +1 -53
  137. package/dist/esm/components/card/basic-card/index.js +1 -14
  138. package/dist/esm/components/card/dashboard-card/index.js +1 -14
  139. package/dist/esm/components/card/entity-card/index.js +1 -52
  140. package/dist/esm/components/card/index.js +1 -4
  141. package/dist/esm/components/dialog/confirmation-dialog/index.js +1 -60
  142. package/dist/esm/components/dialog/confirmation-dialog/use-confirm-dialog.js +1 -49
  143. package/dist/esm/components/dialog/index.js +1 -3
  144. package/dist/esm/components/dialog/large-dialog/index.js +1 -16
  145. package/dist/esm/components/entity-box/index.js +1 -56
  146. package/dist/esm/components/entity-data-table/index.js +1 -17
  147. package/dist/esm/components/form/combo-box-field/index.js +1 -28
  148. package/dist/esm/components/form/country-field/index.js +1 -7
  149. package/dist/esm/components/form/date-picker-field/index.js +1 -43
  150. package/dist/esm/components/form/date-range-field/index.js +1 -18
  151. package/dist/esm/components/form/date-time-picker-field/index.js +1 -74
  152. package/dist/esm/components/form/file-upload-field/index.js +1 -65
  153. package/dist/esm/components/form/index.js +1 -15
  154. package/dist/esm/components/form/input-field/index.js +1 -92
  155. package/dist/esm/components/form/otp-field/index.js +1 -15
  156. package/dist/esm/components/form/pagination-limit-field/index.js +1 -6
  157. package/dist/esm/components/form/password-field/index.js +1 -10
  158. package/dist/esm/components/form/radio-group-field/index.js +1 -32
  159. package/dist/esm/components/form/renderable-label.js +1 -54
  160. package/dist/esm/components/form/select-field/index.js +1 -64
  161. package/dist/esm/components/form/state-field/index.js +1 -35
  162. package/dist/esm/components/form/switch-field/index.js +1 -12
  163. package/dist/esm/components/form/textarea-field/index.js +1 -19
  164. package/dist/esm/components/page/index.js +1 -15
  165. package/dist/esm/components/page-header/index.js +1 -71
  166. package/dist/esm/components/pagination/index.js +1 -6
  167. package/dist/esm/components/table/id-table-cell.js +1 -105
  168. package/dist/esm/components/table/index.js +1 -3
  169. package/dist/esm/components/table/locked-table-actions.js +1 -37
  170. package/dist/esm/components/table/name-table-cell.js +1 -54
  171. package/dist/esm/components/ui/accordion/index.js +1 -24
  172. package/dist/esm/components/ui/alert/index.js +1 -38
  173. package/dist/esm/components/ui/alert-dialog/index.js +1 -39
  174. package/dist/esm/components/ui/autocomplete/index.js +1 -392
  175. package/dist/esm/components/ui/autosize-textarea/index.js +1 -51
  176. package/dist/esm/components/ui/avatar/index.js +1 -14
  177. package/dist/esm/components/ui/badge/index.js +1 -79
  178. package/dist/esm/components/ui/breadcrumb/index.js +1 -27
  179. package/dist/esm/components/ui/button/index.js +1 -60
  180. package/dist/esm/components/ui/calendar/index.js +1 -82
  181. package/dist/esm/components/ui/card/index.js +1 -24
  182. package/dist/esm/components/ui/checkbox/index.js +1 -9
  183. package/dist/esm/components/ui/collapsible/index.js +1 -13
  184. package/dist/esm/components/ui/command/index.js +1 -51
  185. package/dist/esm/components/ui/copy-field/index.js +1 -127
  186. package/dist/esm/components/ui/dialog/index.js +1 -36
  187. package/dist/esm/components/ui/dropdown-menu/index.js +1 -60
  188. package/dist/esm/components/ui/field/index.js +1 -71
  189. package/dist/esm/components/ui/file-upload/index.js +1 -536
  190. package/dist/esm/components/ui/form.js +1 -118
  191. package/dist/esm/components/ui/hover-card/index.js +1 -14
  192. package/dist/esm/components/ui/icon-button/index.js +1 -31
  193. package/dist/esm/components/ui/input/adornment.js +1 -17
  194. package/dist/esm/components/ui/input/index.js +1 -60
  195. package/dist/esm/components/ui/label/index.js +1 -10
  196. package/dist/esm/components/ui/lerian-wordmark/index.js +1 -4
  197. package/dist/esm/components/ui/loading-button/index.js +1 -7
  198. package/dist/esm/components/ui/multiple-select/index.js +1 -196
  199. package/dist/esm/components/ui/otp-input/index.js +1 -21
  200. package/dist/esm/components/ui/paper/index.js +1 -5
  201. package/dist/esm/components/ui/paper-collapsible/index.js +1 -19
  202. package/dist/esm/components/ui/popover/index.js +1 -17
  203. package/dist/esm/components/ui/progress/index.js +1 -31
  204. package/dist/esm/components/ui/qr-code/index.js +1 -24
  205. package/dist/esm/components/ui/radio-group/index.js +1 -12
  206. package/dist/esm/components/ui/scroll-area/index.js +1 -13
  207. package/dist/esm/components/ui/select/index.js +1 -74
  208. package/dist/esm/components/ui/separator/index.js +1 -8
  209. package/dist/esm/components/ui/sheet/index.js +1 -92
  210. package/dist/esm/components/ui/sidebar/index.js +1 -11
  211. package/dist/esm/components/ui/sidebar/next-router.cjs +1 -119
  212. package/dist/esm/components/ui/sidebar/sidebar-back-button.js +1 -5
  213. package/dist/esm/components/ui/sidebar/sidebar-components.js +1 -15
  214. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +1 -42
  215. package/dist/esm/components/ui/sidebar/sidebar-item-button.js +1 -18
  216. package/dist/esm/components/ui/sidebar/sidebar-item-collapsible.js +1 -44
  217. package/dist/esm/components/ui/sidebar/sidebar-item-icon-button.js +1 -14
  218. package/dist/esm/components/ui/sidebar/sidebar-item.js +1 -40
  219. package/dist/esm/components/ui/sidebar/sidebar-provider.js +1 -193
  220. package/dist/esm/components/ui/sidebar/sidebar-root.js +1 -126
  221. package/dist/esm/components/ui/sidebar/sidebar-router.js +1 -89
  222. package/dist/esm/components/ui/sidebar/sidebar-trigger.js +1 -53
  223. package/dist/esm/components/ui/skeleton/index.js +1 -6
  224. package/dist/esm/components/ui/stepper/index.js +1 -20
  225. package/dist/esm/components/ui/switch/index.js +1 -8
  226. package/dist/esm/components/ui/table/index.js +1 -44
  227. package/dist/esm/components/ui/tabs/index.js +1 -17
  228. package/dist/esm/components/ui/textarea/index.js +1 -6
  229. package/dist/esm/components/ui/time-picker/index.js +1 -49
  230. package/dist/esm/components/ui/toast/index.js +1 -2
  231. package/dist/esm/components/ui/toast/toaster.js +1 -13
  232. package/dist/esm/components/ui/toggle-group/index.js +1 -120
  233. package/dist/esm/components/ui/tooltip/index.js +1 -43
  234. package/dist/esm/domain/blotter/index.js +1 -16
  235. package/dist/esm/domain/delinquency-aging/aging-buckets.js +1 -115
  236. package/dist/esm/domain/delinquency-aging/index.js +1 -218
  237. package/dist/esm/domain/figure/index.js +1 -15
  238. package/dist/esm/domain/format.js +1 -128
  239. package/dist/esm/domain/index.js +1 -19
  240. package/dist/esm/domain/key-id/index.js +1 -169
  241. package/dist/esm/domain/ledger-sheet/index.js +1 -24
  242. package/dist/esm/domain/money-diff.js +1 -45
  243. package/dist/esm/domain/money-math.js +1 -98
  244. package/dist/esm/domain/money-text/index.js +1 -118
  245. package/dist/esm/domain/section-label/index.js +1 -14
  246. package/dist/esm/domain/status-rail/index.js +1 -71
  247. package/dist/esm/domain/threshold-gauge/index.js +1 -157
  248. package/dist/esm/enterprise/alert-banner/index.js +1 -21
  249. package/dist/esm/enterprise/app-shell/index.js +1 -51
  250. package/dist/esm/enterprise/cursor-pager/index.js +1 -23
  251. package/dist/esm/enterprise/data-table/column-size.js +1 -97
  252. package/dist/esm/enterprise/data-table/index.js +1 -342
  253. package/dist/esm/enterprise/date-range-picker/index.js +1 -112
  254. package/dist/esm/enterprise/detail-panel/index.js +1 -17
  255. package/dist/esm/enterprise/empty-state/index.js +1 -11
  256. package/dist/esm/enterprise/index.js +1 -22
  257. package/dist/esm/enterprise/number-input/index.js +1 -214
  258. package/dist/esm/enterprise/search-input/index.js +1 -85
  259. package/dist/esm/enterprise/stat-card/index.js +1 -72
  260. package/dist/esm/enterprise/status-badge/index.js +1 -116
  261. package/dist/esm/enterprise/use-is-mobile.js +1 -31
  262. package/dist/esm/enterprise/virtualized-table/index.js +1 -138
  263. package/dist/esm/hooks/use-click-away.js +1 -22
  264. package/dist/esm/hooks/use-pagination.js +1 -38
  265. package/dist/esm/hooks/use-stepper.js +1 -22
  266. package/dist/esm/hooks/use-time.js +1 -13
  267. package/dist/esm/hooks/use-toast.js +1 -107
  268. package/dist/esm/index.js +1 -77
  269. package/dist/esm/lib/storage/get-storage-object.js +1 -17
  270. package/dist/esm/lib/storage/get-storage.js +1 -14
  271. package/dist/esm/lib/storage/index.js +1 -2
  272. package/dist/esm/lib/typography.js +1 -31
  273. package/dist/esm/lib/utils.js +1 -41
  274. package/dist/esm/theme/get-theme-script.js +1 -41
  275. package/dist/esm/theme/index.js +1 -4
  276. package/dist/esm/theme/mode-toggle.js +1 -45
  277. package/dist/esm/theme/theme-provider.js +1 -122
  278. package/dist/esm/toast/helpers.js +1 -36
  279. package/dist/esm/toast/index.js +1 -4
  280. package/dist/esm/types/metadata-type.js +1 -1
  281. package/dist/esm/utils/countries.cjs +1 -17
  282. package/dist/esm/utils/country-utils.js +1 -18
  283. package/dist/esm/utils/currency-codes.js +1 -181
  284. package/dist/hooks/use-click-away.js +1 -29
  285. package/dist/hooks/use-pagination.js +1 -41
  286. package/dist/hooks/use-stepper.js +1 -26
  287. package/dist/hooks/use-time.js +1 -20
  288. package/dist/hooks/use-toast.js +1 -111
  289. package/dist/index.js +1 -96
  290. package/dist/lib/storage/get-storage-object.js +1 -23
  291. package/dist/lib/storage/get-storage.js +1 -17
  292. package/dist/lib/storage/index.js +1 -18
  293. package/dist/lib/typography.js +1 -34
  294. package/dist/lib/utils.js +1 -45
  295. package/dist/theme/get-theme-script.js +1 -44
  296. package/dist/theme/index.js +1 -11
  297. package/dist/theme/mode-toggle.js +1 -48
  298. package/dist/theme/theme-provider.js +1 -160
  299. package/dist/toast/helpers.js +1 -41
  300. package/dist/toast/index.js +1 -10
  301. package/dist/types/metadata-type.js +1 -2
  302. package/dist/utils/countries.cjs +1 -17
  303. package/dist/utils/country-utils.js +1 -25
  304. package/dist/utils/currency-codes.js +1 -184
  305. package/package.json +4 -3
@@ -1,74 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Button } from '../../../components/ui/button/index.js';
4
- import { Calendar } from '../../../components/ui/calendar/index.js';
5
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
6
- import { Popover, PopoverContent, PopoverTrigger } from '../../../components/ui/popover/index.js';
7
- import { TimePicker } from '../../../components/ui/time-picker/index.js';
8
- import { cn } from '../../../lib/utils.js';
9
- import dayjs from 'dayjs';
10
- import { CalendarIcon, XIcon } from 'lucide-react';
11
- import * as React from 'react';
12
- import { enUS } from 'react-day-picker/locale';
13
- export const DateTimePickerField = ({ name, label, tooltip, labelExtra, description, placeholder = 'Select date and time...', disabled, readOnly, control, required, dateFormat = 'MMM DD, YYYY HH:mm', align = 'start', locale = enUS, minDate, maxDate, defaultTime = '00:00', ...others }) => {
14
- const [open, setOpen] = React.useState(false);
15
- const parseDefaultTime = (time) => {
16
- const [h, m] = time.split(':').map(Number);
17
- return {
18
- hour: Number.isFinite(h) && h >= 0 && h <= 23 ? h : 0,
19
- minute: Number.isFinite(m) && m >= 0 && m <= 59 ? m : 0
20
- };
21
- };
22
- return (_jsx(FormField, { name: name, control: control, render: ({ field }) => {
23
- const current = field.value ? dayjs(field.value) : null;
24
- const isValid = current?.isValid() ?? false;
25
- const validCurrent = isValid ? current : null;
26
- const handleDateSelect = (date) => {
27
- if (!date)
28
- return;
29
- const time = validCurrent
30
- ? { hour: validCurrent.hour(), minute: validCurrent.minute() }
31
- : parseDefaultTime(defaultTime);
32
- const combined = dayjs(date)
33
- .hour(time.hour)
34
- .minute(time.minute)
35
- .second(0)
36
- .millisecond(0);
37
- field.onChange(combined.toISOString());
38
- };
39
- const handleTimeChange = (time) => {
40
- if (!validCurrent)
41
- return;
42
- const updated = validCurrent
43
- .hour(time.hour)
44
- .minute(time.minute)
45
- .second(0)
46
- .millisecond(0);
47
- field.onChange(updated.toISOString());
48
- };
49
- const handleClear = (e) => {
50
- e.stopPropagation();
51
- field.onChange('');
52
- setOpen(false);
53
- };
54
- const showClear = !!field.value && !readOnly && !disabled;
55
- return (_jsxs(FormItem, { required: required, children: [label && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : labelExtra, children: label })), _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsxs("div", { className: "relative w-full", children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(FormControl, { children: _jsx(Button, { variant: "outline", disabled: disabled, className: cn('bg-input hover:bg-input border-input-border text-foreground h-10 w-full justify-start rounded-md px-2.5 font-normal', readOnly && 'pointer-events-none', showClear && 'pr-8', open && 'ring-ring ring-2 ring-offset-0'), "data-testid": others['data-testid'], icon: _jsx(CalendarIcon, { className: "size-4" }), children: _jsx("span", { className: cn('text-foreground flex-1 text-left', validCurrent && 'font-bold'), children: validCurrent
56
- ? validCurrent.format(dateFormat)
57
- : placeholder }) }) }) }), showClear && (_jsx("span", { role: "button", tabIndex: 0, "aria-label": "Clear date and time", className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring absolute top-1/2 right-2 z-10 inline-flex shrink-0 -translate-y-1/2 rounded-sm outline-none focus-visible:ring-2", onClick: handleClear, onKeyDown: (e) => {
58
- if (e.key === 'Enter' || e.key === ' ') {
59
- e.preventDefault();
60
- handleClear(e);
61
- }
62
- }, children: _jsx(XIcon, { className: "size-4" }) }))] }), _jsx(PopoverContent, { className: "w-auto p-0", align: align, children: _jsxs("div", { className: "flex flex-col sm:flex-row sm:items-stretch", children: [_jsx(Calendar, { mode: "single", defaultMonth: validCurrent ? validCurrent.toDate() : undefined, selected: validCurrent ? validCurrent.toDate() : undefined, onSelect: handleDateSelect, locale: locale, disabled: (date) => {
63
- if (disabled || readOnly)
64
- return true;
65
- if (minDate &&
66
- date < dayjs(minDate).startOf('day').toDate())
67
- return true;
68
- if (maxDate &&
69
- date > dayjs(maxDate).endOf('day').toDate())
70
- return true;
71
- return false;
72
- } }), _jsx("div", { className: "bg-border hidden w-px self-stretch sm:block" }), _jsx("div", { className: "border-border border-t sm:hidden" }), _jsx(TimePicker, { hour: validCurrent ? validCurrent.hour() : undefined, minute: validCurrent ? validCurrent.minute() : undefined, onChange: handleTimeChange, disabled: disabled || readOnly || !validCurrent })] }) })] }), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] }));
73
- } }));
74
- };
1
+ "use client";import{jsx as r,jsxs as m}from"react/jsx-runtime";import{Button as O}from"../../../components/ui/button/index.js";import{Calendar as H}from"../../../components/ui/calendar/index.js";import{FormControl as V,FormDescription as _,FormField as q,FormItem as B,FormLabel as E,FormMessage as K,FormTooltip as L}from"../../../components/ui/form.js";import{Popover as R,PopoverContent as U,PopoverTrigger as X}from"../../../components/ui/popover/index.js";import{TimePicker as A}from"../../../components/ui/time-picker/index.js";import{cn as C}from"../../../lib/utils.js";import u from"dayjs";import{CalendarIcon as G,XIcon as J}from"lucide-react";import*as Q from"react";import{enUS as W}from"react-day-picker/locale";export const DateTimePickerField=({name:N,label:d,tooltip:c,labelExtra:F,description:f,placeholder:D="Select date and time...",disabled:s,readOnly:a,control:S,required:k,dateFormat:w="MMM DD, YYYY HH:mm",align:j="start",locale:I=W,minDate:h,maxDate:p,defaultTime:P="00:00",...T})=>{const[g,b]=Q.useState(false);const y=t=>{const[o,i]=t.split(":").map(Number);return{hour:Number.isFinite(o)&&o>=0&&o<=23?o:0,minute:Number.isFinite(i)&&i>=0&&i<=59?i:0}};return r(q,{name:N,control:S,render:({field:t})=>{const o=t.value?u(t.value):null;const i=o?.isValid()??false;const e=i?o:null;const M=n=>{if(!n)return;const l=e?{hour:e.hour(),minute:e.minute()}:y(P);const z=u(n).hour(l.hour).minute(l.minute).second(0).millisecond(0);t.onChange(z.toISOString())};const Y=n=>{if(!e)return;const l=e.hour(n.hour).minute(n.minute).second(0).millisecond(0);t.onChange(l.toISOString())};const v=n=>{n.stopPropagation();t.onChange("");b(false)};const x=!!t.value&&!a&&!s;return m(B,{required:k,children:[d&&r(E,{extra:c?r(L,{children:c}):F,children:d}),m(R,{open:g,onOpenChange:b,children:[m("div",{className:"relative w-full",children:[r(X,{asChild:true,children:r(V,{children:r(O,{variant:"outline",disabled:s,className:C("bg-input hover:bg-input border-input-border text-foreground h-10 w-full justify-start rounded-md px-2.5 font-normal",a&&"pointer-events-none",x&&"pr-8",g&&"ring-ring ring-2 ring-offset-0"),"data-testid":T["data-testid"],icon:r(G,{className:"size-4"}),children:r("span",{className:C("text-foreground flex-1 text-left",e&&"font-bold"),children:e?e.format(w):D})})})}),x&&r("span",{role:"button",tabIndex:0,"aria-label":"Clear date and time",className:"text-muted-foreground hover:text-foreground focus-visible:ring-ring absolute top-1/2 right-2 z-10 inline-flex shrink-0 -translate-y-1/2 rounded-sm outline-none focus-visible:ring-2",onClick:v,onKeyDown:n=>{if(n.key==="Enter"||n.key===" "){n.preventDefault();v(n)}},children:r(J,{className:"size-4"})})]}),r(U,{className:"w-auto p-0",align:j,children:m("div",{className:"flex flex-col sm:flex-row sm:items-stretch",children:[r(H,{mode:"single",defaultMonth:e?e.toDate():void 0,selected:e?e.toDate():void 0,onSelect:M,locale:I,disabled:n=>{if(s||a)return true;if(h&&n<u(h).startOf("day").toDate())return true;if(p&&n>u(p).endOf("day").toDate())return true;return false}}),r("div",{className:"bg-border hidden w-px self-stretch sm:block"}),r("div",{className:"border-border border-t sm:hidden"}),r(A,{hour:e?e.hour():void 0,minute:e?e.minute():void 0,onChange:Y,disabled:s||a||!e})]})})]}),r(K,{}),f&&r(_,{children:f})]})}})};
@@ -1,65 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
5
- import { FileUpload } from '../../../components/ui/file-upload/index.js';
6
- import { hasRenderableLabel } from '../../../components/form/renderable-label.js';
7
- /**
8
- * FileUploadField — the react-hook-form field for FileUpload.
9
- *
10
- * The field VALUE is the file's UTF-8 TEXT string (so a Zod `z.string()` PEM
11
- * schema validates directly), `''` when cleared — never the File, never null —
12
- * so `z.string().min(1)` fires the required error with zero adapter code. The
13
- * File metadata for the visible chip lives in field-LOCAL state, since the form
14
- * only holds the text. The shown chip is DERIVED from the form field value, so
15
- * an external `form.reset()` / `setValue(name, '')` that clears the text also
16
- * clears the chip — local state can never linger out of sync with the form. A
17
- * rejected pick (size/type/read) clears the form value so it can't pass
18
- * validation, while the primitive's own inline `role="alert"` announces the
19
- * rejection; on resolver failure the FormMessage announces. Both surfaces are
20
- * wired.
21
- */
22
- export const FileUploadField = ({ control, name, label, description, tooltip, required, accept, maxSizeBytes, disabled, className, labels, onError, onSelect, 'aria-label': ariaLabelProp }) => {
23
- const [localValue, setLocalValue] = useState(null);
24
- const showLabel = hasRenderableLabel(label);
25
- // An empty or whitespace-only aria-label is worse than none: it names the
26
- // control "". Drop it so the attribute never reaches the DOM.
27
- const ariaLabel = ariaLabelProp?.trim() ? ariaLabelProp : undefined;
28
- // The type cannot rule out `label=""`, so this is the only signal a developer
29
- // gets that the control shipped nameless.
30
- if (process.env.NODE_ENV !== 'production' && !showLabel && !ariaLabel) {
31
- console.error(`FileUploadField "${name}" has no accessible name: pass a non-empty label or aria-label.`);
32
- }
33
- return (_jsx(FormField, { control: control, name: name, render: ({ field }) => {
34
- // The chip follows the LOCAL selection, reconciled against the form
35
- // value — not the form value's truthiness.
36
- //
37
- // Truthiness cannot tell "no file" from "an accepted EMPTY file": both
38
- // store ''. So picking a legitimately empty file hid the chip, the zone
39
- // went back to "Choose a file or drag and drop" even though the pick was
40
- // accepted, and a `z.string().min(1)` rule then failed the field with
41
- // nothing on screen to explain why.
42
- //
43
- // Comparing against the text we last wrote keeps the external-reset
44
- // behaviour that truthiness was there for: after form.reset() or
45
- // setValue(name, ''), the stored text no longer matches the selection, so
46
- // the stale File metadata still cannot linger.
47
- //
48
- // ponytail: one residual case is irreducible from the form value alone —
49
- // resetting AFTER picking an empty file leaves the chip up, because ''
50
- // (reset) and '' (that file's text) are the same string and the form
51
- // value carries nothing else to tell them apart. Fix needs a reset epoch
52
- // from react-hook-form, or a form value richer than the file text.
53
- const shown = localValue && field.value === localValue.text ? localValue : null;
54
- return (_jsxs(FormItem, { required: required, children: [showLabel && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : undefined, children: label })), _jsx(FormControl, { children: _jsx(FileUpload, { ref: field.ref, name: field.name, onBlur: field.onBlur, "aria-label": ariaLabel, labels: labels, accept: accept, maxSizeBytes: maxSizeBytes, disabled: disabled, className: className, value: shown, onSelect: (result) => {
55
- setLocalValue(result);
56
- field.onChange(result?.text ?? '');
57
- onSelect?.(result);
58
- }, onError: (error) => {
59
- setLocalValue(null);
60
- field.onChange('');
61
- onSelect?.(null);
62
- onError?.(error);
63
- } }) }), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] }));
64
- } }));
65
- };
1
+ "use client";import{jsx as e,jsxs as v}from"react/jsx-runtime";import{useState as B}from"react";import{FormControl as C,FormDescription as E,FormField as N,FormItem as U,FormLabel as V,FormMessage as _,FormTooltip as w}from"../../../components/ui/form.js";import{FileUpload as y}from"../../../components/ui/file-upload/index.js";import{hasRenderableLabel as D}from"../../../components/form/renderable-label.js";export const FileUploadField=({control:p,name:l,label:n,description:s,tooltip:t,required:F,accept:h,maxSizeBytes:b,disabled:x,className:f,labels:j,onError:L,onSelect:m,"aria-label":i})=>{const[a,c]=B(null);const u=D(n);const d=i?.trim()?i:void 0;if(process.env.NODE_ENV!=="production"&&!u&&!d){console.error(`FileUploadField "${l}" has no accessible name: pass a non-empty label or aria-label.`)}return e(N,{control:p,name:l,render:({field:r})=>{const g=a&&r.value===a.text?a:null;return v(U,{required:F,children:[u&&e(V,{extra:t?e(w,{children:t}):void 0,children:n}),e(C,{children:e(y,{ref:r.ref,name:r.name,onBlur:r.onBlur,"aria-label":d,labels:j,accept:h,maxSizeBytes:b,disabled:x,className:f,value:g,onSelect:o=>{c(o);r.onChange(o?.text??"");m?.(o)},onError:o=>{c(null);r.onChange("");m?.(null);L?.(o)}})}),e(_,{}),s&&e(E,{children:s})]})}})};
@@ -1,15 +1 @@
1
- export * from './input-field/index.js';
2
- export * from './select-field/index.js';
3
- export * from './switch-field/index.js';
4
- export * from './pagination-limit-field/index.js';
5
- export * from './combo-box-field/index.js';
6
- export * from './country-field/index.js';
7
- export * from './state-field/index.js';
8
- export * from './date-range-field/index.js';
9
- export * from './date-picker-field/index.js';
10
- export * from './date-time-picker-field/index.js';
11
- export * from './otp-field/index.js';
12
- export * from './password-field/index.js';
13
- export * from './file-upload-field/index.js';
14
- export * from './radio-group-field/index.js';
15
- export * from './textarea-field/index.js';
1
+ export*from"./input-field/index.js";export*from"./select-field/index.js";export*from"./switch-field/index.js";export*from"./pagination-limit-field/index.js";export*from"./combo-box-field/index.js";export*from"./country-field/index.js";export*from"./state-field/index.js";export*from"./date-range-field/index.js";export*from"./date-picker-field/index.js";export*from"./date-time-picker-field/index.js";export*from"./otp-field/index.js";export*from"./password-field/index.js";export*from"./file-upload-field/index.js";export*from"./radio-group-field/index.js";export*from"./textarea-field/index.js";
@@ -1,92 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { AutosizeTextarea } from '../../../components/ui/autosize-textarea/index.js';
3
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
4
- import { Input } from '../../../components/ui/input/index.js';
5
- import { useMemo, useRef } from 'react';
6
- /**
7
- * Fan one node out to several refs. React hands a node to ONE ref, so a
8
- * consumer ref and react-hook-form's `field.ref` cannot both be passed
9
- * directly — one silently wins. Only used when the consumer actually supplied
10
- * a ref, so a field without one keeps `field.ref`'s own identity and React
11
- * never re-attaches it.
12
- */
13
- function fanOutRef(...refs) {
14
- return (node) => {
15
- const cleanups = [];
16
- for (const ref of refs) {
17
- if (typeof ref === 'function') {
18
- const cleanup = ref(node);
19
- cleanups.push(typeof cleanup === 'function' ? cleanup : () => ref(null));
20
- }
21
- else if (ref) {
22
- ;
23
- ref.current = node;
24
- cleanups.push(() => {
25
- ;
26
- ref.current = null;
27
- });
28
- }
29
- }
30
- return () => cleanups.forEach((cleanup) => cleanup());
31
- };
32
- }
33
- export const InputField = ({ className, type, label, tooltip, labelExtra, placeholder, description, startAdornment, endAdornment, required, readOnly, minHeight, maxHeight, textArea, defaultValue, value, onChange, min, max, step, maxLength, autoComplete, inputMode, pattern, autoFocus, ref, 'aria-invalid': ariaInvalid, ...others }) => {
34
- // OR with the form's error, expressed through the Slot merge rather than by
35
- // reading the form: FormControl already injects `aria-invalid={!!error}`, and
36
- // a child prop only wins that merge when the KEY is present. So emit the key
37
- // only for an explicit `true`, and let FormControl answer for every other
38
- // case. `true || error` is true; `false || error` is whatever the form says,
39
- // which is the whole point — an explicit `false` cannot mute a live error.
40
- // With no `control` there is no error to OR against, so FormControl injects
41
- // `false` and today's behaviour is unchanged.
42
- const ariaInvalidProp = ariaInvalid ? { 'aria-invalid': true } : undefined;
43
- const formRef = useRef(undefined);
44
- const composedRef = useMemo(() => ref ? fanOutRef((node) => formRef.current?.(node), ref) : ref,
45
- // `others.name` belongs here, and leaving it out is not a lint nit.
46
- // react-hook-form hands a fresh `field.ref` for every name, and that ref
47
- // only receives the element when React reattaches, which it does only when
48
- // this callback's identity changes. Memoised on `ref` alone, one identity
49
- // survived a name change, the new field never got its element, and
50
- // `form.setFocus(newName)` then found nothing to focus and said nothing.
51
- [ref, others.name]);
52
- const renderItem = (binding) => (_jsxs(FormItem, { required: required, children: [label && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : labelExtra, children: label })), _jsx(FormControl, { children: textArea ? (_jsx(AutosizeTextarea, { className: className, placeholder: placeholder, readOnly: readOnly, minHeight: minHeight, maxHeight: maxHeight, maxLength: maxLength, autoComplete: autoComplete, inputMode: inputMode, autoFocus: autoFocus, "data-testid": others['data-testid'], ...ariaInvalidProp, ...binding })) : (_jsx(Input, { className: className, type: type, placeholder: placeholder, readOnly: readOnly, startAdornment: startAdornment, endAdornment: endAdornment,
53
- // Bounds belong to the single-line control only: `min`/`max`/`step`
54
- // mean nothing on a textarea and would render as invalid markup.
55
- min: min, max: max, step: step, maxLength: maxLength, autoComplete: autoComplete, inputMode: inputMode,
56
- // Single-line only: `<textarea pattern>` is not a thing.
57
- pattern: pattern, autoFocus: autoFocus, "data-testid": others['data-testid'], ...ariaInvalidProp, ...binding })) }), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] }));
58
- if (!others.control) {
59
- return renderItem({
60
- name: others.name,
61
- disabled: others.disabled,
62
- // Controlled when the caller holds the value, uncontrolled when it only
63
- // seeds one — supplying both is what React warns about.
64
- ...(value !== undefined ? { value } : { defaultValue }),
65
- onChange: (e) => onChange?.(e),
66
- // Nothing else claims the node on this branch, so the consumer ref goes
67
- // straight through. Without it there was no node to focus at all.
68
- ref: ref
69
- });
70
- }
71
- return (_jsx(FormField, { ...others, name: others.name,
72
- // The seed goes through react-hook-form, never straight to the DOM: a
73
- // value painted on the box only makes the field LOOK filled while the
74
- // form still submits nothing for that name. Controller seeds its own
75
- // state from this, so `field.value` carries the seed on both branches.
76
- defaultValue: defaultValue, render: ({ field }) => {
77
- formRef.current = field.ref;
78
- return renderItem({
79
- ...field,
80
- // Controlled from mount. react-hook-form hands `undefined` for any
81
- // name the form declares no default for; React then mounts the box
82
- // uncontrolled and flips it on the first keystroke, losing that
83
- // character.
84
- value: field.value ?? '',
85
- onChange: (e) => {
86
- field.onChange(e);
87
- onChange?.(e);
88
- },
89
- ref: (ref ? composedRef : field.ref)
90
- });
91
- } }));
92
- };
1
+ import{jsx as t,jsxs as D}from"react/jsx-runtime";import{AutosizeTextarea as E}from"../../../components/ui/autosize-textarea/index.js";import{FormControl as N,FormDescription as P,FormField as k,FormItem as w,FormLabel as B,FormMessage as G,FormTooltip as J}from"../../../components/ui/form.js";import{Input as K}from"../../../components/ui/input/index.js";import{useMemo as Q,useRef as S}from"react";function U(...i){return m=>{const a=[];for(const n of i){if(typeof n==="function"){const u=n(m);a.push(typeof u==="function"?u:()=>n(null))}else if(n){;n.current=m;a.push(()=>{;n.current=null})}}return()=>a.forEach(n=>n())}}export const InputField=({className:i,type:m,label:a,tooltip:n,labelExtra:u,placeholder:d,description:s,startAdornment:C,endAdornment:R,required:A,readOnly:c,minHeight:M,maxHeight:H,textArea:L,defaultValue:l,value:p,onChange:f,min:O,max:T,step:_,maxLength:x,autoComplete:F,inputMode:h,pattern:b,autoFocus:g,ref:o,"aria-invalid":q,...r})=>{const I=q?{"aria-invalid":true}:void 0;const j=S(void 0);const z=Q(()=>o?U(e=>j.current?.(e),o):o,[o,r.name]);const v=e=>D(w,{required:A,children:[a&&t(B,{extra:n?t(J,{children:n}):u,children:a}),t(N,{children:L?t(E,{className:i,placeholder:d,readOnly:c,minHeight:M,maxHeight:H,maxLength:x,autoComplete:F,inputMode:h,autoFocus:g,"data-testid":r["data-testid"],...I,...e}):t(K,{className:i,type:m,placeholder:d,readOnly:c,startAdornment:C,endAdornment:R,min:O,max:T,step:_,maxLength:x,autoComplete:F,inputMode:h,pattern:b,autoFocus:g,"data-testid":r["data-testid"],...I,...e})}),t(G,{}),s&&t(P,{children:s})]});if(!r.control){return v({name:r.name,disabled:r.disabled,...p!==void 0?{value:p}:{defaultValue:l},onChange:e=>f?.(e),ref:o})}return t(k,{...r,name:r.name,defaultValue:l,render:({field:e})=>{j.current=e.ref;return v({...e,value:e.value??"",onChange:y=>{e.onChange(y);f?.(y)},ref:o?z:e.ref})}})};
@@ -1,15 +1 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
3
- import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from '../../../components/ui/otp-input/index.js';
4
- export const OtpField = ({ name, label, tooltip, labelExtra, description, maxLength = 6, pattern, separator = false, ...others }) => {
5
- const midpoint = Math.floor(maxLength / 2);
6
- const renderSlots = () => {
7
- if (separator && maxLength > 1) {
8
- const firstGroup = Array.from({ length: midpoint }, (_, i) => (_jsx(InputOTPSlot, { index: i }, i)));
9
- const secondGroup = Array.from({ length: maxLength - midpoint }, (_, i) => _jsx(InputOTPSlot, { index: midpoint + i }, midpoint + i));
10
- return (_jsxs(_Fragment, { children: [_jsx(InputOTPGroup, { children: firstGroup }), _jsx(InputOTPSeparator, {}), _jsx(InputOTPGroup, { children: secondGroup })] }));
11
- }
12
- return (_jsx(InputOTPGroup, { children: Array.from({ length: maxLength }, (_, i) => (_jsx(InputOTPSlot, { index: i }, i))) }));
13
- };
14
- return (_jsx(FormField, { ...others, name: name, render: ({ field }) => (_jsxs(FormItem, { required: others.required, children: [label && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : labelExtra, children: label })), _jsx(FormControl, { children: _jsx(InputOTP, { maxLength: maxLength, pattern: pattern, value: field.value ?? '', onChange: field.onChange, onBlur: field.onBlur, ref: field.ref, name: field.name, disabled: others.disabled, "data-testid": others['data-testid'], children: renderSlots() }) }), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] })) }));
15
- };
1
+ import{jsx as r,Fragment as g,jsxs as u}from"react/jsx-runtime";import{FormControl as I,FormDescription as O,FormField as T,FormItem as j,FormLabel as P,FormMessage as y,FormTooltip as A}from"../../../components/ui/form.js";import{InputOTP as C,InputOTPGroup as i,InputOTPSlot as l,InputOTPSeparator as G}from"../../../components/ui/otp-input/index.js";export const OtpField=({name:p,label:s,tooltip:m,labelExtra:F,description:c,maxLength:n=6,pattern:h,separator:f=false,...t})=>{const a=Math.floor(n/2);const x=()=>{if(f&&n>1){const e=Array.from({length:a},(_,o)=>r(l,{index:o},o));const d=Array.from({length:n-a},(_,o)=>r(l,{index:a+o},a+o));return u(g,{children:[r(i,{children:e}),r(G,{}),r(i,{children:d})]})}return r(i,{children:Array.from({length:n},(e,d)=>r(l,{index:d},d))})};return r(T,{...t,name:p,render:({field:e})=>u(j,{required:t.required,children:[s&&r(P,{extra:m?r(A,{children:m}):F,children:s}),r(I,{children:r(C,{maxLength:n,pattern:h,value:e.value??"",onChange:e.onChange,onBlur:e.onBlur,ref:e.ref,name:e.name,disabled:t.disabled,"data-testid":t["data-testid"],children:x()})}),r(y,{}),c&&r(O,{children:c})]})})};
@@ -1,6 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { SelectField } from '../select-field/index.js';
3
- import { SelectItem } from '../../../components/ui/select/index.js';
4
- export const PaginationLimitField = ({ options = [10, 50, 100], label = 'Items per page', control, ['data-testid']: dataTestId }) => {
5
- return (_jsxs("div", { className: "flex items-center gap-4", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium whitespace-nowrap", children: label }), _jsx(SelectField, { name: "limit", control: control, "data-testid": dataTestId, children: options.map((pageSize) => (_jsx(SelectItem, { value: String(pageSize), children: pageSize }, pageSize))) })] }));
6
- };
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import{SelectField as n}from"../select-field/index.js";import{SelectItem as o}from"../../../components/ui/select/index.js";export const PaginationLimitField=({options:i=[10,50,100],label:r="Items per page",control:m,["data-testid"]:s})=>{return a("div",{className:"flex items-center gap-4",children:[e("p",{className:"text-muted-foreground text-sm font-medium whitespace-nowrap",children:r}),e(n,{name:"limit",control:m,"data-testid":s,children:i.map(t=>e(o,{value:String(t),children:t},t))})]})};
@@ -1,10 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from 'react';
3
- import { FormControl, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
4
- import { Input, InputAdornment } from '../../../components/ui/input/index.js';
5
- import { Eye, EyeOff } from 'lucide-react';
6
- import { IconButton } from '../../../components/ui/icon-button/index.js';
7
- export function PasswordField({ name, label, tooltip, placeholder, control, required = false, disabled = false, 'data-testid': dataTestId, showPasswordLabel = 'Show password', hidePasswordLabel = 'Hide password' }) {
8
- const [show, setShow] = React.useState(false);
9
- return (_jsx(FormField, { control: control, name: name, render: ({ field }) => (_jsxs(FormItem, { required: required, children: [_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : undefined, children: label }), _jsx(FormControl, { children: _jsx(Input, { ...field, type: show ? 'text' : 'password', placeholder: placeholder, endAdornment: _jsx(InputAdornment, { position: "end", children: _jsx(IconButton, { type: "button", variant: "outline", rounded: true, "aria-label": show ? hidePasswordLabel : showPasswordLabel, onClick: () => setShow(!show), children: show ? _jsx(EyeOff, { "aria-hidden": true }) : _jsx(Eye, { "aria-hidden": true }) }) }), disabled: disabled, "data-testid": dataTestId }) }), _jsx(FormMessage, {})] })) }));
10
- }
1
+ import{jsx as e,jsxs as f}from"react/jsx-runtime";import h from"react";import{FormControl as F,FormField as w,FormItem as x,FormLabel as b,FormMessage as j,FormTooltip as y}from"../../../components/ui/form.js";import{Input as I,InputAdornment as S}from"../../../components/ui/input/index.js";import{Eye as A,EyeOff as C}from"lucide-react";import{IconButton as E}from"../../../components/ui/icon-button/index.js";export function PasswordField({name:t,label:d,tooltip:o,placeholder:n,control:i,required:a=false,disabled:s=false,"data-testid":m,showPasswordLabel:l="Show password",hidePasswordLabel:p="Hide password"}){const[r,u]=h.useState(false);return e(w,{control:i,name:t,render:({field:c})=>f(x,{required:a,children:[e(b,{extra:o?e(y,{children:o}):void 0,children:d}),e(F,{children:e(I,{...c,type:r?"text":"password",placeholder:n,endAdornment:e(S,{position:"end",children:e(E,{type:"button",variant:"outline",rounded:true,"aria-label":r?p:l,onClick:()=>u(!r),children:r?e(C,{"aria-hidden":true}):e(A,{"aria-hidden":true})})}),disabled:s,"data-testid":m})}),e(j,{})]})})}
@@ -1,32 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useId } from 'react';
4
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
5
- import { Label } from '../../../components/ui/label/index.js';
6
- import { RadioGroup, RadioGroupItem } from '../../../components/ui/radio-group/index.js';
7
- import { hasRenderableLabel } from '../../../components/form/renderable-label.js';
8
- export const RadioGroupField = ({ control, name, options, label, description, tooltip, required, disabled, 'aria-label': ariaLabelProp }) => {
9
- const showLabel = hasRenderableLabel(label);
10
- // An empty or whitespace-only aria-label is worse than none: it names the
11
- // control "". Drop it so the attribute never reaches the DOM.
12
- const ariaLabel = ariaLabelProp?.trim() ? ariaLabelProp : undefined;
13
- // `FormLabel` names its control through `htmlFor`, which only works on a
14
- // labelable element — and the Radix radiogroup root is a plain div. So the
15
- // visible label reached nobody: a screen-reader user landing on the group
16
- // heard the options and no field name. The group points BACK at the label
17
- // instead, via aria-labelledby on a stable generated id.
18
- const labelId = useId();
19
- // The type cannot rule out `label=""`, so this is the only signal a developer
20
- // gets that the control shipped nameless.
21
- if (process.env.NODE_ENV !== 'production' && !showLabel && !ariaLabel) {
22
- console.error(`RadioGroupField "${name}" has no accessible name: pass a non-empty label or aria-label.`);
23
- }
24
- // `setFocus(name)` / focus-on-error needs a ref to something focusable. The
25
- // RadioGroup root is a plain div, so the ref goes on the first option a user
26
- // could actually reach — a disabled radio is not focusable.
27
- const focusTargetIndex = options.findIndex((option) => !option.disabled);
28
- return (_jsx(FormField, { control: control, name: name, render: ({ field }) => (_jsxs(FormItem, { required: required, children: [showLabel && (_jsx(FormLabel, { id: labelId, extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : undefined, children: label })), _jsx(FormControl, { children: _jsx(RadioGroup, { name: field.name, value: field.value ?? '', onValueChange: field.onChange, onBlur: field.onBlur, disabled: disabled, "aria-labelledby": showLabel ? labelId : undefined, "aria-label": showLabel ? undefined : ariaLabel, className: "gap-2", children: options.map((option, index) => {
29
- const id = `${name}-${option.value}`;
30
- return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(RadioGroupItem, { ref: index === focusTargetIndex ? field.ref : undefined, value: option.value, id: id, disabled: option.disabled }), _jsx(Label, { htmlFor: id, className: "font-normal", children: option.label })] }, option.value));
31
- }) }) }), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] })) }));
32
- };
1
+ "use client";import{jsx as e,jsxs as b}from"react/jsx-runtime";import{useId as v}from"react";import{FormControl as g,FormDescription as I,FormField as N,FormItem as R,FormLabel as j,FormMessage as G,FormTooltip as L}from"../../../components/ui/form.js";import{Label as C}from"../../../components/ui/label/index.js";import{RadioGroup as _,RadioGroupItem as $}from"../../../components/ui/radio-group/index.js";import{hasRenderableLabel as y}from"../../../components/form/renderable-label.js";export const RadioGroupField=({control:f,name:n,options:o,label:d,description:s,tooltip:i,required:h,disabled:p,"aria-label":m})=>{const l=y(d);const c=m?.trim()?m:void 0;const u=v();if(process.env.NODE_ENV!=="production"&&!l&&!c){console.error(`RadioGroupField "${n}" has no accessible name: pass a non-empty label or aria-label.`)}const F=o.findIndex(r=>!r.disabled);return e(N,{control:f,name:n,render:({field:r})=>b(R,{required:h,children:[l&&e(j,{id:u,extra:i?e(L,{children:i}):void 0,children:d}),e(g,{children:e(_,{name:r.name,value:r.value??"",onValueChange:r.onChange,onBlur:r.onBlur,disabled:p,"aria-labelledby":l?u:void 0,"aria-label":l?void 0:c,className:"gap-2",children:o.map((a,x)=>{const t=`${n}-${a.value}`;return b("div",{className:"flex items-center gap-2",children:[e($,{ref:x===F?r.ref:void 0,value:a.value,id:t,disabled:a.disabled}),e(C,{htmlFor:t,className:"font-normal",children:a.label})]},a.value)})})}),e(G,{}),s&&e(I,{children:s})]})})};
@@ -1,54 +1 @@
1
- import { Children, Fragment, isValidElement } from 'react';
2
- /**
3
- * Does this label put readable content INSIDE the label element — i.e. does it
4
- * give the control an accessible name?
5
- *
6
- * Ceiling, on purpose: a non-fragment element always counts, even an empty one.
7
- * We cannot render a component to find out whether it emits text, so
8
- * `label={<EmptyThing />}` is accepted. Fragments ARE unwrapped, since they add
9
- * no markup of their own and `<></>` is a plausible way to say "no label".
10
- *
11
- * A PORTAL DOES NOT COUNT. It is the one node that renders its content
12
- * somewhere else in the DOM — by definition outside the label subtree — so the
13
- * label element itself stays empty and names nothing. The content is visible on
14
- * screen, which is exactly what makes this worth guarding: it looks labelled
15
- * and is silent to a screen reader. Pass `aria-label` when the visible text
16
- * lives in a portal.
17
- *
18
- * BRANCH ORDER IS LOAD-BEARING — element before portal before collection:
19
- * `Children.toArray` hands a portal straight back unchanged, so reaching the
20
- * collection branch with one would recurse forever. The portal branch is the
21
- * crash guard as much as the verdict. Every field in this directory shares this
22
- * one copy precisely so that ordering cannot drift.
23
- */
24
- export function hasRenderableLabel(label) {
25
- if (label === null || label === undefined || typeof label === 'boolean') {
26
- return false;
27
- }
28
- // Empty AND whitespace-only strings render a label box with nothing to
29
- // announce, so both count as absent. A number (`0`) is a real label.
30
- if (typeof label === 'string')
31
- return label.trim() !== '';
32
- if (typeof label === 'number' || typeof label === 'bigint')
33
- return true;
34
- if (isValidElement(label)) {
35
- return label.type === Fragment
36
- ? hasRenderableLabel(label.props?.children ?? null)
37
- : true;
38
- }
39
- // Portals and any other React-internal node that is not an element: their
40
- // content lands outside this subtree (or is unknowable), so it cannot name
41
- // the control. Must stay ABOVE the collection branch: isValidElement is false
42
- // for a portal and Children.toArray hands the identical node straight back,
43
- // so recursing on it would never terminate.
44
- if (typeof label === 'object' && '$$typeof' in label)
45
- return false;
46
- const children = Children.toArray(label);
47
- // Belt for anything else toArray cannot break down: no progress left to make,
48
- // and nothing we can confirm renders in place, so treat it as absent rather
49
- // than recurse forever.
50
- if (children.length === 1 && children[0] === label)
51
- return false;
52
- // Arrays and other iterables: renderable only if some child is.
53
- return children.some((child) => hasRenderableLabel(child));
54
- }
1
+ import{Children as e,Fragment as i,isValidElement as f}from"react";export function hasRenderableLabel(r){if(r===null||r===void 0||typeof r==="boolean"){return false}if(typeof r==="string")return r.trim()!=="";if(typeof r==="number"||typeof r==="bigint")return true;if(f(r)){return r.type===i?hasRenderableLabel(r.props?.children??null):true}if(typeof r==="object"&&"$$typeof"in r)return false;const t=e.toArray(r);if(t.length===1&&t[0]===r)return false;return t.some(n=>hasRenderableLabel(n))}
@@ -1,64 +1 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
3
- import { MultipleSelect, MultipleSelectContent, MultipleSelectTrigger, MultipleSelectValue } from '../../../components/ui/multiple-select/index.js';
4
- import { Select, SelectContent, SelectEmpty, SelectTrigger, SelectValue } from '../../../components/ui/select/index.js';
5
- import { cn } from '../../../lib/utils.js';
6
- export const SelectField = ({ name, label, tooltip, labelExtra, required, placeholder, description, disabled, readOnly, multi, control, value, children, emptyMessage = 'No options found.', leadingIcon, className, onChange, ...others }) => {
7
- // The props union already pairs `multi` with the callback shape that branch
8
- // emits, but destructuring an intersection loses that correlation — TS sees
9
- // two unrelated callbacks. Both branches report through this one seam, each
10
- // with the payload its own union member declared.
11
- const emitChange = onChange;
12
- /**
13
- * ⛔ THE GLYPH AND THE VALUE ARE ONE FLEX CHILD, NEVER TWO.
14
- *
15
- * `.select-trigger` is `flex w-full items-center justify-between`, so a
16
- * third child makes it split the free space into TWO gaps: on any trigger
17
- * wider than its content — which is every filter bar — the selected value
18
- * drifted to the middle of the box instead of sitting beside the glyph.
19
- * Wrapped, the trigger is back to two children, content and chevron,
20
- * whatever the caller passes.
21
- *
22
- * `min-w-0` keeps the value truncating: the wrapper is the flex item now,
23
- * and a flex item never shrinks below its own min-content width. The
24
- * trigger's `VALUE_OVERFLOW_CLASS` reaches through it by descendant
25
- * selector.
26
- *
27
- * No `gap`: the prop's contract is that spacing is the caller's (the Tracer
28
- * filter bars carry their own `mr-2`), and a kit gap would double with it.
29
- *
30
- * The MULTI trigger needs none of this — it already renders its children
31
- * inside one `flex grow flex-wrap` box, so the icon already shares a parent
32
- * with the value and the trigger root already has exactly two children.
33
- * Wrapping there would put the selected-value badges in a non-wrapping row
34
- * and stop the trigger growing to a second line.
35
- */
36
- const withLeadingIcon = (value) => leadingIcon ? (_jsxs("span", { className: "flex min-w-0 items-center", children: [leadingIcon, value] })) : (value);
37
- const renderItem = (field) => {
38
- return (_jsxs(FormItem, { required: required, className: className, children: [label && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : labelExtra, children: label })), multi ? (_jsxs(MultipleSelect, { onValueChange: (value) => {
39
- field.onChange(value);
40
- emitChange?.(value);
41
- }, disabled: disabled, ...field, children: [_jsxs(MultipleSelectTrigger, { readOnly: readOnly, children: [leadingIcon, _jsx(MultipleSelectValue, { placeholder: placeholder })] }), _jsx(MultipleSelectContent, { children: children })] })) : (_jsxs(Select, { onValueChange: (value) => {
42
- field.onChange(value);
43
- emitChange?.(value);
44
- }, value: field.value, disabled: disabled, open: readOnly ? false : undefined, onOpenChange: readOnly ? () => { } : undefined, children: [_jsx(FormControl, { children: _jsx(SelectTrigger, { className: cn(disabled && 'bg-shadcn-100'), readOnly: readOnly, "data-testid": others['data-testid'], children: withLeadingIcon(_jsx(SelectValue, { placeholder: placeholder })) }) }), _jsxs(SelectContent, { children: [_jsx(SelectEmpty, { children: emptyMessage }), children] })] })), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] }));
45
- };
46
- if (!control) {
47
- // `value` undefined leaves Radix to keep its own state, so an uncontrolled
48
- // standalone select still opens and picks; `onChange` reports either way.
49
- // The caller's own `onChange` is invoked by the body, so this is a no-op.
50
- return renderItem({
51
- name,
52
- value,
53
- onChange: () => { },
54
- onBlur: () => { },
55
- ref: () => { },
56
- disabled
57
- });
58
- }
59
- return (_jsx(FormField, { name: name, control: control, ...others,
60
- // An unset field falls back to the EMPTY value of its own shape: `''`
61
- // for the single select, `[]` for the multi one. Falling back to `''`
62
- // for both handed MultipleSelect a string it silently discarded.
63
- render: ({ field }) => renderItem({ ...field, value: field.value ?? (multi ? [] : '') }) }));
64
- };
1
+ import{jsxs as r,jsx as e}from"react/jsx-runtime";import{FormControl as T,FormDescription as w,FormField as L,FormItem as _,FormLabel as q,FormMessage as v,FormTooltip as B}from"../../../components/ui/form.js";import{MultipleSelect as D,MultipleSelectContent as E,MultipleSelectTrigger as I,MultipleSelectValue as b}from"../../../components/ui/multiple-select/index.js";import{Select as k,SelectContent as y,SelectEmpty as z,SelectTrigger as A,SelectValue as G}from"../../../components/ui/select/index.js";import{cn as H}from"../../../lib/utils.js";export const SelectField=({name:i,label:a,tooltip:m,labelExtra:F,required:f,placeholder:s,description:h,disabled:o,readOnly:l,multi:d,control:p,value:x,children:u,emptyMessage:M="No options found.",leadingIcon:c,className:j,onChange:N,...g})=>{const C=N;const V=n=>c?r("span",{className:"flex min-w-0 items-center",children:[c,n]}):n;const S=n=>{return r(_,{required:f,className:j,children:[a&&e(q,{extra:m?e(B,{children:m}):F,children:a}),d?r(D,{onValueChange:t=>{n.onChange(t);C?.(t)},disabled:o,...n,children:[r(I,{readOnly:l,children:[c,e(b,{placeholder:s})]}),e(E,{children:u})]}):r(k,{onValueChange:t=>{n.onChange(t);C?.(t)},value:n.value,disabled:o,open:l?false:void 0,onOpenChange:l?()=>{}:void 0,children:[e(T,{children:e(A,{className:H(o&&"bg-shadcn-100"),readOnly:l,"data-testid":g["data-testid"],children:V(e(G,{placeholder:s}))})}),r(y,{children:[e(z,{children:M}),u]})]}),e(v,{}),h&&e(w,{children:h})]})};if(!p){return S({name:i,value:x,onChange:()=>{},onBlur:()=>{},ref:()=>{},disabled:o})}return e(L,{name:i,control:p,...g,render:({field:n})=>S({...n,value:n.value??(d?[]:"")})})};
@@ -1,35 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from 'react';
3
- import { getStateCountry } from '../../../utils/country-utils.js';
4
- import { useFormContext } from 'react-hook-form';
5
- import { FormField, FormItem, FormLabel, FormMessage } from '../../../components/ui/form.js';
6
- import { Button } from '../../../components/ui/button/index.js';
7
- import { cn } from '../../../lib/utils.js';
8
- import { Popover, PopoverTrigger, PopoverContent } from '../../../components/ui/popover/index.js';
9
- import { ChevronsUpDown } from 'lucide-react';
10
- import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '../../../components/ui/command/index.js';
11
- function StateComboBox({ value, placeholder, onChange, countryName, emptyMessage, readOnly }) {
12
- const [open, setOpen] = React.useState(false);
13
- const form = useFormContext();
14
- const country = form.watch(countryName);
15
- const options = React.useMemo(() => {
16
- const states = getStateCountry(country)?.map((state) => ({
17
- value: state.code,
18
- label: state.name
19
- }));
20
- if (!states) {
21
- onChange?.('');
22
- }
23
- return states ?? [];
24
- }, [country, onChange]);
25
- const getDisplayValue = React.useCallback((value) => {
26
- return options.find((option) => option.value === value)?.label ?? null;
27
- }, [options]);
28
- return (_jsxs(Popover, { open: readOnly ? false : open, onOpenChange: readOnly ? () => { } : setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", role: "combobox", "aria-expanded": readOnly ? false : open, readOnly: readOnly, tabIndex: 0, className: cn('border-input-border bg-input hover:bg-input text-foreground h-10 w-full justify-between rounded-md border px-4 py-2 pl-6 text-left text-base font-normal focus:ring-2 focus:ring-offset-0 focus:outline-none', !value && 'text-muted-foreground'), children: [getDisplayValue(value) ?? placeholder, !readOnly && (_jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" }))] }) }), _jsx(PopoverContent, { className: "w-(--radix-popover-trigger-width) p-0", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: placeholder }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: emptyMessage }), _jsx(CommandGroup, { children: options.map((option) => (_jsx(CommandItem, { value: option.value, keywords: [option.label], onSelect: (currentValue) => {
29
- onChange?.(value !== currentValue ? currentValue : '');
30
- setOpen(false);
31
- }, children: option.label }, option.value))) })] })] }) })] }));
32
- }
33
- export const StateField = ({ countryName = 'address.country', label, placeholder, emptyMessage, required, readOnly, ...others }) => {
34
- return (_jsx(FormField, { ...others, name: others.name, render: ({ field }) => (_jsxs(FormItem, { required: required, children: [label && _jsx(FormLabel, { children: label }), _jsx(StateComboBox, { countryName: countryName, placeholder: placeholder, emptyMessage: emptyMessage, readOnly: readOnly, ...field }), _jsx(FormMessage, {})] })) }));
35
- };
1
+ import{jsx as e,jsxs as l}from"react/jsx-runtime";import u from"react";import{getStateCountry as x}from"../../../utils/country-utils.js";import{useFormContext as g}from"react-hook-form";import{FormField as C,FormItem as v,FormLabel as y,FormMessage as w}from"../../../components/ui/form.js";import{Button as F}from"../../../components/ui/button/index.js";import{cn as j}from"../../../lib/utils.js";import{Popover as S,PopoverTrigger as I,PopoverContent as N}from"../../../components/ui/popover/index.js";import{ChevronsUpDown as k}from"lucide-react";import{Command as M,CommandEmpty as P,CommandGroup as B,CommandInput as D,CommandItem as L,CommandList as _}from"../../../components/ui/command/index.js";function q({value:n,placeholder:m,onChange:a,countryName:d,emptyMessage:c,readOnly:r}){const[s,i]=u.useState(false);const h=g();const f=h.watch(d);const p=u.useMemo(()=>{const o=x(f)?.map(t=>({value:t.code,label:t.name}));if(!o){a?.("")}return o??[]},[f,a]);const b=u.useCallback(o=>{return p.find(t=>t.value===o)?.label??null},[p]);return l(S,{open:r?false:s,onOpenChange:r?()=>{}:i,children:[e(I,{asChild:true,children:l(F,{variant:"outline",role:"combobox","aria-expanded":r?false:s,readOnly:r,tabIndex:0,className:j("border-input-border bg-input hover:bg-input text-foreground h-10 w-full justify-between rounded-md border px-4 py-2 pl-6 text-left text-base font-normal focus:ring-2 focus:ring-offset-0 focus:outline-none",!n&&"text-muted-foreground"),children:[b(n)??m,!r&&e(k,{className:"ml-2 h-4 w-4 shrink-0 opacity-50"})]})}),e(N,{className:"w-(--radix-popover-trigger-width) p-0",children:l(M,{children:[e(D,{placeholder:m}),l(_,{children:[e(P,{children:c}),e(B,{children:p.map(o=>e(L,{value:o.value,keywords:[o.label],onSelect:t=>{a?.(n!==t?t:"");i(false)},children:o.label},o.value))})]})]})})]})}export const StateField=({countryName:n="address.country",label:m,placeholder:a,emptyMessage:d,required:c,readOnly:r,...s})=>{return e(C,{...s,name:s.name,render:({field:i})=>l(v,{required:c,children:[m&&e(y,{children:m}),e(q,{countryName:n,placeholder:a,emptyMessage:d,readOnly:r,...i}),e(w,{})]})})};
@@ -1,12 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { FormControl, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
3
- import { Switch } from '../../../components/ui/switch/index.js';
4
- import { Tooltip, TooltipContent, TooltipTrigger } from '../../../components/ui/tooltip/index.js';
5
- export const SwitchField = ({ label, name, control, labelExtra, tooltip, required, disabled, disabledTooltip, 'data-testid': dataTestId }) => {
6
- return (_jsx(FormField, { name: name, control: control, render: ({ field }) => {
7
- // FormControl stamps the id the label points at on its direct child,
8
- // so it must wrap the Switch itself, never the tooltip around it.
9
- const control = (_jsx(FormControl, { children: _jsx(Switch, { checked: field.value, onCheckedChange: field.onChange, disabled: disabled, "data-testid": dataTestId }) }));
10
- return (_jsxs(FormItem, { required: required, children: [label && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : labelExtra, children: label })), _jsx("div", { className: "relative", children: disabled && disabledTooltip ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: "inline-flex w-auto", children: control }) }), _jsx(TooltipContent, { children: disabledTooltip })] })) : (control) }), _jsx(FormMessage, {})] }));
11
- } }));
12
- };
1
+ import{jsx as r,jsxs as l}from"react/jsx-runtime";import{FormControl as F,FormField as p,FormItem as x,FormLabel as u,FormMessage as C,FormTooltip as g}from"../../../components/ui/form.js";import{Switch as f}from"../../../components/ui/switch/index.js";import{Tooltip as j,TooltipContent as v,TooltipTrigger as T}from"../../../components/ui/tooltip/index.js";export const SwitchField=({label:e,name:d,control:a,labelExtra:m,tooltip:o,required:s,disabled:t,disabledTooltip:i,"data-testid":h})=>{return r(p,{name:d,control:a,render:({field:n})=>{const c=r(F,{children:r(f,{checked:n.value,onCheckedChange:n.onChange,disabled:t,"data-testid":h})});return l(x,{required:s,children:[e&&r(u,{extra:o?r(g,{children:o}):m,children:e}),r("div",{className:"relative",children:t&&i?l(j,{children:[r(T,{asChild:true,children:r("div",{className:"inline-flex w-auto",children:c})}),r(v,{children:i})]}):c}),r(C,{})]})}})};
@@ -1,19 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FormTooltip } from '../../../components/ui/form.js';
3
- import { Textarea } from '../../../components/ui/textarea/index.js';
4
- import { hasRenderableLabel } from '../../../components/form/renderable-label.js';
5
- export const TextareaField = ({ control, name, label, description, placeholder, tooltip, required, disabled, readOnly, rows, className, 'data-testid': dataTestId, 'aria-label': ariaLabelProp }) => {
6
- const showLabel = hasRenderableLabel(label);
7
- // An empty or whitespace-only aria-label is worse than none: it names the
8
- // control "". Drop it so the attribute never reaches the DOM.
9
- const ariaLabel = ariaLabelProp?.trim() ? ariaLabelProp : undefined;
10
- // The type cannot rule out `label=""`, so this is the only signal a developer
11
- // gets that the control shipped nameless.
12
- if (process.env.NODE_ENV !== 'production' && !showLabel && !ariaLabel) {
13
- console.error(`TextareaField "${name}" has no accessible name: pass a non-empty label or aria-label.`);
14
- }
15
- return (_jsx(FormField, { control: control, name: name,
16
- // Controller-level, not just on the element: this is what keeps a
17
- // disabled field out of the submitted values.
18
- disabled: disabled, render: ({ field }) => (_jsxs(FormItem, { required: required, children: [showLabel && (_jsx(FormLabel, { extra: tooltip ? _jsx(FormTooltip, { children: tooltip }) : undefined, children: label })), _jsx(FormControl, { children: _jsx(Textarea, { placeholder: placeholder, readOnly: readOnly, rows: rows, className: className, "data-testid": dataTestId, "aria-label": ariaLabel, ...field }) }), _jsx(FormMessage, {}), description && _jsx(FormDescription, { children: description })] })) }));
19
- };
1
+ import{jsx as e,jsxs as f}from"react/jsx-runtime";import{FormControl as u,FormDescription as j,FormField as T,FormItem as L,FormLabel as N,FormMessage as _,FormTooltip as w}from"../../../components/ui/form.js";import{Textarea as y}from"../../../components/ui/textarea/index.js";import{hasRenderableLabel as D}from"../../../components/form/renderable-label.js";export const TextareaField=({control:t,name:r,label:a,description:o,placeholder:d,tooltip:s,required:m,disabled:c,readOnly:F,rows:b,className:h,"data-testid":p,"aria-label":l})=>{const i=D(a);const n=l?.trim()?l:void 0;if(process.env.NODE_ENV!=="production"&&!i&&!n){console.error(`TextareaField "${r}" has no accessible name: pass a non-empty label or aria-label.`)}return e(T,{control:t,name:r,disabled:c,render:({field:x})=>f(L,{required:m,children:[i&&e(N,{extra:s?e(w,{children:s}):void 0,children:a}),e(u,{children:e(y,{placeholder:d,readOnly:F,rows:b,className:h,"data-testid":p,"aria-label":n,...x})}),e(_,{}),o&&e(j,{children:o})]})})};
@@ -1,15 +1 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { cn } from '../../lib/utils.js';
3
- export function PageRoot({ className, ...props }) {
4
- return (_jsx("div", { "data-slot": "page-root", className: cn('text-foreground bg-body-surface flex h-screen min-h-screen w-full flex-col overflow-y-auto', className), ...props }));
5
- }
6
- export function PageView({ className, ...props }) {
7
- return (_jsx("div", { "data-slot": "page-view", className: cn('flex min-h-0 flex-1', className), ...props }));
8
- }
9
- export function PageContent({ className, padding = 'default', ...props }) {
10
- return (_jsx("div", { "data-slot": "page-content",
11
- // Order is the contract, not a style: `className` last is what lets a
12
- // caller's `p-0` beat `p-16` and a caller's `max-sm:p-0` replace the
13
- // compact rule instead of stacking with it.
14
- className: cn('flex grow flex-col overflow-y-auto p-16', padding === 'compact' && 'max-sm:p-4', className), ...props }));
15
- }
1
+ import{jsx as t}from"react/jsx-runtime";import{cn as a}from"../../lib/utils.js";export function PageRoot({className:e,...o}){return t("div",{"data-slot":"page-root",className:a("text-foreground bg-body-surface flex h-screen min-h-screen w-full flex-col overflow-y-auto",e),...o})}export function PageView({className:e,...o}){return t("div",{"data-slot":"page-view",className:a("flex min-h-0 flex-1",e),...o})}export function PageContent({className:e,padding:o="default",...r}){return t("div",{"data-slot":"page-content",className:a("flex grow flex-col overflow-y-auto p-16",o==="compact"&&"max-sm:p-4",e),...r})}