@bsol-oss/react-datatable5 12.0.0-beta.8 → 12.0.0-beta.80

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 (127) hide show
  1. package/README.md +224 -5
  2. package/dist/index.d.ts +606 -96
  3. package/dist/index.js +2679 -610
  4. package/dist/index.mjs +2683 -619
  5. package/dist/types/components/DataTable/DataTable.d.ts +12 -7
  6. package/dist/types/components/DataTable/DataTableServer.d.ts +6 -4
  7. package/dist/types/components/DataTable/DefaultTable.d.ts +12 -14
  8. package/dist/types/components/DataTable/DefaultTableServer.d.ts +23 -0
  9. package/dist/types/components/DataTable/context/DataTableContext.d.ts +21 -3
  10. package/dist/types/components/DataTable/context/useDataTableContext.d.ts +2 -2
  11. package/dist/types/components/DataTable/controls/ReloadButton.d.ts +1 -2
  12. package/dist/types/components/DataTable/controls/ResetFilteringButton.d.ts +1 -4
  13. package/dist/types/components/DataTable/controls/ResetSelectionButton.d.ts +1 -4
  14. package/dist/types/components/DataTable/controls/ResetSortingButton.d.ts +1 -4
  15. package/dist/types/components/DataTable/controls/TableControls.d.ts +10 -2
  16. package/dist/types/components/DataTable/display/Table.d.ts +3 -3
  17. package/dist/types/components/DataTable/display/TableBody.d.ts +1 -2
  18. package/dist/types/components/DataTable/display/TableBodySkeleton.d.ts +5 -0
  19. package/dist/types/components/DataTable/display/TableCardContainer.d.ts +6 -3
  20. package/dist/types/components/DataTable/display/TableDataDisplay.d.ts +6 -1
  21. package/dist/types/components/DataTable/display/TableFooter.d.ts +1 -5
  22. package/dist/types/components/DataTable/display/TableHeader.d.ts +46 -8
  23. package/dist/types/components/DataTable/useDataTableServer.d.ts +55 -3
  24. package/dist/types/components/DatePicker/DatePicker.d.ts +23 -0
  25. package/dist/types/components/DatePicker/DateTimePicker.d.ts +11 -0
  26. package/dist/types/components/DatePicker/DurationPicker.d.ts +12 -0
  27. package/dist/types/components/DatePicker/IsoTimePicker.d.ts +16 -0
  28. package/dist/types/components/DatePicker/PickerDemo.d.ts +1 -0
  29. package/dist/types/components/DatePicker/UniversalPicker.d.ts +9 -0
  30. package/dist/types/components/DatePicker/index.d.ts +7 -0
  31. package/dist/types/components/Filter/TagFilter.d.ts +5 -1
  32. package/dist/types/components/Form/SchemaFormContext.d.ts +22 -6
  33. package/dist/types/components/Form/components/FileDropzone.d.ts +2 -2
  34. package/dist/types/components/Form/components/core/DefaultForm.d.ts +1 -0
  35. package/dist/types/components/Form/components/core/FormBody.d.ts +2 -1
  36. package/dist/types/components/Form/components/core/FormRoot.d.ts +21 -8
  37. package/dist/types/components/Form/components/fields/BooleanPicker.d.ts +1 -1
  38. package/dist/types/components/Form/components/fields/ColumnRenderer.d.ts +3 -2
  39. package/dist/types/components/Form/components/fields/CustomInput.d.ts +8 -0
  40. package/dist/types/components/Form/components/fields/DatePicker.d.ts +2 -7
  41. package/dist/types/components/Form/components/fields/DateRangePicker.d.ts +2 -0
  42. package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +2 -0
  43. package/dist/types/components/Form/components/fields/EnumPicker.d.ts +3 -2
  44. package/dist/types/components/Form/components/fields/FilePicker.d.ts +2 -5
  45. package/dist/types/components/Form/components/fields/IdPicker.d.ts +1 -1
  46. package/dist/types/components/Form/components/fields/NumberInputField.d.ts +1 -1
  47. package/dist/types/components/Form/components/fields/ObjectInput.d.ts +1 -1
  48. package/dist/types/components/Form/components/fields/RecordInput.d.ts +1 -1
  49. package/dist/types/components/Form/components/fields/SchemaRenderer.d.ts +1 -1
  50. package/dist/types/components/Form/components/fields/StringInputField.d.ts +19 -5
  51. package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +12 -0
  52. package/dist/types/components/Form/components/{DatePicker.d.ts → fields/TimePicker.d.ts} +2 -2
  53. package/dist/types/components/Form/components/fields/types.d.ts +6 -0
  54. package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +77 -4
  55. package/dist/types/components/Form/components/viewers/CustomViewer.d.ts +8 -0
  56. package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +7 -0
  57. package/dist/types/components/Form/components/viewers/NumberViewer.d.ts +1 -1
  58. package/dist/types/components/Form/components/viewers/TextAreaViewer.d.ts +12 -0
  59. package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +7 -0
  60. package/dist/types/components/Form/useForm.d.ts +6 -3
  61. package/dist/types/components/Form/utils/ajvResolver.d.ts +13 -0
  62. package/dist/types/components/Form/utils/buildErrorMessages.d.ts +223 -0
  63. package/dist/types/components/Form/utils/formatBytes.d.ts +6 -0
  64. package/dist/types/components/Form/utils/getFieldError.d.ts +6 -0
  65. package/dist/types/components/Form/utils/useFormI18n.d.ts +53 -0
  66. package/dist/types/components/Form/utils/validateData.d.ts +9 -0
  67. package/dist/types/components/TextArea/TextArea.d.ts +22 -0
  68. package/dist/types/components/TimePicker/TimePicker.d.ts +21 -0
  69. package/dist/types/components/ui/field.d.ts +3 -3
  70. package/dist/types/index.d.ts +19 -2
  71. package/package.json +18 -3
  72. package/dist/types/components/Controls/DensityFeature.d.ts +0 -23
  73. package/dist/types/components/Controls/DensityToggleButton.d.ts +0 -6
  74. package/dist/types/components/Controls/EditFilterButton.d.ts +0 -9
  75. package/dist/types/components/Controls/EditOrderButton.d.ts +0 -7
  76. package/dist/types/components/Controls/EditSortingButton.d.ts +0 -7
  77. package/dist/types/components/Controls/EditViewButton.d.ts +0 -7
  78. package/dist/types/components/Controls/FilterDialog.d.ts +0 -5
  79. package/dist/types/components/Controls/PageSizeControl.d.ts +0 -4
  80. package/dist/types/components/Controls/Pagination.d.ts +0 -1
  81. package/dist/types/components/Controls/ResetFilteringButton.d.ts +0 -4
  82. package/dist/types/components/Controls/ResetSelectionButton.d.ts +0 -4
  83. package/dist/types/components/Controls/ResetSortingButton.d.ts +0 -4
  84. package/dist/types/components/Controls/RowCountText.d.ts +0 -1
  85. package/dist/types/components/Controls/SelectAllRowsToggle.d.ts +0 -8
  86. package/dist/types/components/Controls/TablePagination.d.ts +0 -1
  87. package/dist/types/components/Controls/ViewDialog.d.ts +0 -5
  88. package/dist/types/components/DataTable/CardHeader.d.ts +0 -13
  89. package/dist/types/components/DataTable/DataDisplay.d.ts +0 -6
  90. package/dist/types/components/DataTable/ReloadButton.d.ts +0 -5
  91. package/dist/types/components/DataTable/Table.d.ts +0 -10
  92. package/dist/types/components/DataTable/TableBody.d.ts +0 -21
  93. package/dist/types/components/DataTable/TableCardContainer.d.ts +0 -7
  94. package/dist/types/components/DataTable/TableCards.d.ts +0 -11
  95. package/dist/types/components/DataTable/TableComponent.d.ts +0 -6
  96. package/dist/types/components/DataTable/TableControls.d.ts +0 -21
  97. package/dist/types/components/DataTable/TableFilter.d.ts +0 -1
  98. package/dist/types/components/DataTable/TableFilterTags.d.ts +0 -1
  99. package/dist/types/components/DataTable/TableFilters.d.ts +0 -1
  100. package/dist/types/components/DataTable/TableFooter.d.ts +0 -9
  101. package/dist/types/components/DataTable/TableHeader.d.ts +0 -13
  102. package/dist/types/components/DataTable/TableLoadingComponent.d.ts +0 -5
  103. package/dist/types/components/DataTable/TableOrderer.d.ts +0 -1
  104. package/dist/types/components/DataTable/TableSelector.d.ts +0 -1
  105. package/dist/types/components/DataTable/TableSorter.d.ts +0 -1
  106. package/dist/types/components/DataTable/TableViewer.d.ts +0 -1
  107. package/dist/types/components/DataTable/TextCell.d.ts +0 -10
  108. package/dist/types/components/DataTable/components/EmptyState.d.ts +0 -5
  109. package/dist/types/components/DataTable/components/ErrorAlert.d.ts +0 -4
  110. package/dist/types/components/DataTable/components/RecordDisplay.d.ts +0 -9
  111. package/dist/types/components/DataTable/components/TextCell.d.ts +0 -10
  112. package/dist/types/components/Filter/DateRangeFilter.d.ts +0 -9
  113. package/dist/types/components/Filter/FilterOptions.d.ts +0 -4
  114. package/dist/types/components/Form/Form.d.ts +0 -36
  115. package/dist/types/components/Form/components/ArrayRenderer.d.ts +0 -7
  116. package/dist/types/components/Form/components/BooleanPicker.d.ts +0 -7
  117. package/dist/types/components/Form/components/ColumnRenderer.d.ts +0 -7
  118. package/dist/types/components/Form/components/EnumPicker.d.ts +0 -8
  119. package/dist/types/components/Form/components/FilePicker.d.ts +0 -5
  120. package/dist/types/components/Form/components/IdPicker.d.ts +0 -8
  121. package/dist/types/components/Form/components/IdViewer.d.ts +0 -5
  122. package/dist/types/components/Form/components/NumberInputField.d.ts +0 -7
  123. package/dist/types/components/Form/components/ObjectInput.d.ts +0 -7
  124. package/dist/types/components/Form/components/RecordInput.d.ts +0 -7
  125. package/dist/types/components/Form/components/SchemaRenderer.d.ts +0 -7
  126. package/dist/types/components/Form/components/StringInputField.d.ts +0 -20
  127. package/dist/types/components/Form/components/TagPicker.d.ts +0 -30
package/dist/index.js CHANGED
@@ -29,7 +29,11 @@ var gr = require('react-icons/gr');
29
29
  var reactI18next = require('react-i18next');
30
30
  var axios = require('axios');
31
31
  var reactHookForm = require('react-hook-form');
32
+ var Ajv = require('ajv');
33
+ var addFormats = require('ajv-formats');
32
34
  var dayjs = require('dayjs');
35
+ var utc = require('dayjs/plugin/utc');
36
+ var timezone = require('dayjs/plugin/timezone');
33
37
  var ti = require('react-icons/ti');
34
38
 
35
39
  function _interopNamespaceDefault(e) {
@@ -57,6 +61,56 @@ const DataTableContext = React.createContext({
57
61
  setGlobalFilter: () => { },
58
62
  type: "client",
59
63
  translate: {},
64
+ data: [],
65
+ columns: [],
66
+ columnOrder: [],
67
+ columnFilters: [],
68
+ density: "sm",
69
+ sorting: [],
70
+ setPagination: function () {
71
+ throw new Error("Function not implemented.");
72
+ },
73
+ setSorting: function () {
74
+ throw new Error("Function not implemented.");
75
+ },
76
+ setColumnFilters: function () {
77
+ throw new Error("Function not implemented.");
78
+ },
79
+ setRowSelection: function () {
80
+ throw new Error("Function not implemented.");
81
+ },
82
+ setColumnOrder: function () {
83
+ throw new Error("Function not implemented.");
84
+ },
85
+ setDensity: function () {
86
+ throw new Error("Function not implemented.");
87
+ },
88
+ setColumnVisibility: function () {
89
+ throw new Error("Function not implemented.");
90
+ },
91
+ pagination: {
92
+ pageIndex: 0,
93
+ pageSize: 10,
94
+ },
95
+ rowSelection: {},
96
+ columnVisibility: {},
97
+ tableLabel: {
98
+ view: "View",
99
+ edit: "Edit",
100
+ filterButtonText: "Filter",
101
+ filterTitle: "Filter",
102
+ filterReset: "Reset",
103
+ filterClose: "Close",
104
+ reloadTooltip: "Reload",
105
+ reloadButtonText: "Reload",
106
+ resetSelection: "Reset Selection",
107
+ resetSorting: "Reset Sorting",
108
+ rowCountText: "Row Count",
109
+ hasErrorText: "Has Error",
110
+ globalFilterPlaceholder: "Search",
111
+ trueLabel: "True",
112
+ falseLabel: "False",
113
+ },
60
114
  });
61
115
 
62
116
  const useDataTableContext = () => {
@@ -112,11 +166,13 @@ const TableSorter = () => {
112
166
  }) }))) }));
113
167
  };
114
168
 
115
- const ResetSortingButton = ({ text = "Reset Sorting", }) => {
169
+ const ResetSortingButton = () => {
116
170
  const { table } = useDataTableContext();
171
+ const { tableLabel } = useDataTableContext();
172
+ const { resetSorting } = tableLabel;
117
173
  return (jsxRuntime.jsx(react.Button, { onClick: () => {
118
174
  table.resetSorting();
119
- }, children: text }));
175
+ }, children: resetSorting }));
120
176
  };
121
177
 
122
178
  const EditSortingButton = ({ text, icon = jsxRuntime.jsx(md.MdOutlineSort, {}), title = "Edit Sorting", }) => {
@@ -144,7 +200,7 @@ const monthNamesFull = [
144
200
  "November",
145
201
  "December",
146
202
  ];
147
- const weekdayNamesShort$1 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
203
+ const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
148
204
  function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, selected = [], firstDayOfWeek = 0, }) {
149
205
  const [hoveredDate, setHoveredDate] = React.useState();
150
206
  const onMouseLeave = () => {
@@ -179,7 +235,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
179
235
  offset: 12,
180
236
  }), children: ">>" })] }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", gap: 4, children: calendars.map((calendar) => (jsxRuntime.jsxs(react.Grid, { gap: 4, children: [jsxRuntime.jsxs(react.Grid, { justifyContent: "center", children: [monthNamesFull[calendar.month], " ", calendar.year] }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
181
237
  const weekday = (weekdayNum + firstDayOfWeek) % 7;
182
- return (jsxRuntime.jsx(react.Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort$1[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
238
+ return (jsxRuntime.jsx(react.Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
183
239
  }) }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: calendar.weeks.map((week, windex) => week.map((dateObj, index) => {
184
240
  const key = `${calendar.month}${calendar.year}${windex}${index}`;
185
241
  if (!dateObj) {
@@ -300,8 +356,17 @@ const Tag = React__namespace.forwardRef(function Tag(props, ref) {
300
356
  return (jsxRuntime.jsxs(react.Tag.Root, { ref: ref, ...rest, children: [startElement && (jsxRuntime.jsx(react.Tag.StartElement, { children: startElement })), jsxRuntime.jsx(react.Tag.Label, { children: children }), endElement && (jsxRuntime.jsx(react.Tag.EndElement, { children: endElement })), closable && (jsxRuntime.jsx(react.Tag.EndElement, { children: jsxRuntime.jsx(react.Tag.CloseTrigger, { onClick: onClose }) }))] }));
301
357
  });
302
358
 
303
- const TagFilter = ({ availableTags, selectedTags, onTagChange, }) => {
359
+ const TagFilter = ({ availableTags, selectedTags, onTagChange, selectOne = false, }) => {
304
360
  const toggleTag = (tag) => {
361
+ if (selectOne) {
362
+ if (selectedTags.includes(tag)) {
363
+ onTagChange([]);
364
+ }
365
+ else {
366
+ onTagChange([tag]);
367
+ }
368
+ return;
369
+ }
305
370
  if (selectedTags.includes(tag)) {
306
371
  onTagChange(selectedTags.filter((t) => t !== tag));
307
372
  }
@@ -309,10 +374,14 @@ const TagFilter = ({ availableTags, selectedTags, onTagChange, }) => {
309
374
  onTagChange([...selectedTags, tag]);
310
375
  }
311
376
  };
312
- return (jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", p: "0.5rem", gap: "0.5rem", children: availableTags.map((tag) => (jsxRuntime.jsx(Tag, { variant: selectedTags.includes(tag) ? "solid" : "outline", cursor: "pointer", closable: selectedTags.includes(tag) ? true : undefined, onClick: () => toggleTag(tag), children: tag }))) }));
377
+ return (jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", p: "0.5rem", gap: "0.5rem", children: availableTags.map((tag) => {
378
+ const { label, value } = tag;
379
+ return (jsxRuntime.jsx(Tag, { variant: selectedTags.includes(value) ? "solid" : "outline", cursor: "pointer", closable: selectedTags.includes(value) ? true : undefined, onClick: () => toggleTag(value), children: label ?? value }));
380
+ }) }));
313
381
  };
314
382
 
315
383
  const Filter = ({ column }) => {
384
+ const { tableLabel } = useDataTableContext();
316
385
  const { filterVariant } = column.columnDef.meta ?? {};
317
386
  const displayName = column.columnDef.meta?.displayName ?? column.id;
318
387
  const filterOptions = column.columnDef.meta?.filterOptions ?? [];
@@ -327,10 +396,14 @@ const Filter = ({ column }) => {
327
396
  if (filterVariant === "select") {
328
397
  return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "0.25rem", children: [jsxRuntime.jsx(react.Text, { children: displayName }), jsxRuntime.jsx(RadioGroup, { value: column.getFilterValue() ? String(column.getFilterValue()) : "", onValueChange: (details) => {
329
398
  column.setFilterValue(details.value);
330
- }, children: jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: "0.5rem", children: filterOptions.map((item) => (jsxRuntime.jsx(Radio, { value: item, children: item }, item))) }) })] }, column.id));
399
+ }, children: jsxRuntime.jsxs(react.Flex, { flexFlow: "wrap", gap: "0.5rem", children: [filterOptions.length === 0 && jsxRuntime.jsx(react.Text, { children: "No filter options" }), filterOptions.length > 0 &&
400
+ filterOptions.map((item) => (jsxRuntime.jsx(Radio, { value: item.value, children: item.label }, item.value)))] }) })] }, column.id));
331
401
  }
332
402
  if (filterVariant === "tag") {
333
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "0.25rem", children: [jsxRuntime.jsx(react.Text, { children: displayName }), jsxRuntime.jsx(TagFilter, { availableTags: filterOptions, selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
403
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "0.25rem", children: [jsxRuntime.jsx(react.Text, { children: displayName }), jsxRuntime.jsx(TagFilter, { availableTags: filterOptions.map((item) => ({
404
+ label: item.label,
405
+ value: item.value,
406
+ })), selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
334
407
  if (tags.length === 0) {
335
408
  return column.setFilterValue(undefined);
336
409
  }
@@ -338,7 +411,11 @@ const Filter = ({ column }) => {
338
411
  } })] }, column.id));
339
412
  }
340
413
  if (filterVariant === "boolean") {
341
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "0.25rem", children: [jsxRuntime.jsx(react.Text, { children: displayName }), jsxRuntime.jsx(TagFilter, { availableTags: ["true", "false"], selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
414
+ const { trueLabel, falseLabel } = tableLabel;
415
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "0.25rem", children: [jsxRuntime.jsx(react.Text, { children: displayName }), jsxRuntime.jsx(TagFilter, { availableTags: [
416
+ { label: trueLabel, value: "true" },
417
+ { label: falseLabel, value: "false" },
418
+ ], selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
342
419
  if (tags.length === 0) {
343
420
  return column.setFilterValue(undefined);
344
421
  }
@@ -393,17 +470,20 @@ const TableFilter = () => {
393
470
  }) }));
394
471
  };
395
472
 
396
- const ResetFilteringButton = ({ text = "Reset Filtering", }) => {
473
+ const ResetFilteringButton = () => {
397
474
  const { table } = useDataTableContext();
475
+ const { tableLabel } = useDataTableContext();
476
+ const { filterReset } = tableLabel;
398
477
  return (jsxRuntime.jsx(react.Button, { onClick: () => {
399
478
  table.resetColumnFilters();
400
- }, children: text }));
479
+ }, children: filterReset }));
401
480
  };
402
481
 
403
482
  const FilterDialog = ({ icon = jsxRuntime.jsx(md.MdFilterAlt, {}), }) => {
404
483
  const filterModal = react.useDisclosure();
405
- const { translate } = useDataTableContext();
406
- return (jsxRuntime.jsxs(DialogRoot, { size: ["full", "full", "md", "md"], open: filterModal.open, children: [jsxRuntime.jsx(DialogTrigger, { asChild: true, children: jsxRuntime.jsxs(react.Button, { as: react.Box, variant: "ghost", onClick: filterModal.onOpen, children: [icon, " ", translate.t("filterDialog.buttonText")] }) }), jsxRuntime.jsxs(DialogContent, { children: [jsxRuntime.jsx(DialogHeader, { children: jsxRuntime.jsx(DialogTitle, { children: translate.t("filterDialog.title") }) }), jsxRuntime.jsx(DialogBody, { display: "flex", flexFlow: "column", children: jsxRuntime.jsx(TableFilter, {}) }), jsxRuntime.jsxs(DialogFooter, { children: [jsxRuntime.jsx(ResetFilteringButton, { text: translate.t("filterDialog.reset") }), jsxRuntime.jsx(react.Button, { onClick: filterModal.onClose, variant: "subtle", children: translate.t("filterDialog.close") })] }), jsxRuntime.jsx(DialogCloseTrigger, { onClick: filterModal.onClose })] })] }));
484
+ const { tableLabel } = useDataTableContext();
485
+ const { filterButtonText, filterTitle, filterClose } = tableLabel;
486
+ return (jsxRuntime.jsxs(DialogRoot, { size: ["full", "full", "md", "md"], open: filterModal.open, children: [jsxRuntime.jsx(DialogTrigger, { asChild: true, children: jsxRuntime.jsxs(react.Button, { as: react.Box, variant: "ghost", onClick: filterModal.onOpen, children: [icon, " ", filterButtonText] }) }), jsxRuntime.jsxs(DialogContent, { children: [jsxRuntime.jsx(DialogHeader, { children: jsxRuntime.jsx(DialogTitle, { children: filterTitle }) }), jsxRuntime.jsx(DialogBody, { display: "flex", flexFlow: "column", children: jsxRuntime.jsx(TableFilter, {}) }), jsxRuntime.jsxs(DialogFooter, { children: [jsxRuntime.jsx(ResetFilteringButton, {}), jsxRuntime.jsx(react.Button, { onClick: filterModal.onClose, variant: "subtle", children: filterClose })] }), jsxRuntime.jsx(DialogCloseTrigger, { onClick: filterModal.onClose })] })] }));
407
487
  };
408
488
 
409
489
  const MenuContent = React__namespace.forwardRef(function MenuContent(props, ref) {
@@ -522,11 +602,13 @@ const Pagination = () => {
522
602
  }, children: jsxRuntime.jsxs(react.HStack, { children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), jsxRuntime.jsx(PaginationItems, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) }));
523
603
  };
524
604
 
525
- const ResetSelectionButton = ({ text = "Reset Selection", }) => {
605
+ const ResetSelectionButton = () => {
526
606
  const { table } = useDataTableContext();
607
+ const { tableLabel } = useDataTableContext();
608
+ const { resetSelection } = tableLabel;
527
609
  return (jsxRuntime.jsx(react.Button, { onClick: () => {
528
610
  table.resetRowSelection();
529
- }, children: text }));
611
+ }, children: resetSelection }));
530
612
  };
531
613
 
532
614
  const RowCountText = () => {
@@ -2441,8 +2523,8 @@ react.CheckboxCard.Indicator;
2441
2523
  function ColumnCard({ columnId }) {
2442
2524
  const ref = React.useRef(null);
2443
2525
  const [dragging, setDragging] = React.useState(false); // NEW
2444
- const { table } = useDataTableContext();
2445
- const displayName = columnId;
2526
+ const { table, translate } = useDataTableContext();
2527
+ const displayName = translate.t(columnId);
2446
2528
  const column = table.getColumn(columnId);
2447
2529
  invariant(column);
2448
2530
  React.useEffect(() => {
@@ -2457,7 +2539,7 @@ function ColumnCard({ columnId }) {
2457
2539
  onDrop: () => setDragging(false), // NEW
2458
2540
  });
2459
2541
  }, [columnId, table]);
2460
- return (jsxRuntime.jsxs(react.Grid, { ref: ref, templateColumns: "auto 1fr", gap: "0.5rem", alignItems: "center", style: dragging ? { opacity: 0.4 } : {}, children: [jsxRuntime.jsx(react.Flex, { alignItems: "center", padding: "0", cursor: "grab", children: jsxRuntime.jsx(fa6.FaGripLinesVertical, { color: "gray.400" }) }), jsxRuntime.jsx(react.Flex, { justifyContent: "space-between", alignItems: "center", children: jsxRuntime.jsx(CheckboxCard, { variant: "surface", label: displayName, checked: column.getIsVisible(), onChange: column.getToggleVisibilityHandler() }) })] }));
2542
+ return (jsxRuntime.jsxs(react.Grid, { ref: ref, templateColumns: "auto 1fr", gap: "0.5rem", alignItems: "center", style: dragging ? { opacity: 0.4 } : {}, children: [jsxRuntime.jsx(react.Flex, { alignItems: "center", padding: "0", cursor: "grab", children: jsxRuntime.jsx(fa6.FaGripLinesVertical, { color: "colorPalette.400" }) }), jsxRuntime.jsx(react.Flex, { justifyContent: "space-between", alignItems: "center", children: jsxRuntime.jsx(CheckboxCard, { variant: "surface", label: displayName, checked: column.getIsVisible(), onChange: column.getToggleVisibilityHandler() }) })] }));
2461
2543
  }
2462
2544
  function CardContainer({ location, children }) {
2463
2545
  const ref = React.useRef(null);
@@ -2476,7 +2558,6 @@ function CardContainer({ location, children }) {
2476
2558
  onDrop: () => setIsDraggedOver(false),
2477
2559
  });
2478
2560
  }, [location]);
2479
- // const isDark = (location + location) % 2 === 1;
2480
2561
  function getColor(isDraggedOver) {
2481
2562
  if (isDraggedOver) {
2482
2563
  return {
@@ -2486,7 +2567,6 @@ function CardContainer({ location, children }) {
2486
2567
  },
2487
2568
  };
2488
2569
  }
2489
- // return isDark ? "lightgrey" : "white";
2490
2570
  return {
2491
2571
  backgroundColor: undefined,
2492
2572
  _dark: {
@@ -2537,8 +2617,9 @@ const TableViewer = () => {
2537
2617
 
2538
2618
  const ViewDialog = ({ icon = jsxRuntime.jsx(io.IoMdEye, {}) }) => {
2539
2619
  const viewModel = react.useDisclosure();
2540
- const { translate } = useDataTableContext();
2541
- return (jsxRuntime.jsxs(DialogRoot, { children: [jsxRuntime.jsx(react.DialogBackdrop, {}), jsxRuntime.jsx(DialogTrigger, { asChild: true, children: jsxRuntime.jsxs(react.Button, { as: react.Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", translate.t("viewDialog.buttonText")] }) }), jsxRuntime.jsxs(DialogContent, { children: [jsxRuntime.jsx(DialogCloseTrigger, {}), jsxRuntime.jsx(DialogHeader, { children: jsxRuntime.jsx(DialogTitle, { children: translate.t("viewDialog.title") }) }), jsxRuntime.jsx(DialogBody, { children: jsxRuntime.jsx(TableViewer, {}) }), jsxRuntime.jsx(DialogFooter, {})] })] }));
2620
+ const { tableLabel } = useDataTableContext();
2621
+ const { view } = tableLabel;
2622
+ return (jsxRuntime.jsxs(DialogRoot, { children: [jsxRuntime.jsx(react.DialogBackdrop, {}), jsxRuntime.jsx(DialogTrigger, { asChild: true, children: jsxRuntime.jsxs(react.Button, { as: react.Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", view] }) }), jsxRuntime.jsxs(DialogContent, { children: [jsxRuntime.jsx(DialogCloseTrigger, {}), jsxRuntime.jsx(DialogHeader, { children: jsxRuntime.jsx(DialogTitle, { children: view }) }), jsxRuntime.jsx(DialogBody, { children: jsxRuntime.jsx(TableViewer, {}) }), jsxRuntime.jsx(DialogFooter, {})] })] }));
2542
2623
  };
2543
2624
 
2544
2625
  const CardHeader = ({ row, imageColumnId = undefined, titleColumnId = undefined, tagColumnId = undefined, tagIcon = undefined, showTag = true, imageProps = {}, }) => {
@@ -2589,7 +2670,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = "", }) => {
2589
2670
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "null" });
2590
2671
  }
2591
2672
  return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
2592
- return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsxRuntime.jsx(react.Text, { color: "gray.400", children: getColumn({ field }) }), typeof value === "object" ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, field));
2673
+ return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsxRuntime.jsx(react.Text, { color: "colorPalette.400", children: getColumn({ field }) }), typeof value === "object" ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, field));
2593
2674
  }) }));
2594
2675
  };
2595
2676
 
@@ -2639,7 +2720,7 @@ const CellRenderer = ({ cell }) => {
2639
2720
  paddingY: 2,
2640
2721
  }, object: value })] }, cell.id));
2641
2722
  }
2642
- return (jsxRuntime.jsxs(react.Box, { gridColumn, gridRow, children: [jsxRuntime.jsx(react.Box, { color: 'gray.400', children: getLabel({ columnId: cell.column.id }) }), jsxRuntime.jsx(react.Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
2723
+ return (jsxRuntime.jsxs(react.Box, { gridColumn, gridRow, children: [jsxRuntime.jsx(react.Box, { color: "colorPalette.400", children: getLabel({ columnId: cell.column.id }) }), jsxRuntime.jsx(react.Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
2643
2724
  };
2644
2725
  const DataDisplay = ({ variant = "" }) => {
2645
2726
  const { table, translate } = useDataTableContext();
@@ -2761,7 +2842,23 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
2761
2842
  *
2762
2843
  * @link https://tanstack.com/table/latest/docs/guide/column-defs
2763
2844
  */
2764
- function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, translate, children, }) {
2845
+ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, translate, children, tableLabel = {
2846
+ view: 'View',
2847
+ edit: 'Edit',
2848
+ filterButtonText: 'Filter',
2849
+ filterTitle: 'Filter',
2850
+ filterReset: 'Reset',
2851
+ filterClose: 'Close',
2852
+ reloadTooltip: 'Reload',
2853
+ reloadButtonText: 'Reload',
2854
+ resetSelection: 'Reset Selection',
2855
+ resetSorting: 'Reset Sorting',
2856
+ rowCountText: 'Row Count',
2857
+ hasErrorText: 'Has Error',
2858
+ globalFilterPlaceholder: 'Search',
2859
+ trueLabel: 'True',
2860
+ falseLabel: 'False',
2861
+ }, }) {
2765
2862
  const table = reactTable.useReactTable({
2766
2863
  _features: [DensityFeature],
2767
2864
  data: data,
@@ -2779,12 +2876,12 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2779
2876
  enableRowSelection: enableRowSelection,
2780
2877
  enableMultiRowSelection: enableMultiRowSelection,
2781
2878
  enableSubRowSelection: enableSubRowSelection,
2782
- columnResizeMode: "onChange",
2879
+ columnResizeMode: 'onChange',
2783
2880
  // global filter start
2784
2881
  filterFns: {
2785
2882
  fuzzy: fuzzyFilter,
2786
2883
  },
2787
- globalFilterFn: "fuzzy",
2884
+ globalFilterFn: 'fuzzy',
2788
2885
  state: {
2789
2886
  pagination,
2790
2887
  sorting,
@@ -2812,9 +2909,9 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2812
2909
  table: table,
2813
2910
  globalFilter,
2814
2911
  setGlobalFilter,
2815
- type: "client",
2912
+ type: 'client',
2816
2913
  translate,
2817
- columns,
2914
+ columns: columns,
2818
2915
  sorting,
2819
2916
  setSorting,
2820
2917
  columnFilters,
@@ -2829,6 +2926,8 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2829
2926
  setDensity,
2830
2927
  columnVisibility,
2831
2928
  setColumnVisibility,
2929
+ data,
2930
+ tableLabel,
2832
2931
  }, children: children }));
2833
2932
  }
2834
2933
 
@@ -2843,10 +2942,26 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2843
2942
  *
2844
2943
  * @link https://tanstack.com/table/latest/docs/guide/column-defs
2845
2944
  */
2846
- function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, translate, children, }) {
2945
+ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSelection = true, enableSubRowSelection = true, columnOrder, columnFilters, columnVisibility, density, globalFilter, pagination, sorting, rowSelection, setPagination, setSorting, setColumnFilters, setRowSelection, setGlobalFilter, setColumnOrder, setDensity, setColumnVisibility, query, url, translate, children, tableLabel = {
2946
+ view: "View",
2947
+ edit: "Edit",
2948
+ filterButtonText: "Filter",
2949
+ filterTitle: "Filter",
2950
+ filterReset: "Reset",
2951
+ filterClose: "Close",
2952
+ reloadTooltip: "Reload",
2953
+ reloadButtonText: "Reload",
2954
+ resetSelection: "Reset Selection",
2955
+ resetSorting: "Reset Sorting",
2956
+ rowCountText: "Row Count",
2957
+ hasErrorText: "Has Error",
2958
+ globalFilterPlaceholder: "Search",
2959
+ trueLabel: "True",
2960
+ falseLabel: "False",
2961
+ }, }) {
2847
2962
  const table = reactTable.useReactTable({
2848
2963
  _features: [DensityFeature],
2849
- data: query.data?.data ?? [],
2964
+ data: (query.data?.data ?? []),
2850
2965
  rowCount: query.data?.count ?? 0,
2851
2966
  columns: columns,
2852
2967
  getCoreRowModel: reactTable.getCoreRowModel(),
@@ -2892,12 +3007,12 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
2892
3007
  // for tanstack-table ts bug end
2893
3008
  });
2894
3009
  return (jsxRuntime.jsx(DataTableContext.Provider, { value: {
2895
- table: { ...table },
3010
+ table: table,
2896
3011
  globalFilter,
2897
3012
  setGlobalFilter,
2898
3013
  type: "server",
2899
3014
  translate,
2900
- columns,
3015
+ columns: columns,
2901
3016
  sorting,
2902
3017
  setSorting,
2903
3018
  columnFilters,
@@ -2912,15 +3027,108 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
2912
3027
  setDensity,
2913
3028
  columnVisibility,
2914
3029
  setColumnVisibility,
3030
+ data: query.data?.data ?? [],
3031
+ tableLabel,
2915
3032
  }, children: jsxRuntime.jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
2916
3033
  }
2917
3034
 
3035
+ const InputGroup = React__namespace.forwardRef(function InputGroup(props, ref) {
3036
+ const { startElement, startElementProps, endElement, endElementProps, children, startOffset = "6px", endOffset = "6px", ...rest } = props;
3037
+ return (jsxRuntime.jsxs(react.Group, { ref: ref, ...rest, children: [startElement && (jsxRuntime.jsx(react.InputElement, { pointerEvents: "none", ...startElementProps, children: startElement })), React__namespace.cloneElement(children, {
3038
+ ...(startElement && {
3039
+ ps: `calc(var(--input-height) - ${startOffset})`,
3040
+ }),
3041
+ ...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
3042
+ // @ts-expect-error chakra generated files
3043
+ ...children.props,
3044
+ }), endElement && (jsxRuntime.jsx(react.InputElement, { placement: "end", ...endElementProps, children: endElement }))] }));
3045
+ });
3046
+
3047
+ const GlobalFilter = () => {
3048
+ const { table, tableLabel } = useDataTableContext();
3049
+ const { globalFilterPlaceholder } = tableLabel;
3050
+ const [searchTerm, setSearchTerm] = React.useState("");
3051
+ const debouncedSearchTerm = usehooks.useDebounce(searchTerm, 500);
3052
+ React.useEffect(() => {
3053
+ const searchHN = async () => {
3054
+ table.setGlobalFilter(debouncedSearchTerm);
3055
+ };
3056
+ searchHN();
3057
+ }, [debouncedSearchTerm]);
3058
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(InputGroup, { flex: "1", startElement: jsxRuntime.jsx(md.MdSearch, {}), children: jsxRuntime.jsx(react.Input, { placeholder: globalFilterPlaceholder, variant: "outline", onChange: (e) => {
3059
+ setSearchTerm(e.target.value);
3060
+ } }) }) }));
3061
+ };
3062
+
3063
+ const Tooltip = React__namespace.forwardRef(function Tooltip(props, ref) {
3064
+ const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
3065
+ if (disabled)
3066
+ return children;
3067
+ return (jsxRuntime.jsxs(react.Tooltip.Root, { ...rest, children: [jsxRuntime.jsx(react.Tooltip.Trigger, { asChild: true, children: children }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, container: portalRef, children: jsxRuntime.jsx(react.Tooltip.Positioner, { children: jsxRuntime.jsxs(react.Tooltip.Content, { ref: ref, ...contentProps, children: [showArrow && (jsxRuntime.jsx(react.Tooltip.Arrow, { children: jsxRuntime.jsx(react.Tooltip.ArrowTip, {}) })), content] }) }) })] }));
3068
+ });
3069
+
3070
+ const ReloadButton = ({ variant = "icon", }) => {
3071
+ const { url } = useDataTableServerContext();
3072
+ const queryClient = reactQuery.useQueryClient();
3073
+ const { tableLabel } = useDataTableContext();
3074
+ const { reloadTooltip, reloadButtonText } = tableLabel;
3075
+ if (variant === "icon") {
3076
+ return (jsxRuntime.jsx(Tooltip, { showArrow: true, content: reloadTooltip, children: jsxRuntime.jsx(Button, { variant: "ghost", onClick: () => {
3077
+ queryClient.invalidateQueries({ queryKey: [url] });
3078
+ }, "aria-label": "refresh", children: jsxRuntime.jsx(io5.IoReload, {}) }) }));
3079
+ }
3080
+ return (jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3081
+ queryClient.invalidateQueries({ queryKey: [url] });
3082
+ }, children: [jsxRuntime.jsx(io5.IoReload, {}), " ", reloadButtonText] }));
3083
+ };
3084
+
3085
+ const TableFilterTags = () => {
3086
+ const { table } = useDataTableContext();
3087
+ return (jsxRuntime.jsx(react.Flex, { gap: "0.5rem", flexFlow: "wrap", children: table.getState().columnFilters.map(({ id, value }) => {
3088
+ return (jsxRuntime.jsx(Tag, { gap: "0.5rem", closable: true, cursor: "pointer", onClick: () => {
3089
+ table.setColumnFilters(table.getState().columnFilters.filter((filter) => {
3090
+ return filter.value != value;
3091
+ }));
3092
+ }, children: `${id}: ${value}` }, `${id}-${value}`));
3093
+ }) }));
3094
+ };
3095
+
3096
+ const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsxRuntime.jsx(jsxRuntime.Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsxRuntime.jsx(jsxRuntime.Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
3097
+ const { tableLabel, table } = useDataTableContext();
3098
+ const { rowCountText, hasErrorText } = tableLabel;
3099
+ return (jsxRuntime.jsxs(react.Grid, { templateRows: "auto 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", ...gridProps, children: [jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: 2, children: [jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", children: [jsxRuntime.jsx(react.Box, { children: showView && jsxRuntime.jsx(ViewDialog, { icon: jsxRuntime.jsx(md.MdOutlineViewColumn, {}) }) }), jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsxRuntime.jsx(react.Spinner, { size: "sm" }), hasError && (jsxRuntime.jsx(Tooltip, { content: hasErrorText, children: jsxRuntime.jsx(react.Icon, { as: bs.BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsxRuntime.jsx(GlobalFilter, {}), showFilter && jsxRuntime.jsx(FilterDialog, {}), showReload && jsxRuntime.jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: "0.5rem", children: filterTagsOptions.map((option) => {
3100
+ const { column, options } = option;
3101
+ const tableColumn = table.getColumn(column);
3102
+ return (jsxRuntime.jsxs(react.Flex, { alignItems: "center", flexFlow: "wrap", gap: "0.5rem", children: [tableColumn?.columnDef.meta?.displayName && (jsxRuntime.jsx(react.Text, { children: tableColumn?.columnDef.meta?.displayName })), jsxRuntime.jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
3103
+ if (tags.length === 0) {
3104
+ return tableColumn?.setFilterValue(undefined);
3105
+ }
3106
+ tableColumn?.setFilterValue(tags);
3107
+ } })] }, column));
3108
+ }) })), showFilterTags && (jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(TableFilterTags, {}) }))] }), jsxRuntime.jsx(react.Grid, { overflow: "auto", bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", children: [jsxRuntime.jsxs(react.Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsxRuntime.jsx(PageSizeControl, {}), showPageCountText && (jsxRuntime.jsxs(react.Flex, { children: [jsxRuntime.jsx(react.Text, { paddingRight: "0.5rem", children: rowCountText }), jsxRuntime.jsx(RowCountText, {})] }))] }), jsxRuntime.jsx(react.Box, { justifySelf: "end", children: showPagination && jsxRuntime.jsx(Pagination, {}) })] }))] }));
3109
+ };
3110
+
3111
+ const EmptyState = React__namespace.forwardRef(function EmptyState(props, ref) {
3112
+ const { title, description, icon, children, ...rest } = props;
3113
+ return (jsxRuntime.jsx(react.EmptyState.Root, { ref: ref, ...rest, children: jsxRuntime.jsxs(react.EmptyState.Content, { children: [icon && (jsxRuntime.jsx(react.EmptyState.Indicator, { children: icon })), description ? (jsxRuntime.jsxs(react.VStack, { textAlign: "center", children: [jsxRuntime.jsx(react.EmptyState.Title, { children: title }), jsxRuntime.jsx(react.EmptyState.Description, { children: description })] })) : (jsxRuntime.jsx(react.EmptyState.Title, { children: title })), children] }) }));
3114
+ });
3115
+
3116
+ const EmptyResult = (jsxRuntime.jsx(EmptyState, { icon: jsxRuntime.jsx(hi.HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxRuntime.jsxs(react.List.Root, { variant: "marker", children: [jsxRuntime.jsx(react.List.Item, { children: "Try removing filters" }), jsxRuntime.jsx(react.List.Item, { children: "Try different keywords" })] }) }));
3117
+ const Table = ({ children, emptyComponent = EmptyResult, canResize = true, showLoading = false, ...props }) => {
3118
+ const { table } = useDataTableContext();
3119
+ // Skip empty check when loading to allow skeleton to render
3120
+ if (!showLoading && table.getRowModel().rows.length <= 0) {
3121
+ return emptyComponent;
3122
+ }
3123
+ return (jsxRuntime.jsx(react.Table.Root, { stickyHeader: true, variant: 'outline', width: canResize ? table.getCenterTotalSize() : undefined, display: 'grid', alignContent: 'start', overflowY: 'auto', bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...props, children: children }));
3124
+ };
3125
+
2918
3126
  const Checkbox = React__namespace.forwardRef(function Checkbox(props, ref) {
2919
3127
  const { icon, children, inputProps, rootRef, ...rest } = props;
2920
3128
  return (jsxRuntime.jsxs(react.Checkbox.Root, { ref: rootRef, ...rest, children: [jsxRuntime.jsx(react.Checkbox.HiddenInput, { ref: ref, ...inputProps }), jsxRuntime.jsx(react.Checkbox.Control, { children: icon || jsxRuntime.jsx(react.Checkbox.Indicator, {}) }), children != null && (jsxRuntime.jsx(react.Checkbox.Label, { children: children }))] }));
2921
3129
  });
2922
3130
 
2923
- const TableBody = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, alwaysShowSelector = true, canResize = true, }) => {
3131
+ const TableBody = ({ showSelector = false, canResize = true, }) => {
2924
3132
  "use no memo";
2925
3133
  const { table } = useDataTableContext();
2926
3134
  const SELECTION_BOX_WIDTH = 20;
@@ -2934,12 +3142,7 @@ const TableBody = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, sho
2934
3142
  left: showSelector
2935
3143
  ? `${cell.column.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
2936
3144
  : `${cell.column.getStart("left")}px`,
2937
- background: pinnedBgColor.light,
2938
- position: "sticky",
2939
- zIndex: -1,
2940
- _dark: {
2941
- backgroundColor: pinnedBgColor.dark,
2942
- },
3145
+ position: "relative",
2943
3146
  }
2944
3147
  : {};
2945
3148
  return tdProps;
@@ -2958,133 +3161,91 @@ const TableBody = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, sho
2958
3161
  };
2959
3162
  };
2960
3163
  return (jsxRuntime.jsx(react.Table.Body, { children: table.getRowModel().rows.map((row, index) => {
2961
- return (jsxRuntime.jsxs(react.Table.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsxRuntime.jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow, alwaysShowSelector: alwaysShowSelector })), row.getVisibleCells().map((cell, index) => {
3164
+ return (jsxRuntime.jsxs(react.Table.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsxRuntime.jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow })), row.getVisibleCells().map((cell, index) => {
2962
3165
  return (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`,
2963
3166
  // styling resize and pinning start
2964
- flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`, backgroundColor: "white", ...getTdProps(cell), _dark: {
2965
- backgroundColor: "gray.950",
2966
- }, children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
3167
+ flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`,
3168
+ // this is to avoid the cell from being too wide
3169
+ minWidth: `0`, color: {
3170
+ base: "colorPalette.900",
3171
+ _dark: "colorPalette.100",
3172
+ },
3173
+ bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, ...getTdProps(cell), children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
2967
3174
  })] }, `chakra-table-row-${row.id}`));
2968
3175
  }) }));
2969
3176
  };
2970
- const TableRowSelector = ({ index, row, hoveredRow, pinnedBgColor = { light: "gray.50", dark: "gray.700" }, alwaysShowSelector = true, }) => {
3177
+ const TableRowSelector = ({ row, }) => {
2971
3178
  const { table } = useDataTableContext();
2972
3179
  const SELECTION_BOX_WIDTH = 20;
2973
- const isCheckBoxVisible = (current_index, current_row) => {
2974
- if (alwaysShowSelector) {
2975
- return true;
2976
- }
2977
- if (current_row.getIsSelected()) {
2978
- return true;
2979
- }
2980
- if (hoveredRow == current_index) {
2981
- return true;
2982
- }
2983
- return false;
2984
- };
2985
- return (jsxRuntime.jsxs(react.Table.Cell, { padding: `${table.getDensityValue()}px`, ...(table.getIsSomeColumnsPinned("left")
2986
- ? {
2987
- left: `0px`,
2988
- backgroundColor: pinnedBgColor.light,
2989
- position: "sticky",
2990
- zIndex: 1,
2991
- _dark: { backgroundColor: pinnedBgColor.dark },
2992
- }
2993
- : {}),
2994
- // styling resize and pinning end
2995
- display: "grid", children: [!isCheckBoxVisible(index, row) && (jsxRuntime.jsx(react.Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` })), isCheckBoxVisible(index, row) && (jsxRuntime.jsx(react.Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: row.getIsSelected(),
2996
- disabled: !row.getCanSelect(),
2997
- onChange: row.getToggleSelectedHandler() }) }))] }));
3180
+ return (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
3181
+ base: "colorPalette.900",
3182
+ _dark: "colorPalette.100",
3183
+ },
3184
+ bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: row.getIsSelected(),
3185
+ disabled: !row.getCanSelect(),
3186
+ onCheckedChange: row.getToggleSelectedHandler() }) }));
2998
3187
  };
2999
3188
 
3000
- const Tooltip = React__namespace.forwardRef(function Tooltip(props, ref) {
3001
- const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
3002
- if (disabled)
3003
- return children;
3004
- return (jsxRuntime.jsxs(react.Tooltip.Root, { ...rest, children: [jsxRuntime.jsx(react.Tooltip.Trigger, { asChild: true, children: children }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, container: portalRef, children: jsxRuntime.jsx(react.Tooltip.Positioner, { children: jsxRuntime.jsxs(react.Tooltip.Content, { ref: ref, ...contentProps, children: [showArrow && (jsxRuntime.jsx(react.Tooltip.Arrow, { children: jsxRuntime.jsx(react.Tooltip.ArrowTip, {}) })), content] }) }) })] }));
3005
- });
3006
-
3007
- const InputGroup = React__namespace.forwardRef(function InputGroup(props, ref) {
3008
- const { startElement, startElementProps, endElement, endElementProps, children, startOffset = "6px", endOffset = "6px", ...rest } = props;
3009
- return (jsxRuntime.jsxs(react.Group, { ref: ref, ...rest, children: [startElement && (jsxRuntime.jsx(react.InputElement, { pointerEvents: "none", ...startElementProps, children: startElement })), React__namespace.cloneElement(children, {
3010
- ...(startElement && {
3011
- ps: `calc(var(--input-height) - ${startOffset})`,
3012
- }),
3013
- ...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
3014
- // @ts-expect-error chakra generated files
3015
- ...children.props,
3016
- }), endElement && (jsxRuntime.jsx(react.InputElement, { placement: "end", ...endElementProps, children: endElement }))] }));
3017
- });
3018
-
3019
- const GlobalFilter = () => {
3189
+ const TableBodySkeleton = ({ showSelector = false, canResize = true, }) => {
3190
+ 'use no memo';
3020
3191
  const { table } = useDataTableContext();
3021
- const [searchTerm, setSearchTerm] = React.useState("");
3022
- const debouncedSearchTerm = usehooks.useDebounce(searchTerm, 500);
3023
- React.useEffect(() => {
3024
- const searchHN = async () => {
3025
- table.setGlobalFilter(debouncedSearchTerm);
3192
+ const SELECTION_BOX_WIDTH = 20;
3193
+ const [hoveredRow, setHoveredRow] = React.useState(-1);
3194
+ const handleRowHover = (index) => {
3195
+ setHoveredRow(index);
3196
+ };
3197
+ const getTdProps = (column) => {
3198
+ const tdProps = column.getIsPinned()
3199
+ ? {
3200
+ left: showSelector
3201
+ ? `${column.getStart('left') + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
3202
+ : `${column.getStart('left')}px`,
3203
+ position: 'relative',
3204
+ }
3205
+ : {};
3206
+ return tdProps;
3207
+ };
3208
+ const getTrProps = ({ hoveredRow, index, }) => {
3209
+ if (hoveredRow === -1) {
3210
+ return {};
3211
+ }
3212
+ if (hoveredRow === index) {
3213
+ return {
3214
+ opacity: '1',
3215
+ };
3216
+ }
3217
+ return {
3218
+ opacity: '0.8',
3026
3219
  };
3027
- searchHN();
3028
- }, [debouncedSearchTerm]);
3029
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(InputGroup, { flex: "1", startElement: jsxRuntime.jsx(md.MdSearch, {}), children: jsxRuntime.jsx(react.Input, { placeholder: "Outline", variant: "outline", onChange: (e) => {
3030
- setSearchTerm(e.target.value);
3031
- } }) }) }));
3032
- };
3033
-
3034
- const ReloadButton = ({ text = "Reload", variant = "icon", }) => {
3035
- const { url } = useDataTableServerContext();
3036
- const queryClient = reactQuery.useQueryClient();
3037
- if (variant === "icon") {
3038
- return (jsxRuntime.jsx(Tooltip, { showArrow: true, content: "This is the tooltip content", children: jsxRuntime.jsx(Button, { variant: "ghost", onClick: () => {
3039
- queryClient.invalidateQueries({ queryKey: [url] });
3040
- }, "aria-label": "refresh", children: jsxRuntime.jsx(io5.IoReload, {}) }) }));
3041
- }
3042
- return (jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3043
- queryClient.invalidateQueries({ queryKey: [url] });
3044
- }, children: [jsxRuntime.jsx(io5.IoReload, {}), " ", text] }));
3045
- };
3046
-
3047
- const FilterOptions = ({ column }) => {
3048
- const { table } = useDataTableContext();
3049
- const tableColumn = table.getColumn(column);
3050
- const options = tableColumn?.columnDef.meta?.filterOptions ?? [];
3051
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: options.map((option) => {
3052
- const selected = table.getColumn(column)?.getFilterValue() === option;
3053
- return (jsxRuntime.jsxs(react.Button, { size: "sm", onClick: () => {
3054
- if (selected) {
3055
- table.setColumnFilters((state) => {
3056
- return state.filter((filter) => {
3057
- return filter.id !== column;
3058
- });
3059
- });
3060
- return;
3061
- }
3062
- table.getColumn(column)?.setFilterValue(option);
3063
- }, variant: selected ? "solid" : "outline", display: "flex", gap: "0.25rem", children: [option, selected && jsxRuntime.jsx(md.MdClose, {})] }, option));
3220
+ };
3221
+ // Get the number of skeleton rows based on current pageSize
3222
+ const pageSize = table.getState().pagination.pageSize;
3223
+ const visibleColumns = table.getVisibleLeafColumns();
3224
+ return (jsxRuntime.jsx(react.Table.Body, { children: Array.from({ length: pageSize }).map((_, rowIndex) => {
3225
+ return (jsxRuntime.jsxs(react.Table.Row, { display: 'flex', zIndex: 1, onMouseEnter: () => handleRowHover(rowIndex), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index: rowIndex }), children: [showSelector && jsxRuntime.jsx(TableRowSelectorSkeleton, {}), visibleColumns.map((column, colIndex) => {
3226
+ return (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`,
3227
+ // styling resize and pinning start
3228
+ flex: `${canResize ? '0' : '1'} 0 ${column.getSize()}px`,
3229
+ // this is to avoid the cell from being too wide
3230
+ minWidth: `0`, color: {
3231
+ base: 'colorPalette.900',
3232
+ _dark: 'colorPalette.100',
3233
+ },
3234
+ bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, ...getTdProps(column), children: jsxRuntime.jsx(react.Skeleton, { height: "20px", width: "80%" }) }, `chakra-table-skeleton-cell-${rowIndex}-${colIndex}`));
3235
+ })] }, `chakra-table-skeleton-row-${rowIndex}`));
3064
3236
  }) }));
3065
3237
  };
3066
-
3067
- const TableFilterTags = () => {
3238
+ const TableRowSelectorSkeleton = () => {
3068
3239
  const { table } = useDataTableContext();
3069
- return (jsxRuntime.jsx(react.Flex, { gap: "0.5rem", flexFlow: "wrap", children: table.getState().columnFilters.map(({ id, value }) => {
3070
- return (jsxRuntime.jsx(Tag, { gap: "0.5rem", closable: true, cursor: "pointer", onClick: () => {
3071
- table.setColumnFilters(table.getState().columnFilters.filter((filter) => {
3072
- return filter.value != value;
3073
- }));
3074
- }, children: `${id}: ${value}` }, `${id}-${value}`));
3075
- }) }));
3076
- };
3077
-
3078
- const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsxRuntime.jsx(jsxRuntime.Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterOptions = [], extraItems = jsxRuntime.jsx(jsxRuntime.Fragment, {}), loading = false, hasError = false, }) => {
3079
- const { translate } = useDataTableContext();
3080
- return (jsxRuntime.jsxs(react.Grid, { templateRows: "auto 1fr auto", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", children: [jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: 2, children: [jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", children: [jsxRuntime.jsx(react.Box, { children: showView && jsxRuntime.jsx(ViewDialog, { icon: jsxRuntime.jsx(md.MdOutlineViewColumn, {}) }) }), jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsxRuntime.jsx(react.Spinner, { size: "sm" }), hasError && (jsxRuntime.jsx(Tooltip, { content: translate.t("hasError"), children: jsxRuntime.jsx(react.Icon, { as: bs.BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsxRuntime.jsx(GlobalFilter, {}), showFilter && jsxRuntime.jsx(FilterDialog, {}), showReload && jsxRuntime.jsx(ReloadButton, {}), extraItems] })] }), filterOptions.length > 0 && (jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: "0.5rem", children: filterOptions.map((column) => {
3081
- return (jsxRuntime.jsxs(react.Flex, { alignItems: "center", flexFlow: "wrap", gap: "0.5rem", children: [showFilterName && jsxRuntime.jsxs(react.Text, { children: [column, ":"] }), jsxRuntime.jsx(FilterOptions, { column: column })] }, column));
3082
- }) })), showFilterTags && (jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(TableFilterTags, {}) }))] }), jsxRuntime.jsx(react.Grid, { overflow: "auto", backgroundColor: "gray.50", _dark: {
3083
- backgroundColor: "gray.900",
3084
- }, children: children }), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", children: [jsxRuntime.jsxs(react.Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsxRuntime.jsx(PageSizeControl, {}), showPageCountText && (jsxRuntime.jsxs(react.Flex, { children: [jsxRuntime.jsx(react.Text, { paddingRight: "0.5rem", children: translate.t("rowcount.total") }), jsxRuntime.jsx(RowCountText, {})] }))] }), jsxRuntime.jsx(react.Box, { justifySelf: "end", children: showPagination && jsxRuntime.jsx(Pagination, {}) })] })] }));
3240
+ const SELECTION_BOX_WIDTH = 20;
3241
+ return (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`, display: 'grid', color: {
3242
+ base: 'colorPalette.900',
3243
+ _dark: 'colorPalette.100',
3244
+ },
3245
+ bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(react.Skeleton, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }) }));
3085
3246
  };
3086
3247
 
3087
- const TableFooter = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, alwaysShowSelector = true, }) => {
3248
+ const TableFooter = ({ showSelector = false, alwaysShowSelector = true, }) => {
3088
3249
  const table = useDataTableContext().table;
3089
3250
  const SELECTION_BOX_WIDTH = 20;
3090
3251
  const [hoveredCheckBox, setHoveredCheckBox] = React.useState(false);
@@ -3103,65 +3264,62 @@ const TableFooter = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, s
3103
3264
  }
3104
3265
  return false;
3105
3266
  };
3106
- const getThProps = (header) => {
3107
- const thProps = header.column.getIsPinned()
3108
- ? {
3109
- left: showSelector
3110
- ? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
3111
- : `${header.getStart("left") + table.getDensityValue() * 2}px`,
3112
- background: pinnedBgColor.light,
3113
- position: "sticky",
3114
- zIndex: 1,
3115
- _dark: {
3116
- backgroundColor: pinnedBgColor.dark,
3117
- },
3118
- }
3119
- : {};
3120
- return thProps;
3121
- };
3122
- return (jsxRuntime.jsx(react.Table.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: "flex", children: [showSelector && (jsxRuntime.jsxs(react.Table.Header
3123
- // styling resize and pinning start
3124
- , {
3125
- // styling resize and pinning start
3126
- padding: `${table.getDensityValue()}px`, ...(table.getIsSomeColumnsPinned("left")
3127
- ? {
3128
- left: `0px`,
3129
- backgroundColor: pinnedBgColor.light,
3130
- position: "sticky",
3131
- zIndex: 1,
3132
- _dark: { backgroundColor: pinnedBgColor.dark },
3133
- }
3134
- : {}),
3135
- // styling resize and pinning end
3136
- onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
3267
+ return (jsxRuntime.jsx(react.Table.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: "flex", children: [showSelector && (jsxRuntime.jsxs(react.Table.Header, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
3137
3268
  // indeterminate: table.getIsSomeRowsSelected(),
3138
3269
  onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), footerGroup.headers.map((header) => (jsxRuntime.jsx(react.Table.Cell, { padding: "0", columnSpan: `${header.colSpan}`,
3139
3270
  // styling resize and pinning start
3140
- maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", ...getThProps(header), children: jsxRuntime.jsx(react.MenuRoot, { children: jsxRuntime.jsx(react.MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", _hover: { backgroundColor: "gray.100" }, children: jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
3271
+ maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", children: jsxRuntime.jsx(react.MenuRoot, { children: jsxRuntime.jsx(react.MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", children: jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
3141
3272
  ? null
3142
- : reactTable.flexRender(header.column.columnDef.footer, header.getContext()), jsxRuntime.jsx(react.Box, { children: header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [header.column.getIsSorted() === false && (
3143
- // <UpDownIcon />
3144
- jsxRuntime.jsx(jsxRuntime.Fragment, {})), header.column.getIsSorted() === "asc" && (jsxRuntime.jsx(bi.BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsxRuntime.jsx(bi.BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
3273
+ : reactTable.flexRender(header.column.columnDef.footer, header.getContext()), jsxRuntime.jsx(react.Box, { children: header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [header.column.getIsSorted() === false && jsxRuntime.jsx(jsxRuntime.Fragment, {}), header.column.getIsSorted() === "asc" && (jsxRuntime.jsx(bi.BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsxRuntime.jsx(bi.BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
3145
3274
  };
3146
3275
 
3147
- const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, isSticky = true, alwaysShowSelector = true, tHeadProps = {}, }) => {
3276
+ // Default text values
3277
+ const DEFAULT_HEADER_TEXTS = {
3278
+ pinColumn: "Pin Column",
3279
+ cancelPin: "Cancel Pin",
3280
+ sortAscending: "Sort Ascending",
3281
+ sortDescending: "Sort Descending",
3282
+ clearSorting: "Clear Sorting",
3283
+ };
3284
+ /**
3285
+ * TableHeader component with configurable text strings.
3286
+ *
3287
+ * @example
3288
+ * // Using default texts
3289
+ * <TableHeader />
3290
+ *
3291
+ * @example
3292
+ * // Customizing default texts for all columns
3293
+ * <TableHeader
3294
+ * defaultTexts={{
3295
+ * pinColumn: "Pin This Column",
3296
+ * sortAscending: "Sort A-Z"
3297
+ * }}
3298
+ * />
3299
+ *
3300
+ * @example
3301
+ * // Customizing texts per column via meta
3302
+ * const columns = [
3303
+ * columnHelper.accessor("name", {
3304
+ * header: "Name",
3305
+ * meta: {
3306
+ * headerTexts: {
3307
+ * pinColumn: "Pin Name Column",
3308
+ * sortAscending: "Sort Names A-Z"
3309
+ * }
3310
+ * }
3311
+ * })
3312
+ * ];
3313
+ */
3314
+ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true, tableHeaderProps = {}, tableRowProps = {}, defaultTexts = {}, }) => {
3148
3315
  const { table } = useDataTableContext();
3149
3316
  const SELECTION_BOX_WIDTH = 20;
3150
- const [hoveredCheckBox, setHoveredCheckBox] = React.useState(false);
3151
- const handleRowHover = (isHovered) => {
3152
- setHoveredCheckBox(isHovered);
3153
- };
3154
- const isCheckBoxVisible = () => {
3155
- if (alwaysShowSelector) {
3156
- return true;
3157
- }
3158
- if (table.getIsAllRowsSelected()) {
3159
- return true;
3160
- }
3161
- if (hoveredCheckBox) {
3162
- return true;
3163
- }
3164
- return false;
3317
+ // Merge default texts with provided defaults
3318
+ const mergedDefaultTexts = { ...DEFAULT_HEADER_TEXTS, ...defaultTexts };
3319
+ // Helper function to get text for a specific header
3320
+ const getHeaderText = (header, key) => {
3321
+ const columnMeta = header.column.columnDef.meta;
3322
+ return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
3165
3323
  };
3166
3324
  const getThProps = (header) => {
3167
3325
  const thProps = header.column.getIsPinned()
@@ -3169,12 +3327,8 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3169
3327
  left: showSelector
3170
3328
  ? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
3171
3329
  : `${header.getStart("left")}px`,
3172
- background: pinnedBgColor.light,
3173
3330
  position: "sticky",
3174
3331
  zIndex: 100 + 1,
3175
- _dark: {
3176
- backgroundColor: pinnedBgColor.dark,
3177
- },
3178
3332
  }
3179
3333
  : {};
3180
3334
  return thProps;
@@ -3183,21 +3337,13 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3183
3337
  position: "sticky",
3184
3338
  top: 0,
3185
3339
  };
3186
- return (jsxRuntime.jsx(react.Table.Header, { ...(isSticky ? stickyProps : {}), ...tHeadProps, children: table.getHeaderGroups().map((headerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: "flex", children: [showSelector && (jsxRuntime.jsxs(react.Table.ColumnHeader
3187
- // styling resize and pinning start
3188
- , { ...(table.getIsSomeColumnsPinned("left")
3189
- ? {
3190
- left: `0px`,
3191
- backgroundColor: pinnedBgColor.light,
3192
- position: "sticky",
3193
- zIndex: 1,
3194
- _dark: { backgroundColor: pinnedBgColor.dark },
3195
- }
3196
- : {}),
3197
- // styling resize and pinning end
3198
- padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
3199
- // indeterminate: table.getIsSomeRowsSelected(),
3200
- onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), headerGroup.headers.map((header) => {
3340
+ return (jsxRuntime.jsx(react.Table.Header, { ...(isSticky ? stickyProps : {}), bgColor: "transparent", ...tableHeaderProps, children: table.getHeaderGroups().map((headerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: "flex", bgColor: "transparent", ...tableRowProps, children: [showSelector && (jsxRuntime.jsx(react.Table.ColumnHeader, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
3341
+ base: "colorPalette.900",
3342
+ _dark: "colorPalette.100",
3343
+ },
3344
+ bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: table.getIsAllRowsSelected(),
3345
+ // indeterminate: table.getIsSomeRowsSelected(),
3346
+ onChange: table.getToggleAllRowsSelectedHandler() }) })), headerGroup.headers.map((header) => {
3201
3347
  const resizeProps = {
3202
3348
  onMouseDown: header.getResizeHandler(),
3203
3349
  onTouchStart: header.getResizeHandler(),
@@ -3205,18 +3351,32 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3205
3351
  };
3206
3352
  return (jsxRuntime.jsxs(react.Table.ColumnHeader, { padding: 0, columnSpan: `${header.colSpan}`,
3207
3353
  // styling resize and pinning start
3208
- flex: `${canResize ? "0" : "1"} 0 ${header.column.getSize()}px`, display: "grid", gridTemplateColumns: "1fr auto", zIndex: 1500 + header.index, ...getThProps(header), children: [jsxRuntime.jsxs(MenuRoot, { children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Flex, { padding: `${table.getDensityValue()}px`, alignItems: "center", justifyContent: "start", borderRadius: "0rem", overflow: "auto", _hover: {
3209
- backgroundColor: "gray.100",
3210
- _dark: {
3211
- backgroundColor: "gray.700",
3354
+ flex: `${canResize ? "0" : "1"} 0 ${header.column.getSize()}px`, display: "grid", gridTemplateColumns: "1fr auto", zIndex: 1500 + header.index, color: {
3355
+ base: "colorPalette.800",
3356
+ _dark: "colorPalette.200",
3357
+ },
3358
+ bg: { base: "colorPalette.100", _dark: "colorPalette.900" }, ...getThProps(header), children: [jsxRuntime.jsxs(MenuRoot, { children: [jsxRuntime.jsx(MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Flex, { padding: `${table.getDensityValue()}px`, alignItems: "center", justifyContent: "start", borderRadius: "0rem", overflow: "auto", color: {
3359
+ base: "colorPalette.800",
3360
+ _dark: "colorPalette.200",
3361
+ _hover: {
3362
+ base: "colorPalette.700",
3363
+ _dark: "colorPalette.300",
3364
+ },
3365
+ },
3366
+ bg: {
3367
+ base: "colorPalette.100",
3368
+ _dark: "colorPalette.900",
3369
+ _hover: {
3370
+ base: "colorPalette.200",
3371
+ _dark: "colorPalette.800",
3212
3372
  },
3213
3373
  }, children: jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
3214
3374
  ? null
3215
3375
  : reactTable.flexRender(header.column.columnDef.header, header.getContext()), jsxRuntime.jsx(react.Box, { children: header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [header.column.getIsSorted() === false && jsxRuntime.jsx(jsxRuntime.Fragment, {}), header.column.getIsSorted() === "asc" && (jsxRuntime.jsx(bi.BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsxRuntime.jsx(bi.BiDownArrow, {}))] })) }), jsxRuntime.jsx(react.Box, { children: header.column.getIsFiltered() && jsxRuntime.jsx(md.MdFilterListAlt, {}) })] }) }) }), jsxRuntime.jsxs(MenuContent, { children: [!header.column.getIsPinned() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "pin-column", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3216
3376
  header.column.pin("left");
3217
- }, children: [jsxRuntime.jsx(md.MdPushPin, {}), "Pin Column"] }) })), header.column.getIsPinned() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3377
+ }, children: [jsxRuntime.jsx(md.MdPushPin, {}), getHeaderText(header, "pinColumn")] }) })), header.column.getIsPinned() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3218
3378
  header.column.pin(false);
3219
- }, children: [jsxRuntime.jsx(md.MdCancel, {}), "Cancel Pin"] }) })), header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3379
+ }, children: [jsxRuntime.jsx(md.MdCancel, {}), getHeaderText(header, "cancelPin")] }) })), header.column.getCanSort() && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3220
3380
  table.setSorting((state) => {
3221
3381
  return [
3222
3382
  ...state.filter((column) => {
@@ -3225,7 +3385,7 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3225
3385
  { id: header.id, desc: false },
3226
3386
  ];
3227
3387
  });
3228
- }, children: [jsxRuntime.jsx(gr.GrAscend, {}), "Sort Ascending"] }) }), jsxRuntime.jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3388
+ }, children: [jsxRuntime.jsx(gr.GrAscend, {}), getHeaderText(header, "sortAscending")] }) }), jsxRuntime.jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3229
3389
  table.setSorting((state) => {
3230
3390
  return [
3231
3391
  ...state.filter((column) => {
@@ -3234,42 +3394,53 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3234
3394
  { id: header.id, desc: true },
3235
3395
  ];
3236
3396
  });
3237
- }, children: [jsxRuntime.jsx(gr.GrDescend, {}), "Sort Descending"] }) }), header.column.getIsSorted() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3397
+ }, children: [jsxRuntime.jsx(gr.GrDescend, {}), getHeaderText(header, "sortDescending")] }) }), header.column.getIsSorted() && (jsxRuntime.jsx(MenuItem, { asChild: true, value: "clear-sorting", children: jsxRuntime.jsxs(Button, { variant: "ghost", onClick: () => {
3238
3398
  header.column.clearSorting();
3239
- }, children: [jsxRuntime.jsx(md.MdClear, {}), "Clear Sorting"] }) }))] }))] })] }), canResize && (jsxRuntime.jsx(react.Box, { borderRight: "0.2rem solid", borderRightColor: header.column.getIsResizing() ? "gray.700" : "transparent", position: "relative", right: "0.1rem", width: "2px", height: "100%", userSelect: "none", style: { touchAction: "none" }, _hover: {
3399
+ }, children: [jsxRuntime.jsx(md.MdClear, {}), getHeaderText(header, "clearSorting")] }) }))] }))] })] }), canResize && (jsxRuntime.jsx(react.Box, { borderRight: "0.2rem solid", borderRightColor: header.column.getIsResizing()
3400
+ ? "colorPalette.700"
3401
+ : "transparent", position: "relative", right: "0.1rem", width: "2px", height: "100%", userSelect: "none", style: { touchAction: "none" }, _hover: {
3240
3402
  borderRightColor: header.column.getIsResizing()
3241
- ? "gray.700"
3242
- : "gray.400",
3403
+ ? "colorPalette.700"
3404
+ : "colorPalette.400",
3243
3405
  }, ...resizeProps }))] }, `chakra-table-header-${header.id}`));
3244
3406
  })] }, `chakra-table-headergroup-${headerGroup.id}`))) }));
3245
3407
  };
3246
3408
 
3247
- const EmptyState = React__namespace.forwardRef(function EmptyState(props, ref) {
3248
- const { title, description, icon, children, ...rest } = props;
3249
- return (jsxRuntime.jsx(react.EmptyState.Root, { ref: ref, ...rest, children: jsxRuntime.jsxs(react.EmptyState.Content, { children: [icon && (jsxRuntime.jsx(react.EmptyState.Indicator, { children: icon })), description ? (jsxRuntime.jsxs(react.VStack, { textAlign: "center", children: [jsxRuntime.jsx(react.EmptyState.Title, { children: title }), jsxRuntime.jsx(react.EmptyState.Description, { children: description })] })) : (jsxRuntime.jsx(react.EmptyState.Title, { children: title })), children] }) }));
3250
- });
3251
-
3252
- const EmptyResult = (jsxRuntime.jsx(EmptyState, { icon: jsxRuntime.jsx(hi.HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxRuntime.jsxs(react.List.Root, { variant: "marker", children: [jsxRuntime.jsx(react.List.Item, { children: "Try removing filters" }), jsxRuntime.jsx(react.List.Item, { children: "Try different keywords" })] }) }));
3253
- const Table = ({ children, emptyComponent = EmptyResult, canResize = true, ...props }) => {
3254
- const { table } = useDataTableContext();
3255
- if (table.getRowModel().rows.length <= 0) {
3256
- return emptyComponent;
3409
+ const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = '', isLoading = false, }) => {
3410
+ if (variant === 'greedy') {
3411
+ const bodyComponent = isLoading ? (jsxRuntime.jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: false })) : (jsxRuntime.jsx(TableBody, { ...tableBodyProps, canResize: false, ...tableBodyProps }));
3412
+ return (jsxRuntime.jsx(TableControls, { ...controlProps, children: jsxRuntime.jsxs(Table, { canResize: false, showLoading: isLoading, ...tableProps, children: [jsxRuntime.jsx(TableHeader, { canResize: false, ...tableHeaderProps }), bodyComponent, showFooter && (jsxRuntime.jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
3257
3413
  }
3258
- return (jsxRuntime.jsx(react.Table.Root, { stickyHeader: true, variant: "outline", width: canResize ? table.getCenterTotalSize() : undefined, display: "grid", alignContent: "start", overflowY: "auto", ...props, children: children }));
3414
+ const bodyComponent = isLoading ? (jsxRuntime.jsx(TableBodySkeleton, { showSelector: tableBodyProps.showSelector, canResize: tableBodyProps.canResize })) : (jsxRuntime.jsx(TableBody, { ...tableBodyProps }));
3415
+ return (jsxRuntime.jsx(TableControls, { ...controlProps, children: jsxRuntime.jsxs(Table, { showLoading: isLoading, ...tableProps, children: [jsxRuntime.jsx(TableHeader, { ...tableHeaderProps }), bodyComponent, showFooter && jsxRuntime.jsx(TableFooter, { ...tableFooterProps })] }) }));
3259
3416
  };
3260
3417
 
3261
- const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, controlProps = {}, tableFooterProps = {}, variant = "", }) => {
3262
- if (variant === "greedy") {
3263
- return (jsxRuntime.jsx(TableControls, { ...controlProps, children: jsxRuntime.jsxs(Table, { canResize: false, ...{ ...tableProps }, children: [jsxRuntime.jsx(TableHeader, { canResize: false, ...tableHeaderProps }), jsxRuntime.jsx(TableBody, { canResize: false, ...tableBodyProps }), showFooter && (jsxRuntime.jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
3264
- }
3265
- return (jsxRuntime.jsx(TableControls, { ...controlProps, children: jsxRuntime.jsxs(Table, { ...tableProps, children: [jsxRuntime.jsx(TableHeader, { ...tableHeaderProps }), jsxRuntime.jsx(TableBody, { ...tableBodyProps }), showFooter && jsxRuntime.jsx(TableFooter, { ...tableFooterProps })] }) }));
3418
+ /**
3419
+ * DefaultTableServer is a wrapper around DefaultTable that automatically
3420
+ * detects server-side loading state from DataTableServerContext.
3421
+ *
3422
+ * Use this component when working with DataTableServer to automatically
3423
+ * show skeleton loading state during data fetching.
3424
+ *
3425
+ * @example
3426
+ * ```tsx
3427
+ * <DataTableServer columns={columns} {...datatableServer}>
3428
+ * <DefaultTableServer />
3429
+ * </DataTableServer>
3430
+ * ```
3431
+ */
3432
+ const DefaultTableServer = ({ isLoading: isLoadingOverride, ...props }) => {
3433
+ // Automatically detect loading state from server context
3434
+ const serverContext = useDataTableServerContext();
3435
+ const isLoading = isLoadingOverride ?? serverContext?.query?.isLoading ?? false;
3436
+ return jsxRuntime.jsx(DefaultTable, { ...props, isLoading: isLoading });
3266
3437
  };
3267
3438
 
3268
- const TableCardContainer = ({ children, variant = "", ...props }) => {
3439
+ const TableCardContainer = ({ children, variant = "", gap = "1rem", gridTemplateColumns = "repeat(auto-fit, minmax(20rem, 1fr))", direction = "row", ...props }) => {
3269
3440
  if (variant === "carousel") {
3270
- return (jsxRuntime.jsx(react.Flex, { overflow: "scroll", gap: "1rem", children: children }));
3441
+ return (jsxRuntime.jsx(react.Flex, { overflow: "auto", gap: gap, direction: direction, ...props, children: children }));
3271
3442
  }
3272
- return (jsxRuntime.jsx(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(20rem, 1fr))", gap: "0.5rem", ...props, children: children }));
3443
+ return (jsxRuntime.jsx(react.Grid, { gridTemplateColumns: gridTemplateColumns, gap: gap, ...props, children: children }));
3273
3444
  };
3274
3445
 
3275
3446
  const DefaultCardTitle = () => {
@@ -3298,8 +3469,8 @@ const TableComponent = ({ render = () => {
3298
3469
  };
3299
3470
 
3300
3471
  const TableLoadingComponent = ({ render, }) => {
3301
- const { loading } = useDataTableContext();
3302
- return jsxRuntime.jsx(jsxRuntime.Fragment, { children: render(loading) });
3472
+ const { query } = useDataTableServerContext();
3473
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: render(query.isLoading) });
3303
3474
  };
3304
3475
 
3305
3476
  const SelectAllRowsToggle = ({ selectAllIcon = jsxRuntime.jsx(md.MdOutlineChecklist, {}), clearAllIcon = jsxRuntime.jsx(md.MdClear, {}), selectAllText = "", clearAllText = "", }) => {
@@ -3385,50 +3556,43 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
3385
3556
  };
3386
3557
  };
3387
3558
 
3388
- const useDataTableServer = ({ url, default: { sorting: defaultSorting = [], pagination: defaultPagination = {
3389
- pageIndex: 0, //initial page index
3390
- pageSize: 10, //default page size
3391
- }, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = "", density: defaultDensity = "sm", } = {
3392
- sorting: [],
3393
- pagination: {
3559
+ const useDataTableServer = (props) => {
3560
+ const { url, default: defaultProps, keyPrefix, placeholderData, queryFn: customQueryFn, } = props;
3561
+ const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
3562
+ const [sorting, setSorting] = React.useState(defaultSorting || []);
3563
+ const [columnFilters, setColumnFilters] = React.useState(defaultColumnFilters || []); // can set initial column filter state here
3564
+ const [pagination, setPagination] = React.useState(defaultPagination || {
3394
3565
  pageIndex: 0, //initial page index
3395
- pageSize: 10, //age size
3396
- },
3397
- rowSelection: {},
3398
- columnFilters: [],
3399
- columnOrder: [],
3400
- columnVisibility: {},
3401
- globalFilter: "",
3402
- density: "sm",
3403
- }, keyPrefix, }) => {
3404
- const [sorting, setSorting] = React.useState(defaultSorting);
3405
- const [columnFilters, setColumnFilters] = React.useState(defaultColumnFilters); // can set initial column filter state here
3406
- const [pagination, setPagination] = React.useState(defaultPagination);
3407
- const [rowSelection, setRowSelection] = React.useState(defaultRowSelection);
3408
- const [columnOrder, setColumnOrder] = React.useState(defaultColumnOrder);
3409
- const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter);
3410
- const [density, setDensity] = React.useState(defaultDensity);
3411
- const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility);
3566
+ pageSize: 10, //default page size
3567
+ });
3568
+ const [rowSelection, setRowSelection] = React.useState(defaultRowSelection || {});
3569
+ const [columnOrder, setColumnOrder] = React.useState(defaultColumnOrder || []);
3570
+ const [globalFilter, setGlobalFilter] = React.useState(defaultGlobalFilter || "");
3571
+ const [density, setDensity] = React.useState(defaultDensity || "sm");
3572
+ const [columnVisibility, setColumnVisibility] = React.useState(defaultColumnVisibility || {});
3573
+ const { pageSize, pageIndex } = pagination;
3412
3574
  const params = {
3413
- offset: pagination.pageIndex * pagination.pageSize,
3414
- limit: pagination.pageSize,
3575
+ offset: pageIndex * pageSize,
3576
+ limit: pageSize,
3415
3577
  sorting,
3416
3578
  where: columnFilters,
3417
3579
  searching: globalFilter,
3418
3580
  };
3581
+ const defaultQueryFn = async () => {
3582
+ if (!url) {
3583
+ throw new Error("url is required");
3584
+ }
3585
+ const response = await axios.get(url, {
3586
+ params,
3587
+ });
3588
+ return response.data;
3589
+ };
3419
3590
  const query = reactQuery.useQuery({
3420
3591
  queryKey: [url, JSON.stringify(params)],
3421
- queryFn: () => {
3422
- return axios
3423
- .get(url, {
3424
- params,
3425
- })
3426
- .then((res) => res.data);
3427
- },
3428
- placeholderData: {
3429
- count: 0,
3430
- data: [],
3431
- },
3592
+ queryFn: customQueryFn !== undefined
3593
+ ? () => customQueryFn(params)
3594
+ : defaultQueryFn,
3595
+ placeholderData,
3432
3596
  });
3433
3597
  const translate = reactI18next.useTranslation("", { keyPrefix });
3434
3598
  return {
@@ -3518,23 +3682,33 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
3518
3682
  return columns;
3519
3683
  };
3520
3684
 
3521
- const TableDataDisplay = () => {
3522
- const { table, columns, translate } = useDataTableContext();
3523
- const { query } = useDataTableServerContext();
3524
- const { data } = query;
3525
- const columnDef = table._getColumnDefs();
3526
- console.log(columnDef, "glp");
3527
- console.log(columnDef, columns, table.getState().columnOrder, data, "glp");
3685
+ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
3686
+ const { columns, translate, data } = useDataTableContext();
3528
3687
  const columnsMap = Object.fromEntries(columns.map((def) => {
3529
- return [def.accessorKey, def];
3688
+ const { accessorKey, id } = def;
3689
+ if (accessorKey) {
3690
+ return [accessorKey, def];
3691
+ }
3692
+ return [id, def];
3530
3693
  }));
3531
3694
  const columnHeaders = Object.keys(columnsMap);
3695
+ const totalWidths = columns
3696
+ .map(({ size }) => {
3697
+ if (!!size === false) {
3698
+ return 0;
3699
+ }
3700
+ if (typeof size === "number") {
3701
+ return size;
3702
+ }
3703
+ return 0;
3704
+ })
3705
+ .reduce((previous, current) => previous + current, 0);
3532
3706
  const columnWidths = columns
3533
3707
  .map(({ size }) => {
3534
3708
  if (!!size === false) {
3535
3709
  return "1fr";
3536
3710
  }
3537
- return `${size}px`;
3711
+ return `minmax(${size}px, ${(size / totalWidths) * 100}%)`;
3538
3712
  })
3539
3713
  .join(" ");
3540
3714
  console.log({ columnWidths }, "hadfg");
@@ -3543,48 +3717,55 @@ const TableDataDisplay = () => {
3543
3717
  overflow: "auto",
3544
3718
  paddingX: "2",
3545
3719
  py: "1",
3720
+ color: { base: "colorPalette.900", _dark: "colorPalette.100" },
3721
+ bgColor: { base: "colorPalette.50", _dark: "colorPalette.950" },
3546
3722
  borderBottomColor: { base: "colorPalette.200", _dark: "colorPalette.800" },
3547
3723
  borderBottomWidth: "1px",
3724
+ ...{ colorPalette },
3548
3725
  };
3549
- return (jsxRuntime.jsxs(react.Grid, { templateColumns: `${columnWidths}`, overflow: "auto", borderWidth: "1px", borderColor: { base: "colorPalette.200", _dark: "colorPalette.800" }, children: [jsxRuntime.jsx(react.Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: "colorPalette.200", _dark: "colorPalette.800" }, children: columnHeaders.map((header) => {
3550
- return (jsxRuntime.jsx(react.Box, { flex: "1 0 0%", paddingX: "2", py: "1", children: translate.t(`column_header.${header}`) }));
3551
- }) }), data?.data.map((record) => {
3726
+ if (data.length <= 0) {
3727
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: emptyComponent });
3728
+ }
3729
+ return (jsxRuntime.jsxs(react.Grid, { templateColumns: `${columnWidths}`, overflow: "auto", borderWidth: "1px", color: { base: "colorPalette.900", _dark: "colorPalette.100" }, borderColor: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: [jsxRuntime.jsx(react.Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: columnHeaders.map((header) => {
3730
+ return (jsxRuntime.jsx(react.Box, { flex: "1 0 0%", paddingX: "2", py: "1", overflow: "auto", textOverflow: "ellipsis", children: translate.t(`column_header.${header}`) }));
3731
+ }) }), data.map((record) => {
3552
3732
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: columnHeaders.map((header) => {
3733
+ const { cell } = columnsMap[header];
3734
+ const value = record[header];
3553
3735
  if (!!record === false) {
3554
3736
  return (jsxRuntime.jsx(react.Box, { ...cellProps, children: translate.t(`column_cell.placeholder`) }));
3555
3737
  }
3556
- if (!!record[header] === false) {
3557
- return (jsxRuntime.jsx(react.Box, { ...cellProps, children: translate.t(`column_cell.placeholder`) }));
3738
+ if (cell) {
3739
+ return (jsxRuntime.jsx(react.Box, { ...cellProps, children: cell({ row: { original: record } }) }));
3558
3740
  }
3559
- if (typeof record[header] === "object") {
3560
- return (jsxRuntime.jsx(react.Box, { ...cellProps, children: jsxRuntime.jsx(RecordDisplay, { object: record[header] }) }));
3741
+ if (typeof value === "object") {
3742
+ return (jsxRuntime.jsx(react.Box, { ...cellProps, children: jsxRuntime.jsx(RecordDisplay, { object: value }) }));
3561
3743
  }
3562
- return jsxRuntime.jsx(react.Box, { ...cellProps, children: record[header] ?? "" });
3744
+ return jsxRuntime.jsx(react.Box, { ...cellProps, children: value });
3563
3745
  }) }));
3564
3746
  })] }));
3565
3747
  };
3566
3748
 
3567
- const AccordionItemTrigger = React__namespace.forwardRef(function AccordionItemTrigger(props, ref) {
3568
- const { children, indicatorPlacement = "end", ...rest } = props;
3569
- return (jsxRuntime.jsxs(react.Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsxRuntime.jsx(react.Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsxRuntime.jsx(lu.LuChevronDown, {}) })), jsxRuntime.jsx(react.HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsxRuntime.jsx(react.Accordion.ItemIndicator, { children: jsxRuntime.jsx(lu.LuChevronDown, {}) }))] }));
3570
- });
3571
- const AccordionItemContent = React__namespace.forwardRef(function AccordionItemContent(props, ref) {
3572
- return (jsxRuntime.jsx(react.Accordion.ItemContent, { children: jsxRuntime.jsx(react.Accordion.ItemBody, { ...props, ref: ref }) }));
3573
- });
3574
- const AccordionRoot = react.Accordion.Root;
3575
- const AccordionItem = react.Accordion.Item;
3576
-
3577
3749
  //@ts-expect-error TODO: find appropriate type
3578
3750
  const SchemaFormContext = React.createContext({
3579
3751
  schema: {},
3580
- serverUrl: "",
3581
- requestUrl: "",
3752
+ serverUrl: '',
3753
+ requestUrl: '',
3582
3754
  order: [],
3583
3755
  ignore: [],
3584
3756
  include: [],
3585
3757
  onSubmit: async () => { },
3586
3758
  rowNumber: 0,
3587
3759
  requestOptions: {},
3760
+ timezone: 'Asia/Hong_Kong',
3761
+ displayConfig: {
3762
+ showSubmitButton: true,
3763
+ showResetButton: true,
3764
+ showTitle: true,
3765
+ },
3766
+ requireConfirmation: false,
3767
+ onFormSubmit: async () => { },
3768
+ ajvResolver: async () => ({ values: {}, errors: {} }),
3588
3769
  });
3589
3770
 
3590
3771
  const useSchemaContext = () => {
@@ -3595,6 +3776,202 @@ const clearEmptyString = (object) => {
3595
3776
  return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3596
3777
  };
3597
3778
 
3779
+ const validateData = (data, schema) => {
3780
+ const ajv = new Ajv({
3781
+ strict: false,
3782
+ allErrors: true,
3783
+ });
3784
+ addFormats(ajv);
3785
+ const validate = ajv.compile(schema);
3786
+ const validationResult = validate(data);
3787
+ const errors = validate.errors;
3788
+ console.log(errors, data);
3789
+ return {
3790
+ isValid: validationResult,
3791
+ validate,
3792
+ errors,
3793
+ };
3794
+ };
3795
+
3796
+ /**
3797
+ * Gets the schema node for a field by following the path from root schema
3798
+ */
3799
+ const getSchemaNodeForField = (schema, fieldPath) => {
3800
+ if (!fieldPath || fieldPath === '') {
3801
+ return schema;
3802
+ }
3803
+ const pathParts = fieldPath.split('.');
3804
+ let currentSchema = schema;
3805
+ for (const part of pathParts) {
3806
+ if (currentSchema &&
3807
+ currentSchema.properties &&
3808
+ currentSchema.properties[part] &&
3809
+ typeof currentSchema.properties[part] === 'object' &&
3810
+ currentSchema.properties[part] !== null) {
3811
+ currentSchema = currentSchema.properties[part];
3812
+ }
3813
+ else {
3814
+ return undefined;
3815
+ }
3816
+ }
3817
+ return currentSchema;
3818
+ };
3819
+ /**
3820
+ * Converts AJV error objects to react-hook-form field errors format
3821
+ */
3822
+ const convertAjvErrorsToFieldErrors = (errors, schema) => {
3823
+ if (!errors || errors.length === 0) {
3824
+ return {};
3825
+ }
3826
+ const fieldErrors = {};
3827
+ errors.forEach((error) => {
3828
+ let fieldName = '';
3829
+ // Special handling for required keyword: map to the specific missing property
3830
+ if (error.keyword === 'required') {
3831
+ const basePath = (error.instancePath || '')
3832
+ .replace(/^\//, '')
3833
+ .replace(/\//g, '.');
3834
+ const missingProperty = (error.params &&
3835
+ error.params.missingProperty);
3836
+ if (missingProperty) {
3837
+ fieldName = basePath
3838
+ ? `${basePath}.${missingProperty}`
3839
+ : missingProperty;
3840
+ }
3841
+ else {
3842
+ // Fallback to schemaPath conversion if missingProperty is unavailable
3843
+ fieldName = (error.schemaPath || '')
3844
+ .replace(/^#\//, '#.')
3845
+ .replace(/\//g, '.');
3846
+ }
3847
+ }
3848
+ else {
3849
+ const fieldPath = error.instancePath || error.schemaPath;
3850
+ if (fieldPath) {
3851
+ fieldName = fieldPath.replace(/^\//, '').replace(/\//g, '.');
3852
+ }
3853
+ }
3854
+ if (fieldName) {
3855
+ // Get the schema node for this field to check for custom error messages
3856
+ const fieldSchema = getSchemaNodeForField(schema, fieldName);
3857
+ const customMessage = fieldSchema?.errorMessages?.[error.keyword];
3858
+ // Provide helpful fallback message if no custom message is provided
3859
+ const fallbackMessage = customMessage ||
3860
+ `Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
3861
+ if (error.keyword === 'required') {
3862
+ // Required errors override any existing non-required errors for this field
3863
+ fieldErrors[fieldName] = {
3864
+ type: 'required',
3865
+ keyword: error.keyword,
3866
+ params: error.params,
3867
+ message: fallbackMessage,
3868
+ };
3869
+ }
3870
+ else {
3871
+ const existing = fieldErrors[fieldName];
3872
+ if (existing) {
3873
+ // Do not override required errors
3874
+ if (existing.type === 'required') {
3875
+ return;
3876
+ }
3877
+ // Combine messages if multiple errors for same field
3878
+ existing.message = existing.message
3879
+ ? `${existing.message}; ${fallbackMessage}`
3880
+ : fallbackMessage;
3881
+ }
3882
+ else {
3883
+ fieldErrors[fieldName] = {
3884
+ type: error.keyword,
3885
+ keyword: error.keyword,
3886
+ params: error.params,
3887
+ message: fallbackMessage,
3888
+ };
3889
+ }
3890
+ }
3891
+ }
3892
+ });
3893
+ return fieldErrors;
3894
+ };
3895
+ /**
3896
+ * AJV resolver for react-hook-form
3897
+ * Integrates AJV validation with react-hook-form's validation system
3898
+ */
3899
+ /**
3900
+ * Strips null, undefined, and empty string values from an object
3901
+ */
3902
+ const stripEmptyValues = (obj) => {
3903
+ if (obj === null || obj === undefined) {
3904
+ return undefined;
3905
+ }
3906
+ if (typeof obj === 'string' && obj.trim() === '') {
3907
+ return undefined;
3908
+ }
3909
+ if (Array.isArray(obj)) {
3910
+ const filtered = obj
3911
+ .map(stripEmptyValues)
3912
+ .filter((item) => item !== undefined);
3913
+ return filtered.length > 0 ? filtered : undefined;
3914
+ }
3915
+ if (typeof obj === 'object' && obj !== null) {
3916
+ const result = {};
3917
+ let hasValues = false;
3918
+ for (const [key, value] of Object.entries(obj)) {
3919
+ const cleanedValue = stripEmptyValues(value);
3920
+ if (cleanedValue !== undefined) {
3921
+ result[key] = cleanedValue;
3922
+ hasValues = true;
3923
+ }
3924
+ }
3925
+ return hasValues ? result : undefined;
3926
+ }
3927
+ return obj;
3928
+ };
3929
+ const ajvResolver = (schema) => {
3930
+ return async (values) => {
3931
+ try {
3932
+ // Strip empty values before validation
3933
+ const cleanedValues = stripEmptyValues(values);
3934
+ // Use empty object for validation if all values were stripped
3935
+ const valuesToValidate = cleanedValues === undefined ? {} : cleanedValues;
3936
+ const { isValid, errors } = validateData(valuesToValidate, schema);
3937
+ console.debug('AJV Validation Result:', {
3938
+ isValid,
3939
+ errors,
3940
+ cleanedValues,
3941
+ valuesToValidate,
3942
+ });
3943
+ if (isValid) {
3944
+ return {
3945
+ values: (cleanedValues || {}),
3946
+ errors: {},
3947
+ };
3948
+ }
3949
+ const fieldErrors = convertAjvErrorsToFieldErrors(errors, schema);
3950
+ console.debug('AJV Validation Failed:', {
3951
+ errors,
3952
+ fieldErrors,
3953
+ cleanedValues,
3954
+ valuesToValidate,
3955
+ });
3956
+ return {
3957
+ values: {},
3958
+ errors: fieldErrors,
3959
+ };
3960
+ }
3961
+ catch (error) {
3962
+ return {
3963
+ values: {},
3964
+ errors: {
3965
+ root: {
3966
+ type: 'validation',
3967
+ message: error instanceof Error ? error.message : 'Validation failed',
3968
+ },
3969
+ },
3970
+ };
3971
+ }
3972
+ };
3973
+ };
3974
+
3598
3975
  const idPickerSanityCheck = (column, foreign_key) => {
3599
3976
  if (!!foreign_key == false) {
3600
3977
  throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
@@ -3610,13 +3987,65 @@ const idPickerSanityCheck = (column, foreign_key) => {
3610
3987
  throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
3611
3988
  }
3612
3989
  };
3613
- const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, }) => {
3990
+ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, customSuccessRenderer, displayConfig = {
3991
+ showSubmitButton: true,
3992
+ showResetButton: true,
3993
+ showTitle: true,
3994
+ }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, }) => {
3614
3995
  const [isSuccess, setIsSuccess] = React.useState(false);
3615
3996
  const [isError, setIsError] = React.useState(false);
3616
3997
  const [isSubmiting, setIsSubmiting] = React.useState(false);
3617
3998
  const [isConfirming, setIsConfirming] = React.useState(false);
3618
3999
  const [validatedData, setValidatedData] = React.useState();
3619
4000
  const [error, setError] = React.useState();
4001
+ const onBeforeSubmit = () => {
4002
+ setIsSubmiting(true);
4003
+ };
4004
+ const onAfterSubmit = () => {
4005
+ setIsSubmiting(false);
4006
+ };
4007
+ const onSubmitError = (error) => {
4008
+ setIsError(true);
4009
+ setError(error);
4010
+ };
4011
+ const onSubmitSuccess = () => {
4012
+ setIsSuccess(true);
4013
+ };
4014
+ const defaultOnSubmit = async (promise) => {
4015
+ try {
4016
+ console.log('onBeforeSubmit');
4017
+ onBeforeSubmit();
4018
+ await promise;
4019
+ console.log('onSubmitSuccess');
4020
+ onSubmitSuccess();
4021
+ }
4022
+ catch (error) {
4023
+ console.log('onSubmitError', error);
4024
+ onSubmitError(error);
4025
+ }
4026
+ finally {
4027
+ onAfterSubmit();
4028
+ }
4029
+ };
4030
+ const defaultSubmitPromise = (data) => {
4031
+ const options = {
4032
+ method: 'POST',
4033
+ url: `${serverUrl}`,
4034
+ data: clearEmptyString(data),
4035
+ ...requestOptions,
4036
+ };
4037
+ return axios.request(options);
4038
+ };
4039
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4040
+ const onFormSubmit = async (data) => {
4041
+ // AJV validation is now handled by react-hook-form resolver
4042
+ // This function will only be called if validation passes
4043
+ if (onSubmit === undefined) {
4044
+ await defaultOnSubmit(Promise.resolve(defaultSubmitPromise(data)));
4045
+ return;
4046
+ }
4047
+ await defaultOnSubmit(Promise.resolve(onSubmit(data)));
4048
+ };
3620
4049
  return (jsxRuntime.jsx(SchemaFormContext.Provider, { value: {
3621
4050
  schema,
3622
4051
  serverUrl,
@@ -3643,11 +4072,21 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3643
4072
  error,
3644
4073
  setError,
3645
4074
  getUpdatedData,
4075
+ customErrorRenderer,
4076
+ customSuccessRenderer,
4077
+ displayConfig,
4078
+ requireConfirmation,
4079
+ onFormSubmit,
4080
+ dateTimePickerLabels,
4081
+ idPickerLabels,
4082
+ enumPickerLabels,
4083
+ filePickerLabels,
4084
+ ajvResolver: ajvResolver(schema),
3646
4085
  }, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
3647
4086
  };
3648
4087
 
3649
4088
  function removeIndex(str) {
3650
- return str.replace(/\.\d+\./g, '.');
4089
+ return str.replace(/\.\d+\./g, ".");
3651
4090
  }
3652
4091
 
3653
4092
  const ArrayRenderer = ({ schema, column, prefix, }) => {
@@ -3659,13 +4098,17 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3659
4098
  const isRequired = required?.some((columnId) => columnId === column);
3660
4099
  const { formState: { errors }, setValue, watch, } = reactHookForm.useFormContext();
3661
4100
  const fields = (watch(colLabel) ?? []);
3662
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), fields.map((field, index) => (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", children: [jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: jsxRuntime.jsx(SchemaRenderer, { column: `${index}`,
3663
- prefix: `${colLabel}.`,
3664
- schema: items }) }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { variant: "ghost", onClick: () => {
3665
- setValue(colLabel, fields.filter((_, curIndex) => {
3666
- return curIndex === index;
3667
- }));
3668
- }, children: translate.t(removeIndex(`${colLabel}.remove`)) }) })] }, `${colLabel}.${index}`))), jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(react.Button, { onClick: () => {
4101
+ return (jsxRuntime.jsxs(react.Flex, { gridRow, gridColumn, flexFlow: "column", gap: 2, children: [jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 2, children: fields.map((field, index) => (jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
4102
+ base: "colorPalette.200",
4103
+ _dark: "colorPalette.800",
4104
+ }, children: [jsxRuntime.jsx(react.Grid, { gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsxRuntime.jsx(SchemaRenderer, { column: `${index}`,
4105
+ prefix: `${colLabel}.`,
4106
+ // @ts-expect-error find suitable types
4107
+ schema: { showLabel: false, ...(items ?? {}) } }) }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { variant: "ghost", onClick: () => {
4108
+ setValue(colLabel, fields.filter((_, curIndex) => {
4109
+ return curIndex !== index;
4110
+ }));
4111
+ }, children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(cg.CgTrash, {}) }) }) })] }, `${colLabel}.${index}`))) }), jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(react.Button, { onClick: () => {
3669
4112
  if (type === "number") {
3670
4113
  setValue(colLabel, [...fields, 0]);
3671
4114
  return;
@@ -3679,48 +4122,49 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3679
4122
  return;
3680
4123
  }
3681
4124
  setValue(colLabel, [...fields, {}]);
3682
- }, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4125
+ }, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
3683
4126
  };
3684
4127
 
3685
4128
  const Field = React__namespace.forwardRef(function Field(props, ref) {
3686
4129
  const { label, children, helperText, errorText, optionalText, ...rest } = props;
3687
- return (jsxRuntime.jsxs(react.Field.Root, { ref: ref, ...rest, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, jsxRuntime.jsx(react.Field.RequiredIndicator, { fallback: optionalText })] })), children, helperText && (jsxRuntime.jsx(react.Field.HelperText, { children: helperText })), errorText && (jsxRuntime.jsx(react.Field.ErrorText, { children: errorText }))] }));
4130
+ return (jsxRuntime.jsxs(react.Field.Root, { ref: ref, ...rest, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, jsxRuntime.jsx(react.Field.RequiredIndicator, { color: rest.invalid && rest.required ? 'red.500' : undefined, fallback: optionalText })] })), children, helperText && (jsxRuntime.jsx(react.Field.HelperText, { children: helperText })), !!errorText && (jsxRuntime.jsxs(react.Field.ErrorText, { children: [rest.required && rest.invalid && (jsxRuntime.jsx("span", { style: { color: 'var(--chakra-colors-red-500)' }, children: "* " })), errorText] }))] }));
3688
4131
  });
3689
4132
 
3690
4133
  const BooleanPicker = ({ schema, column, prefix }) => {
3691
4134
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
3692
4135
  const { translate } = useSchemaContext();
3693
- const { required, gridColumn, gridRow } = schema;
4136
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
3694
4137
  const isRequired = required?.some((columnId) => columnId === column);
3695
4138
  const colLabel = `${prefix}${column}`;
3696
4139
  const value = watch(colLabel);
3697
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3698
- gridRow, children: [jsxRuntime.jsx(CheckboxCard, { checked: value, variant: "surface", onChange: () => {
3699
- setValue(colLabel, !value);
3700
- } }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4140
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
4141
+ gridRow, errorText: errors[`${colLabel}`]
4142
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
4143
+ : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
4144
+ setValue(colLabel, !value);
4145
+ } }) }));
4146
+ };
4147
+
4148
+ const CustomInput = ({ column, schema, prefix }) => {
4149
+ const formContext = reactHookForm.useFormContext();
4150
+ const { inputRender } = schema;
4151
+ return (inputRender &&
4152
+ inputRender({
4153
+ column,
4154
+ schema,
4155
+ prefix,
4156
+ formContext,
4157
+ }));
3701
4158
  };
3702
4159
 
3703
- const monthNamesShort = [
3704
- "Jan",
3705
- "Feb",
3706
- "Mar",
3707
- "Apr",
3708
- "May",
3709
- "Jun",
3710
- "Jul",
3711
- "Aug",
3712
- "Sep",
3713
- "Oct",
3714
- "Nov",
3715
- "Dec",
3716
- ];
3717
- const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
3718
4160
  const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
4161
+ const { labels } = React.useContext(DatePickerContext);
4162
+ const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
3719
4163
  if (calendars.length) {
3720
4164
  return (jsxRuntime.jsxs(react.Grid, { children: [jsxRuntime.jsxs(react.Grid, { templateColumns: "repeat(4, auto)", justifyContent: "center", children: [jsxRuntime.jsx(react.Button, { variant: "ghost", ...getBackProps({
3721
4165
  calendars,
3722
4166
  offset: 12,
3723
- }), children: "<<" }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getBackProps({ calendars }), children: "Back" }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getForwardProps({ calendars }), children: "Next" }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getForwardProps({
4167
+ }), children: "<<" }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getBackProps({ calendars }), children: backButtonLabel }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getForwardProps({ calendars }), children: forwardButtonLabel }), jsxRuntime.jsx(react.Button, { variant: "ghost", ...getForwardProps({
3724
4168
  calendars,
3725
4169
  offset: 12,
3726
4170
  }), children: ">>" })] }), jsxRuntime.jsx(react.Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", children: calendars.map((calendar) => (jsxRuntime.jsxs(react.Grid, { gap: 4, children: [jsxRuntime.jsxs(react.Grid, { justifyContent: "center", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxRuntime.jsxs(react.Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [[0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
@@ -3763,9 +4207,52 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
3763
4207
  }
3764
4208
  return null;
3765
4209
  };
4210
+ const DatePickerContext = React.createContext({
4211
+ labels: {
4212
+ monthNamesShort: [
4213
+ "Jan",
4214
+ "Feb",
4215
+ "Mar",
4216
+ "Apr",
4217
+ "May",
4218
+ "Jun",
4219
+ "Jul",
4220
+ "Aug",
4221
+ "Sep",
4222
+ "Oct",
4223
+ "Nov",
4224
+ "Dec",
4225
+ ],
4226
+ weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
4227
+ backButtonLabel: "Back",
4228
+ forwardButtonLabel: "Next",
4229
+ },
4230
+ });
3766
4231
  let DatePicker$1 = class DatePicker extends React.Component {
3767
4232
  render() {
3768
- return (jsxRuntime.jsx(Dayzed, { onDateSelected: this.props.onDateSelected, selected: this.props.selected, firstDayOfWeek: this.props.firstDayOfWeek, showOutsideDays: this.props.showOutsideDays, date: this.props.date, minDate: this.props.minDate, maxDate: this.props.maxDate, monthsToDisplay: this.props.monthsToDisplay, render: (dayzedData) => (jsxRuntime.jsx(Calendar, { ...dayzedData, firstDayOfWeek: this.props.firstDayOfWeek })) }));
4233
+ const { labels = {
4234
+ monthNamesShort: [
4235
+ "Jan",
4236
+ "Feb",
4237
+ "Mar",
4238
+ "Apr",
4239
+ "May",
4240
+ "Jun",
4241
+ "Jul",
4242
+ "Aug",
4243
+ "Sep",
4244
+ "Oct",
4245
+ "Nov",
4246
+ "Dec",
4247
+ ],
4248
+ weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
4249
+ backButtonLabel: "Back",
4250
+ forwardButtonLabel: "Next",
4251
+ }, } = this.props;
4252
+ return (jsxRuntime.jsx(DatePickerContext.Provider, { value: { labels }, children: jsxRuntime.jsx(Dayzed, { onDateSelected: this.props.onDateSelected, selected: this.props.selected, firstDayOfWeek: this.props.firstDayOfWeek, showOutsideDays: this.props.showOutsideDays, date: this.props.date, minDate: this.props.minDate, maxDate: this.props.maxDate, monthsToDisplay: this.props.monthsToDisplay, render:
4253
+ // @ts-expect-error - Dayzed types need to be fixed
4254
+ (dayzedData) => (jsxRuntime.jsx(Calendar, { ...dayzedData,
4255
+ firstDayOfWeek: this.props.firstDayOfWeek })) }) }));
3769
4256
  }
3770
4257
  };
3771
4258
 
@@ -3787,28 +4274,270 @@ const PopoverRoot = react.Popover.Root;
3787
4274
  const PopoverBody = react.Popover.Body;
3788
4275
  const PopoverTrigger = react.Popover.Trigger;
3789
4276
 
4277
+ /**
4278
+ * Custom hook to simplify i18n translation for form fields.
4279
+ * Automatically handles colLabel construction and removeIndex logic.
4280
+ *
4281
+ * @param column - The column name
4282
+ * @param prefix - The prefix for the field (usually empty string or parent path)
4283
+ * @returns Object with translation helper functions
4284
+ *
4285
+ * @example
4286
+ * ```tsx
4287
+ * const formI18n = useFormI18n(column, prefix);
4288
+ *
4289
+ * // Get field label
4290
+ * <Field label={formI18n.label()} />
4291
+ *
4292
+ * // Get error message
4293
+ * <Text>{formI18n.required()}</Text>
4294
+ *
4295
+ * // Get custom translation key
4296
+ * <Text>{formI18n.t('add_more')}</Text>
4297
+ *
4298
+ * // Access the raw colLabel
4299
+ * const colLabel = formI18n.colLabel;
4300
+ * ```
4301
+ */
4302
+ const useFormI18n = (column, prefix = "") => {
4303
+ const { translate } = useSchemaContext();
4304
+ const colLabel = `${prefix}${column}`;
4305
+ return {
4306
+ /**
4307
+ * The constructed column label (prefix + column)
4308
+ */
4309
+ colLabel,
4310
+ /**
4311
+ * Get the field label translation
4312
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.field_label`))
4313
+ */
4314
+ label: (options) => {
4315
+ return translate.t(removeIndex(`${colLabel}.field_label`), options);
4316
+ },
4317
+ /**
4318
+ * Get the required error message translation
4319
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
4320
+ */
4321
+ required: (options) => {
4322
+ return translate.t(removeIndex(`${colLabel}.field_required`), options);
4323
+ },
4324
+ /**
4325
+ * Get a translation for any custom key relative to the field
4326
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
4327
+ *
4328
+ * @param key - The translation key suffix (e.g., 'add_more', 'total', etc.)
4329
+ * @param options - Optional translation options (e.g., defaultValue, interpolation variables)
4330
+ */
4331
+ t: (key, options) => {
4332
+ return translate.t(removeIndex(`${colLabel}.${key}`), options);
4333
+ },
4334
+ /**
4335
+ * Access to the original translate object for edge cases
4336
+ */
4337
+ translate,
4338
+ };
4339
+ };
4340
+
4341
+ dayjs.extend(utc);
4342
+ dayjs.extend(timezone);
3790
4343
  const DatePicker = ({ column, schema, prefix }) => {
3791
4344
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
3792
- const { translate } = useSchemaContext();
3793
- const { required, gridColumn, gridRow } = schema;
4345
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
4346
+ const formI18n = useFormI18n(column, prefix);
4347
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
3794
4348
  const isRequired = required?.some((columnId) => columnId === column);
3795
- const colLabel = `${prefix}${column}`;
4349
+ const colLabel = formI18n.colLabel;
3796
4350
  const [open, setOpen] = React.useState(false);
3797
4351
  const selectedDate = watch(colLabel);
3798
- const formatedDate = dayjs(selectedDate).format("YYYY-MM-DD");
3799
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3800
- gridRow, children: [jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsx(Button, { size: "sm", variant: "outline", onClick: () => {
3801
- setOpen(true);
3802
- }, children: selectedDate !== undefined ? `${formatedDate}` : "" }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1
3803
- // @ts-expect-error TODO: find appropriate types
3804
- , {
3805
- // @ts-expect-error TODO: find appropriate types
3806
- selected: new Date(selectedDate),
3807
- // @ts-expect-error TODO: find appropriate types
3808
- onDateSelected: ({ date }) => {
3809
- setValue(colLabel, dayjs(date).format("YYYY-MM-DD"));
3810
- setOpen(false);
3811
- } })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4352
+ const displayDate = dayjs(selectedDate)
4353
+ .tz(timezone)
4354
+ .format(displayDateFormat);
4355
+ React.useEffect(() => {
4356
+ try {
4357
+ if (selectedDate) {
4358
+ // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
4359
+ // For example, parse as UTC:
4360
+ const parsedDate = dayjs(selectedDate).tz(timezone);
4361
+ if (!parsedDate.isValid())
4362
+ return;
4363
+ // Format according to dateFormat from schema
4364
+ const formatted = parsedDate.format(dateFormat);
4365
+ // Update the form value only if different to avoid loops
4366
+ if (formatted !== selectedDate) {
4367
+ setValue(colLabel, formatted, {
4368
+ shouldValidate: true,
4369
+ shouldDirty: true,
4370
+ });
4371
+ }
4372
+ }
4373
+ }
4374
+ catch (e) {
4375
+ console.error(e);
4376
+ }
4377
+ }, [selectedDate, dateFormat, colLabel, setValue]);
4378
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4379
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4380
+ setOpen(true);
4381
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4382
+ setValue(colLabel, dayjs(date).format(dateFormat));
4383
+ setOpen(false);
4384
+ }, labels: {
4385
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4386
+ formI18n.translate.t(`common.month_1`, {
4387
+ defaultValue: 'January',
4388
+ }),
4389
+ formI18n.translate.t(`common.month_2`, {
4390
+ defaultValue: 'February',
4391
+ }),
4392
+ formI18n.translate.t(`common.month_3`, {
4393
+ defaultValue: 'March',
4394
+ }),
4395
+ formI18n.translate.t(`common.month_4`, {
4396
+ defaultValue: 'April',
4397
+ }),
4398
+ formI18n.translate.t(`common.month_5`, {
4399
+ defaultValue: 'May',
4400
+ }),
4401
+ formI18n.translate.t(`common.month_6`, {
4402
+ defaultValue: 'June',
4403
+ }),
4404
+ formI18n.translate.t(`common.month_7`, {
4405
+ defaultValue: 'July',
4406
+ }),
4407
+ formI18n.translate.t(`common.month_8`, {
4408
+ defaultValue: 'August',
4409
+ }),
4410
+ formI18n.translate.t(`common.month_9`, {
4411
+ defaultValue: 'September',
4412
+ }),
4413
+ formI18n.translate.t(`common.month_10`, {
4414
+ defaultValue: 'October',
4415
+ }),
4416
+ formI18n.translate.t(`common.month_11`, {
4417
+ defaultValue: 'November',
4418
+ }),
4419
+ formI18n.translate.t(`common.month_12`, {
4420
+ defaultValue: 'December',
4421
+ }),
4422
+ ],
4423
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
4424
+ formI18n.translate.t(`common.weekday_1`, {
4425
+ defaultValue: 'Sun',
4426
+ }),
4427
+ formI18n.translate.t(`common.weekday_2`, {
4428
+ defaultValue: 'Mon',
4429
+ }),
4430
+ formI18n.translate.t(`common.weekday_3`, {
4431
+ defaultValue: 'Tue',
4432
+ }),
4433
+ formI18n.translate.t(`common.weekday_4`, {
4434
+ defaultValue: 'Wed',
4435
+ }),
4436
+ formI18n.translate.t(`common.weekday_5`, {
4437
+ defaultValue: 'Thu',
4438
+ }),
4439
+ formI18n.translate.t(`common.weekday_6`, {
4440
+ defaultValue: 'Fri',
4441
+ }),
4442
+ formI18n.translate.t(`common.weekday_7`, {
4443
+ defaultValue: 'Sat',
4444
+ }),
4445
+ ],
4446
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
4447
+ formI18n.translate.t(`common.back_button`, {
4448
+ defaultValue: 'Back',
4449
+ }),
4450
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
4451
+ formI18n.translate.t(`common.forward_button`, {
4452
+ defaultValue: 'Forward',
4453
+ }),
4454
+ } })] }) })] }) }));
4455
+ };
4456
+
4457
+ dayjs.extend(utc);
4458
+ dayjs.extend(timezone);
4459
+ const DateRangePicker = ({ column, schema, prefix, }) => {
4460
+ const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4461
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
4462
+ const formI18n = useFormI18n(column, prefix);
4463
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4464
+ const isRequired = required?.some((columnId) => columnId === column);
4465
+ const colLabel = formI18n.colLabel;
4466
+ const [open, setOpen] = React.useState(false);
4467
+ const selectedDateRange = watch(colLabel);
4468
+ // Convert string[] to Date[] for the picker
4469
+ const selectedDates = (selectedDateRange ?? [])
4470
+ .map((dateStr) => {
4471
+ if (!dateStr)
4472
+ return null;
4473
+ const parsed = dayjs(dateStr).tz(timezone);
4474
+ return parsed.isValid() ? parsed.toDate() : null;
4475
+ })
4476
+ .filter((date) => date !== null);
4477
+ // Format display string
4478
+ const getDisplayText = () => {
4479
+ if (!selectedDateRange || selectedDateRange.length === 0) {
4480
+ return '';
4481
+ }
4482
+ if (selectedDateRange.length === 1) {
4483
+ const date = dayjs(selectedDateRange[0]).tz(timezone);
4484
+ return date.isValid() ? date.format(displayDateFormat) : '';
4485
+ }
4486
+ if (selectedDateRange.length === 2) {
4487
+ const startDate = dayjs(selectedDateRange[0]).tz(timezone);
4488
+ const endDate = dayjs(selectedDateRange[1]).tz(timezone);
4489
+ if (startDate.isValid() && endDate.isValid()) {
4490
+ return `${startDate.format(displayDateFormat)} - ${endDate.format(displayDateFormat)}`;
4491
+ }
4492
+ }
4493
+ return '';
4494
+ };
4495
+ React.useEffect(() => {
4496
+ try {
4497
+ if (selectedDateRange && selectedDateRange.length > 0) {
4498
+ // Format dates according to dateFormat from schema
4499
+ const formatted = selectedDateRange
4500
+ .map((dateStr) => {
4501
+ if (!dateStr)
4502
+ return null;
4503
+ const parsed = dayjs(dateStr).tz(timezone);
4504
+ return parsed.isValid() ? parsed.format(dateFormat) : null;
4505
+ })
4506
+ .filter((date) => date !== null);
4507
+ // Update the form value only if different to avoid loops
4508
+ // Compare arrays element by element
4509
+ const needsUpdate = formatted.length !== selectedDateRange.length ||
4510
+ formatted.some((val, idx) => val !== selectedDateRange[idx]);
4511
+ if (needsUpdate && formatted.length > 0) {
4512
+ setValue(colLabel, formatted, {
4513
+ shouldValidate: true,
4514
+ shouldDirty: true,
4515
+ });
4516
+ }
4517
+ }
4518
+ }
4519
+ catch (e) {
4520
+ console.error(e);
4521
+ }
4522
+ }, [selectedDateRange, dateFormat, colLabel, setValue, timezone]);
4523
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4524
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4525
+ setOpen(true);
4526
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), getDisplayText()] }) }), jsxRuntime.jsx(PopoverContent, { minW: '600px', children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(RangeDatePicker, { selected: selectedDates, onDateSelected: ({ selected, selectable, date }) => {
4527
+ const newDates = getRangeDates({
4528
+ selectable,
4529
+ date,
4530
+ selectedDates,
4531
+ }) ?? [];
4532
+ // Convert Date[] to string[]
4533
+ const formattedDates = newDates
4534
+ .map((dateObj) => dayjs(dateObj).tz(timezone).format(dateFormat))
4535
+ .filter((dateStr) => dateStr);
4536
+ setValue(colLabel, formattedDates, {
4537
+ shouldValidate: true,
4538
+ shouldDirty: true,
4539
+ });
4540
+ }, monthsToDisplay: 2 })] }) })] }) }));
3812
4541
  };
3813
4542
 
3814
4543
  function filterArray(array, searchTerm) {
@@ -3821,17 +4550,18 @@ function filterArray(array, searchTerm) {
3821
4550
  });
3822
4551
  }
3823
4552
 
3824
- const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
4553
+ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
3825
4554
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
3826
- const { translate } = useSchemaContext();
3827
- const { required } = schema;
4555
+ const { enumPickerLabels } = useSchemaContext();
4556
+ const formI18n = useFormI18n(column, prefix);
4557
+ const { required, variant } = schema;
3828
4558
  const isRequired = required?.some((columnId) => columnId === column);
3829
- const { gridColumn, gridRow, renderDisplay } = schema;
4559
+ const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
3830
4560
  const [searchText, setSearchText] = React.useState();
3831
4561
  const [limit, setLimit] = React.useState(10);
3832
4562
  const [openSearchResult, setOpenSearchResult] = React.useState();
3833
4563
  const ref = React.useRef(null);
3834
- const colLabel = `${prefix}${column}`;
4564
+ const colLabel = formI18n.colLabel;
3835
4565
  const watchEnum = watch(colLabel);
3836
4566
  const watchEnums = (watch(colLabel) ?? []);
3837
4567
  const dataList = schema.enum ?? [];
@@ -3841,32 +4571,63 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
3841
4571
  setSearchText(event.target.value);
3842
4572
  setLimit(10);
3843
4573
  };
3844
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3845
- gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
4574
+ if (variant === 'radio') {
4575
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4576
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(react.RadioGroup.Root, { defaultValue: "1", children: jsxRuntime.jsx(react.HStack, { gap: "6", children: filterArray(dataList, searchText ?? '').map((item) => {
4577
+ return (jsxRuntime.jsxs(react.RadioGroup.Item, { onClick: () => {
4578
+ if (!isMultiple) {
4579
+ setOpenSearchResult(false);
4580
+ setValue(colLabel, item);
4581
+ return;
4582
+ }
4583
+ const newSet = new Set([...(watchEnums ?? []), item]);
4584
+ setValue(colLabel, [...newSet]);
4585
+ }, value: item, children: [jsxRuntime.jsx(react.RadioGroup.ItemHiddenInput, {}), jsxRuntime.jsx(react.RadioGroup.ItemIndicator, {}), jsxRuntime.jsx(react.RadioGroup.ItemText, { children: !!renderDisplay === true
4586
+ ? renderDisplay(item)
4587
+ : formI18n.t(item) })] }, `${colLabel}-${item}`));
4588
+ }) }) }) }));
4589
+ }
4590
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4591
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchEnums.map((enumValue) => {
3846
4592
  const item = enumValue;
3847
- if (item === undefined) {
3848
- return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "undefined" });
4593
+ if (!!item === false) {
4594
+ return jsxRuntime.jsx(jsxRuntime.Fragment, {});
3849
4595
  }
3850
- return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
3851
- // setSelectedEnums((state) => state.filter((id) => id != item));
4596
+ return (jsxRuntime.jsx(Tag, { size: "lg", closable: true, onClick: () => {
3852
4597
  setValue(column, watchEnums.filter((id) => id != item));
3853
4598
  }, children: !!renderDisplay === true
3854
4599
  ? renderDisplay(item)
3855
- : translate.t(removeIndex(`${colLabel}.${item}`)) }));
3856
- }), jsxRuntime.jsx(Tag, { cursor: "pointer", onClick: () => {
4600
+ : formI18n.t(item) }, item));
4601
+ }), jsxRuntime.jsx(Tag, { size: "lg", cursor: 'pointer', onClick: () => {
3857
4602
  setOpenSearchResult(true);
3858
- }, children: translate.t(removeIndex(`${colLabel}.addMore`)) })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: "outline", onClick: () => {
4603
+ }, children: enumPickerLabels?.addMore ?? formI18n.t('add_more') }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: 'outline', onClick: () => {
3859
4604
  setOpenSearchResult(true);
3860
- }, children: watchEnum === undefined
3861
- ? ""
3862
- : translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: translate.t(`${column}.typeToSearch`), onChange: (event) => {
4605
+ }, justifyContent: 'start', children: !!watchEnum === false ? '' : formI18n.t(watchEnum ?? 'null') })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: 'bottom-start' }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { portalled: false, children: jsxRuntime.jsxs(PopoverBody, { display: 'grid', gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: enumPickerLabels?.typeToSearch ?? formI18n.t('type_to_search'), onChange: (event) => {
3863
4606
  onSearchChange(event);
3864
4607
  setOpenSearchResult(true);
3865
- }, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(react.Text, { children: `${translate.t(`${column}.total`)}: ${count}, ${translate.t(`${column}.showing`)} ${limit}` }), jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", children: filterArray(dataList, searchText ?? "").map((item) => {
4608
+ }, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), showTotalAndLimit && (jsxRuntime.jsx(react.Text, { children: `${enumPickerLabels?.total ?? formI18n.t('total')}: ${count}, ${enumPickerLabels?.showing ?? formI18n.t('showing')} ${limit}` })), jsxRuntime.jsxs(react.Grid, { overflow: 'auto', maxHeight: '20rem', children: [jsxRuntime.jsx(react.Flex, { flexFlow: 'column wrap', children: dataList
4609
+ .filter((item) => {
4610
+ const searchTerm = (searchText || '').toLowerCase();
4611
+ if (!searchTerm)
4612
+ return true;
4613
+ // Check if the original enum value contains the search text
4614
+ const enumValueMatch = item
4615
+ .toLowerCase()
4616
+ .includes(searchTerm);
4617
+ // Check if the display value (translation) contains the search text
4618
+ const displayValue = !!renderDisplay === true
4619
+ ? renderDisplay(item)
4620
+ : formI18n.t(item);
4621
+ // Convert to string and check if it includes the search term
4622
+ const displayValueString = String(displayValue).toLowerCase();
4623
+ const displayValueMatch = displayValueString.includes(searchTerm);
4624
+ return enumValueMatch || displayValueMatch;
4625
+ })
4626
+ .map((item) => {
3866
4627
  const selected = isMultiple
3867
4628
  ? watchEnums.some((enumValue) => item === enumValue)
3868
4629
  : watchEnum == item;
3869
- return (jsxRuntime.jsx(react.Box, { cursor: "pointer", onClick: () => {
4630
+ return (jsxRuntime.jsx(react.Box, { cursor: 'pointer', onClick: () => {
3870
4631
  if (!isMultiple) {
3871
4632
  setOpenSearchResult(false);
3872
4633
  setValue(colLabel, item);
@@ -3874,10 +4635,11 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
3874
4635
  }
3875
4636
  const newSet = new Set([...(watchEnums ?? []), item]);
3876
4637
  setValue(colLabel, [...newSet]);
3877
- }, ...(selected ? { color: "gray.400/50" } : {}), children: !!renderDisplay === true
4638
+ }, ...(selected ? { color: 'colorPalette.400/50' } : {}), children: !!renderDisplay === true
3878
4639
  ? renderDisplay(item)
3879
- : translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
3880
- }) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: translate.t(removeIndex(`${colLabel}.emptySearchResult`)) })) }))] })] }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4640
+ : formI18n.t(item) }, `${colLabel}-${item}`));
4641
+ }) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: enumPickerLabels?.emptySearchResult ??
4642
+ formI18n.t('empty_search_result') })) }))] })] }) })] })] }));
3881
4643
  };
3882
4644
 
3883
4645
  function isEnteringWindow(_ref) {
@@ -4183,7 +4945,7 @@ function getText(_ref2) {
4183
4945
  return source.getStringData(textMediaType);
4184
4946
  }
4185
4947
 
4186
- const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }, placeholder = "Drop files here or click to upload", }) => {
4948
+ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }, placeholder = 'Drop files here or click to upload', }) => {
4187
4949
  const ref = React.useRef(null);
4188
4950
  const [isDraggedOver, setIsDraggedOver] = React.useState(false);
4189
4951
  React.useEffect(() => {
@@ -4197,7 +4959,7 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4197
4959
  onDrop: ({ source }) => {
4198
4960
  const files = getFiles({ source });
4199
4961
  const text = getText({ source });
4200
- console.log(files, text, "dfposa");
4962
+ console.log(files, text, 'dfposa');
4201
4963
  onDrop({ files, text });
4202
4964
  },
4203
4965
  });
@@ -4206,9 +4968,9 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4206
4968
  function getColor(isDraggedOver) {
4207
4969
  if (isDraggedOver) {
4208
4970
  return {
4209
- backgroundColor: "blue.400",
4971
+ backgroundColor: 'blue.400',
4210
4972
  _dark: {
4211
- backgroundColor: "blue.400",
4973
+ backgroundColor: 'blue.400',
4212
4974
  },
4213
4975
  };
4214
4976
  }
@@ -4229,28 +4991,223 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4229
4991
  const filesArray = [...event.target.files];
4230
4992
  onDrop({ files: filesArray });
4231
4993
  };
4232
- return (jsxRuntime.jsxs(react.Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "gray.400", alignContent: "center", justifyContent: "center", borderWidth: 1, borderRadius: 4, ...gridProps, children: [children, !!children === false && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Flex, { children: placeholder }), jsxRuntime.jsx(react.Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
4994
+ return (jsxRuntime.jsxs(react.Grid, { ...getColor(isDraggedOver), ref: ref, cursor: 'pointer', onClick: handleClick, borderStyle: 'dashed', borderColor: 'colorPalette.400', alignContent: 'center', justifyContent: 'center', borderWidth: 1, borderRadius: 4, minH: "120px", ...gridProps, children: [children, !!children === false && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Flex, { children: placeholder }), jsxRuntime.jsx(react.Input, { type: "file", multiple: true, style: { display: 'none' }, ref: fileInput, onChange: handleChange })] }))] }));
4233
4995
  };
4234
4996
 
4997
+ /**
4998
+ * Format bytes to human-readable string
4999
+ * @param bytes - The number of bytes to format
5000
+ * @returns Formatted string (e.g., "1.5 KB", "2.3 MB")
5001
+ */
5002
+ function formatBytes(bytes) {
5003
+ if (bytes === 0)
5004
+ return '0 Bytes';
5005
+ const k = 1024;
5006
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
5007
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
5008
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
5009
+ }
5010
+
5011
+ function FilePickerDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, labels, translate, colLabel, }) {
5012
+ const [searchTerm, setSearchTerm] = React.useState('');
5013
+ const [selectedFileId, setSelectedFileId] = React.useState('');
5014
+ const [failedImageIds, setFailedImageIds] = React.useState(new Set());
5015
+ const { data: filesData, isLoading, isError, } = reactQuery.useQuery({
5016
+ queryKey: ['file-picker-library', searchTerm],
5017
+ queryFn: async () => {
5018
+ if (!onFetchFiles)
5019
+ return { data: [] };
5020
+ const files = await onFetchFiles(searchTerm.trim() || '');
5021
+ return { data: files };
5022
+ },
5023
+ enabled: open && !!onFetchFiles,
5024
+ });
5025
+ const files = (filesData?.data || []);
5026
+ const filteredFiles = filterImageOnly
5027
+ ? files.filter((file) => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name))
5028
+ : files;
5029
+ const handleSelect = () => {
5030
+ if (selectedFileId) {
5031
+ onSelect(selectedFileId);
5032
+ onClose();
5033
+ setSelectedFileId('');
5034
+ setSearchTerm('');
5035
+ }
5036
+ };
5037
+ const handleClose = () => {
5038
+ onClose();
5039
+ setSelectedFileId('');
5040
+ setSearchTerm('');
5041
+ setFailedImageIds(new Set());
5042
+ };
5043
+ const handleImageError = (fileId) => {
5044
+ setFailedImageIds((prev) => new Set(prev).add(fileId));
5045
+ };
5046
+ if (!onFetchFiles)
5047
+ return null;
5048
+ return (jsxRuntime.jsx(DialogRoot, { open: open, onOpenChange: (e) => !e.open && handleClose(), children: jsxRuntime.jsxs(DialogContent, { maxWidth: "800px", maxHeight: "90vh", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { fontSize: "lg", fontWeight: "bold", children: title }), jsxRuntime.jsx(DialogCloseTrigger, {})] }), jsxRuntime.jsx(DialogBody, { children: jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 4, children: [jsxRuntime.jsxs(react.Box, { position: "relative", children: [jsxRuntime.jsx(react.Input, { placeholder: labels?.searchPlaceholder ??
5049
+ translate(removeIndex(`${colLabel}.search_placeholder`)) ??
5050
+ 'Search files...', value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), bg: "bg.panel", border: "1px solid", borderColor: "border.default", colorPalette: "blue", _focus: {
5051
+ borderColor: 'colorPalette.500',
5052
+ _dark: {
5053
+ borderColor: 'colorPalette.400',
5054
+ },
5055
+ boxShadow: {
5056
+ base: '0 0 0 1px var(--chakra-colors-blue-500)',
5057
+ _dark: '0 0 0 1px var(--chakra-colors-blue-400)',
5058
+ },
5059
+ }, pl: 10 }), jsxRuntime.jsx(react.Icon, { as: lu.LuSearch, position: "absolute", left: 3, top: "50%", transform: "translateY(-50%)", color: "fg.muted", boxSize: 4 })] }), isLoading && (jsxRuntime.jsxs(react.Box, { textAlign: "center", py: 8, children: [jsxRuntime.jsx(react.Spinner, { size: "lg", colorPalette: "blue" }), jsxRuntime.jsx(react.Text, { mt: 4, color: "fg.muted", children: labels?.loading ??
5060
+ translate(removeIndex(`${colLabel}.loading`)) ??
5061
+ 'Loading files...' })] })), isError && (jsxRuntime.jsx(react.Box, { bg: { base: 'colorPalette.50', _dark: 'colorPalette.900/20' }, border: "1px solid", borderColor: {
5062
+ base: 'colorPalette.200',
5063
+ _dark: 'colorPalette.800',
5064
+ }, colorPalette: "red", borderRadius: "md", p: 4, children: jsxRuntime.jsx(react.Text, { color: {
5065
+ base: 'colorPalette.600',
5066
+ _dark: 'colorPalette.300',
5067
+ }, children: labels?.loadingFailed ??
5068
+ translate(removeIndex(`${colLabel}.error.loading_failed`)) ??
5069
+ 'Failed to load files' }) })), !isLoading && !isError && (jsxRuntime.jsx(react.Box, { maxHeight: "400px", overflowY: "auto", children: filteredFiles.length === 0 ? (jsxRuntime.jsx(react.Box, { textAlign: "center", py: 8, children: jsxRuntime.jsx(react.Text, { color: "fg.muted", children: labels?.noFilesFound ??
5070
+ translate(removeIndex(`${colLabel}.no_files_found`)) ??
5071
+ 'No files found' }) })) : (jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: filteredFiles.map((file) => {
5072
+ const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name);
5073
+ const isSelected = selectedFileId === file.id;
5074
+ const imageFailed = failedImageIds.has(file.id);
5075
+ return (jsxRuntime.jsx(react.Box, { p: 3, border: "2px solid", borderColor: isSelected
5076
+ ? {
5077
+ base: 'colorPalette.500',
5078
+ _dark: 'colorPalette.400',
5079
+ }
5080
+ : 'border.default', borderRadius: "md", bg: isSelected
5081
+ ? {
5082
+ base: 'colorPalette.50',
5083
+ _dark: 'colorPalette.900/20',
5084
+ }
5085
+ : 'bg.panel', colorPalette: "blue", cursor: "pointer", onClick: () => setSelectedFileId(file.id), _hover: {
5086
+ borderColor: isSelected
5087
+ ? {
5088
+ base: 'colorPalette.600',
5089
+ _dark: 'colorPalette.400',
5090
+ }
5091
+ : {
5092
+ base: 'colorPalette.300',
5093
+ _dark: 'colorPalette.400',
5094
+ },
5095
+ bg: isSelected
5096
+ ? {
5097
+ base: 'colorPalette.100',
5098
+ _dark: 'colorPalette.800/30',
5099
+ }
5100
+ : 'bg.muted',
5101
+ }, transition: "all 0.2s", children: jsxRuntime.jsxs(react.HStack, { gap: 3, children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, children: isImage && file.url && !imageFailed ? (jsxRuntime.jsx(react.Image, { src: file.url, alt: file.name, boxSize: "60px", objectFit: "cover", borderRadius: "md", onError: () => handleImageError(file.id) })) : isImage && (imageFailed || !file.url) ? (jsxRuntime.jsx(react.Icon, { as: lu.LuImage, boxSize: 6, color: "fg.muted" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.name }), jsxRuntime.jsxs(react.HStack, { gap: 2, children: [file.size && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: typeof file.size === 'number'
5102
+ ? formatBytes(file.size)
5103
+ : file.size }) })), file.comment && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [file.size && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: "\u2022" })), jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: file.comment })] }))] })] }), isSelected && (jsxRuntime.jsx(react.Box, { width: "24px", height: "24px", borderRadius: "full", bg: {
5104
+ base: 'colorPalette.500',
5105
+ _dark: 'colorPalette.400',
5106
+ }, colorPalette: "blue", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, children: jsxRuntime.jsx(react.Text, { color: "white", fontSize: "xs", fontWeight: "bold", children: "\u2713" }) }))] }) }, file.id));
5107
+ }) })) }))] }) }), jsxRuntime.jsx(DialogFooter, { children: jsxRuntime.jsxs(react.HStack, { gap: 3, justify: "end", children: [jsxRuntime.jsx(react.Button, { variant: "outline", onClick: handleClose, borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: labels?.cancel ??
5108
+ translate(removeIndex(`${colLabel}.cancel`)) ??
5109
+ 'Cancel' }), jsxRuntime.jsx(react.Button, { colorPalette: "blue", onClick: handleSelect, disabled: !selectedFileId, children: labels?.select ??
5110
+ translate(removeIndex(`${colLabel}.select`)) ??
5111
+ 'Select' })] }) })] }) }));
5112
+ }
4235
5113
  const FilePicker = ({ column, schema, prefix }) => {
4236
5114
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
4237
- const { translate } = useSchemaContext();
4238
- const { required, gridColumn, gridRow } = schema;
5115
+ const { filePickerLabels } = useSchemaContext();
5116
+ const formI18n = useFormI18n(column, prefix);
5117
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, } = schema;
4239
5118
  const isRequired = required?.some((columnId) => columnId === column);
4240
- const currentFiles = (watch(column) ?? []);
4241
- const colLabel = `${prefix}${column}`;
4242
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${colLabel}.fieldLabel`)}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
4243
- const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4244
- setValue(colLabel, [...currentFiles, ...newFiles]);
4245
- }, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
4246
- return (jsxRuntime.jsx(react.Card.Root, { variant: "subtle", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
4247
- setValue(column, currentFiles.filter(({ name }) => {
4248
- return name !== file.name;
4249
- }));
4250
- }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [jsxRuntime.jsx(react.Box, { children: file.name }), jsxRuntime.jsx(ti.TiDeleteOutline, {})] }) }, file.name));
4251
- }) }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5119
+ const currentValue = watch(column) ?? [];
5120
+ const currentFiles = Array.isArray(currentValue)
5121
+ ? currentValue
5122
+ : [];
5123
+ const colLabel = formI18n.colLabel;
5124
+ const [dialogOpen, setDialogOpen] = React.useState(false);
5125
+ const [failedImageIds, setFailedImageIds] = React.useState(new Set());
5126
+ const { onFetchFiles, enableMediaLibrary = false, filterImageOnly = false, } = filePicker || {};
5127
+ const showMediaLibrary = enableMediaLibrary && !!onFetchFiles;
5128
+ const handleImageError = (fileIdentifier) => {
5129
+ setFailedImageIds((prev) => new Set(prev).add(fileIdentifier));
5130
+ };
5131
+ const handleMediaLibrarySelect = (fileId) => {
5132
+ const newFiles = [...currentFiles, fileId];
5133
+ setValue(colLabel, newFiles);
5134
+ };
5135
+ const handleRemove = (index) => {
5136
+ const newFiles = currentFiles.filter((_, i) => i !== index);
5137
+ setValue(colLabel, newFiles);
5138
+ };
5139
+ const isFileObject = (value) => {
5140
+ return value instanceof File;
5141
+ };
5142
+ const getFileIdentifier = (file, index) => {
5143
+ if (isFileObject(file)) {
5144
+ return `${file.name}-${file.size}-${index}`;
5145
+ }
5146
+ return file;
5147
+ };
5148
+ const getFileName = (file) => {
5149
+ if (isFileObject(file)) {
5150
+ return file.name;
5151
+ }
5152
+ return typeof file === 'string' ? file : 'Unknown file';
5153
+ };
5154
+ const getFileSize = (file) => {
5155
+ if (isFileObject(file)) {
5156
+ return file.size;
5157
+ }
5158
+ return undefined;
5159
+ };
5160
+ const isImageFile = (file) => {
5161
+ if (isFileObject(file)) {
5162
+ return file.type.startsWith('image/');
5163
+ }
5164
+ if (typeof file === 'string') {
5165
+ return /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file);
5166
+ }
5167
+ return false;
5168
+ };
5169
+ const getImageUrl = (file) => {
5170
+ if (isFileObject(file)) {
5171
+ return URL.createObjectURL(file);
5172
+ }
5173
+ return undefined;
5174
+ };
5175
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5176
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsxs(react.VStack, { align: "stretch", gap: 2, children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
5177
+ const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => {
5178
+ if (isFileObject(cur)) {
5179
+ return cur.name === name;
5180
+ }
5181
+ return false;
5182
+ }));
5183
+ setValue(colLabel, [...currentFiles, ...newFiles]);
5184
+ }, placeholder: filePickerLabels?.fileDropzone ?? formI18n.t('fileDropzone') }), showMediaLibrary && (jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
5185
+ formI18n.t('browse_library') ??
5186
+ 'Browse from Library' }))] }), showMediaLibrary && (jsxRuntime.jsx(FilePickerDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
5187
+ formI18n.t('dialog_title') ??
5188
+ 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, labels: filePickerLabels, translate: formI18n.t, colLabel: colLabel })), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file, index) => {
5189
+ const fileIdentifier = getFileIdentifier(file, index);
5190
+ const fileName = getFileName(file);
5191
+ const fileSize = getFileSize(file);
5192
+ const isImage = isImageFile(file);
5193
+ const imageUrl = getImageUrl(file);
5194
+ const imageFailed = failedImageIds.has(fileIdentifier);
5195
+ return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', colorPalette: "blue", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: 'pointer', onClick: () => handleRemove(index), display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', border: "2px solid", borderColor: "border.default", borderRadius: "md", _hover: {
5196
+ borderColor: 'colorPalette.300',
5197
+ bg: 'bg.muted',
5198
+ }, transition: "all 0.2s", children: [jsxRuntime.jsx(react.Box, { width: "60px", height: "60px", display: "flex", alignItems: "center", justifyContent: "center", bg: "bg.muted", borderRadius: "md", flexShrink: 0, marginRight: "2", children: isImage && imageUrl && !imageFailed ? (jsxRuntime.jsx(react.Image, { src: imageUrl, alt: fileName, boxSize: "60px", objectFit: "cover", borderRadius: "md", onError: () => handleImageError(fileIdentifier) })) : isImage && (imageFailed || !imageUrl) ? (jsxRuntime.jsx(react.Icon, { as: lu.LuImage, boxSize: 6, color: "fg.muted" })) : (jsxRuntime.jsx(react.Icon, { as: lu.LuFile, boxSize: 6, color: "fg.muted" })) }), jsxRuntime.jsxs(react.VStack, { align: "start", flex: 1, gap: 1, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", fontWeight: "medium", color: "fg.default", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: fileName }), fileSize !== undefined && (jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: formatBytes(fileSize) }))] }), jsxRuntime.jsx(react.Icon, { as: ti.TiDeleteOutline, boxSize: 5, color: "fg.muted" })] }) }, fileIdentifier));
5199
+ }) })] }));
4252
5200
  };
4253
5201
 
5202
+ const ToggleTip = React__namespace.forwardRef(function ToggleTip(props, ref) {
5203
+ const { showArrow, children, portalled = true, content, portalRef, ...rest } = props;
5204
+ return (jsxRuntime.jsxs(react.Popover.Root, { ...rest, positioning: { ...rest.positioning, gutter: 4 }, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: children }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, container: portalRef, children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsxs(react.Popover.Content, { width: "auto", px: "2", py: "1", textStyle: "xs", rounded: "sm", ref: ref, children: [showArrow && (jsxRuntime.jsx(react.Popover.Arrow, { children: jsxRuntime.jsx(react.Popover.ArrowTip, {}) })), content] }) }) })] }));
5205
+ });
5206
+ const InfoTip = React__namespace.forwardRef(function InfoTip(props, ref) {
5207
+ const { children, ...rest } = props;
5208
+ return (jsxRuntime.jsx(ToggleTip, { content: children, ...rest, ref: ref, children: jsxRuntime.jsx(react.IconButton, { variant: "ghost", "aria-label": "info", size: "2xs", colorPalette: "colorPalette", children: jsxRuntime.jsx(hi.HiOutlineInformationCircle, {}) }) }));
5209
+ });
5210
+
4254
5211
  const getTableData = async ({ serverUrl, in_table, searching = "", where = [], limit = 10, offset = 0, }) => {
4255
5212
  if (serverUrl === undefined || serverUrl.length == 0) {
4256
5213
  throw new Error("The serverUrl is missing");
@@ -4281,25 +5238,40 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
4281
5238
 
4282
5239
  const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4283
5240
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4284
- const { serverUrl, idMap, setIdMap, translate, schema: parentSchema, } = useSchemaContext();
4285
- const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
5241
+ const { serverUrl, idMap, setIdMap, schema: parentSchema, idPickerLabels, } = useSchemaContext();
5242
+ const formI18n = useFormI18n(column, prefix);
5243
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
4286
5244
  const isRequired = required?.some((columnId) => columnId === column);
4287
- const { table, column: column_ref, display_column, } = foreign_key;
4288
- const [searchText, setSearchText] = React.useState();
5245
+ const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
5246
+ const [searchText, setSearchText] = React.useState('');
4289
5247
  const [limit, setLimit] = React.useState(10);
4290
5248
  const [openSearchResult, setOpenSearchResult] = React.useState();
4291
5249
  const [page, setPage] = React.useState(0);
4292
5250
  const ref = React.useRef(null);
4293
- const colLabel = `${prefix}${column}`;
5251
+ const colLabel = formI18n.colLabel;
5252
+ const watchId = watch(colLabel);
5253
+ const watchIds = isMultiple ? (watch(colLabel) ?? []) : [];
5254
+ // Query for search results
4294
5255
  const query = reactQuery.useQuery({
4295
5256
  queryKey: [`idpicker`, { column, searchText, limit, page }],
4296
5257
  queryFn: async () => {
5258
+ if (customQueryFn) {
5259
+ const { data, idMap } = await customQueryFn({
5260
+ searching: searchText ?? '',
5261
+ limit: limit,
5262
+ offset: page * limit,
5263
+ });
5264
+ setIdMap((state) => {
5265
+ return { ...state, ...idMap };
5266
+ });
5267
+ return data;
5268
+ }
4297
5269
  const data = await getTableData({
4298
5270
  serverUrl,
4299
- searching: searchText ?? "",
5271
+ searching: searchText ?? '',
4300
5272
  in_table: table,
4301
5273
  limit: limit,
4302
- offset: page * 10,
5274
+ offset: page * limit,
4303
5275
  });
4304
5276
  const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
4305
5277
  return [
@@ -4314,27 +5286,38 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4314
5286
  });
4315
5287
  return data;
4316
5288
  },
4317
- enabled: (searchText ?? "")?.length > 0,
5289
+ enabled: openSearchResult === true,
4318
5290
  staleTime: 300000,
4319
5291
  });
4320
- const { isLoading, isFetching, data, isPending, isError } = query;
4321
- const dataList = data?.data ?? [];
4322
- const count = data?.count ?? 0;
4323
- const isDirty = (searchText?.length ?? 0) > 0;
4324
- const watchId = watch(colLabel);
4325
- const watchIds = (watch(colLabel) ?? []);
4326
- reactQuery.useQuery({
5292
+ // Query for currently selected items (to display them properly)
5293
+ const queryDefault = reactQuery.useQuery({
4327
5294
  queryKey: [
4328
- `idpicker`,
4329
- { form: parentSchema.title, column, searchText, limit, page },
5295
+ `idpicker-default`,
5296
+ { form: parentSchema.title, column, id: isMultiple ? watchIds : watchId },
4330
5297
  ],
4331
5298
  queryFn: async () => {
5299
+ if (customQueryFn) {
5300
+ const { data, idMap } = await customQueryFn({
5301
+ searching: watchIds.join(','),
5302
+ limit: isMultiple ? watchIds.length : 1,
5303
+ offset: 0,
5304
+ });
5305
+ setIdMap((state) => {
5306
+ return { ...state, ...idMap };
5307
+ });
5308
+ return data;
5309
+ }
5310
+ if (!watchId && (!watchIds || watchIds.length === 0)) {
5311
+ return { data: [] };
5312
+ }
5313
+ const searchValue = isMultiple ? watchIds.join(',') : watchId;
4332
5314
  const data = await getTableData({
4333
5315
  serverUrl,
4334
- searching: watchId,
5316
+ searching: searchValue,
4335
5317
  in_table: table,
4336
- limit: limit,
4337
- offset: page * 10,
5318
+ where: [{ id: column_ref, value: isMultiple ? watchIds : watchId }],
5319
+ limit: isMultiple ? watchIds.length : 1,
5320
+ offset: 0,
4338
5321
  });
4339
5322
  const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
4340
5323
  return [
@@ -4349,85 +5332,199 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4349
5332
  });
4350
5333
  return data;
4351
5334
  },
5335
+ enabled: isMultiple
5336
+ ? Array.isArray(watchIds) && watchIds.length > 0
5337
+ : !!watchId,
4352
5338
  });
5339
+ // Effect to load selected values when component mounts
5340
+ React.useEffect(() => {
5341
+ if (isMultiple ? watchIds.length > 0 : !!watchId) {
5342
+ queryDefault.refetch();
5343
+ }
5344
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5345
+ }, []);
5346
+ // Effect to trigger initial data fetch when popover opens
5347
+ React.useEffect(() => {
5348
+ if (openSearchResult) {
5349
+ // Reset search text when opening the popover
5350
+ setSearchText('');
5351
+ // Reset page to first page
5352
+ setPage(0);
5353
+ // Fetch initial data
5354
+ query.refetch();
5355
+ }
5356
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5357
+ }, [openSearchResult]);
4353
5358
  const onSearchChange = async (event) => {
4354
5359
  setSearchText(event.target.value);
4355
5360
  setPage(0);
4356
- setLimit(10);
5361
+ query.refetch();
5362
+ };
5363
+ const handleLimitChange = (event) => {
5364
+ const newLimit = Number(event.target.value);
5365
+ setLimit(newLimit);
5366
+ // Reset to first page when changing limit
5367
+ setPage(0);
5368
+ // Trigger a new search with the updated limit
5369
+ query.refetch();
4357
5370
  };
5371
+ const { isLoading, isFetching, data, isPending, isError } = query;
5372
+ const dataList = data?.data ?? [];
5373
+ const count = data?.count ?? 0;
4358
5374
  const getPickedValue = () => {
4359
5375
  if (Object.keys(idMap).length <= 0) {
4360
- return "";
5376
+ return '';
4361
5377
  }
4362
5378
  const record = idMap[watchId];
4363
5379
  if (record === undefined) {
4364
- return "";
5380
+ return '';
5381
+ }
5382
+ if (!!renderDisplay === true) {
5383
+ return renderDisplay(record);
4365
5384
  }
4366
5385
  return record[display_column];
4367
5386
  };
4368
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(removeIndex(`${column}.fieldLabel`)))}`, required: isRequired, alignItems: "stretch", gridColumn,
4369
- gridRow, children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: "wrap", gap: 1, children: [watchIds.map((id) => {
5387
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5388
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [isMultiple && (jsxRuntime.jsxs(react.Flex, { flexFlow: 'wrap', gap: 1, children: [watchIds.map((id) => {
4370
5389
  const item = idMap[id];
4371
5390
  if (item === undefined) {
4372
- return (jsxRuntime.jsx(react.Text, { children: translate.t(removeIndex(`${colLabel}.undefined`)) }, id));
5391
+ return (jsxRuntime.jsx(react.Text, { children: idPickerLabels?.undefined ?? formI18n.t('undefined') }, id));
4373
5392
  }
4374
5393
  return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
4375
- setValue(column, watchIds.filter((id) => id != item[column_ref]));
5394
+ setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
4376
5395
  }, children: !!renderDisplay === true
4377
5396
  ? renderDisplay(item)
4378
5397
  : item[display_column] }, id));
4379
- }), jsxRuntime.jsx(Tag, { cursor: "pointer", onClick: () => {
5398
+ }), jsxRuntime.jsx(Tag, { cursor: 'pointer', onClick: () => {
4380
5399
  setOpenSearchResult(true);
4381
- }, children: translate.t(removeIndex(`${colLabel}.addMore`)) })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: "outline", onClick: () => {
5400
+ }, children: idPickerLabels?.addMore ?? formI18n.t('add_more') })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: 'outline', onClick: () => {
4382
5401
  setOpenSearchResult(true);
4383
- }, children: getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: translate.t(removeIndex(`${colLabel}.typeToSearch`)), onChange: (event) => {
4384
- onSearchChange(event);
4385
- setOpenSearchResult(true);
4386
- }, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), (searchText?.length ?? 0) > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isFetching && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isFetching" }), isLoading && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isLoading" }), isPending && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isPending" }), (isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: "red.400", children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsx(react.Text, { justifySelf: "center", children: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` }), jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", children:
4387
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4388
- dataList.map((item) => {
4389
- const selected = isMultiple
4390
- ? watchIds.some((id) => item[column_ref] === id)
4391
- : watchId === item[column_ref];
4392
- return (jsxRuntime.jsx(react.Box, { cursor: "pointer", onClick: () => {
4393
- if (!isMultiple) {
4394
- setOpenSearchResult(false);
4395
- setValue(colLabel, item[column_ref]);
4396
- return;
4397
- }
4398
- const newSet = new Set([
4399
- ...(watchIds ?? []),
4400
- item[column_ref],
4401
- ]);
4402
- setValue(colLabel, [...newSet]);
4403
- }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected ? { color: "gray.400/50" } : {}), children: !!renderDisplay === true
4404
- ? renderDisplay(item)
4405
- : item[display_column] }, item[column_ref]));
4406
- }) }), isDirty && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: dataList.length <= 0 && (jsxRuntime.jsx(react.Text, { children: translate.t(removeIndex(`${colLabel}.emptySearchResult`)) })) }))] }), jsxRuntime.jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: 10, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5402
+ }, justifyContent: 'start', children: queryDefault.isLoading ? jsxRuntime.jsx(react.Spinner, { size: "sm" }) : getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: 'bottom-start', strategy: 'fixed' }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { portalled: false, children: jsxRuntime.jsxs(PopoverBody, { display: 'grid', gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: idPickerLabels?.typeToSearch ?? formI18n.t('type_to_search'), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsxRuntime.jsx(PopoverTitle, {}), openSearchResult && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: 'red.400', children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", children: [jsxRuntime.jsx(InfoTip, { children: `${idPickerLabels?.total ?? formI18n.t('total')} ${count}, ${idPickerLabels?.showing ?? formI18n.t('showing')} ${limit} ${idPickerLabels?.perPage ?? formI18n.t('per_page', { defaultValue: 'per page' })}` }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", ' ', count > 0
5403
+ ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}`
5404
+ : '0'] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
5405
+ padding: '4px 8px',
5406
+ borderRadius: '4px',
5407
+ border: '1px solid #ccc',
5408
+ fontSize: '14px',
5409
+ }, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "30", children: "30" })] }) })] }), jsxRuntime.jsx(react.Grid, { overflowY: 'auto', children: dataList.length > 0 ? (jsxRuntime.jsx(react.Flex, { flexFlow: 'column wrap', gap: 1, children: dataList.map((item) => {
5410
+ const selected = isMultiple
5411
+ ? watchIds.some((id) => item[column_ref] === id)
5412
+ : watchId === item[column_ref];
5413
+ return (jsxRuntime.jsx(react.Box, { cursor: 'pointer', onClick: () => {
5414
+ if (!isMultiple) {
5415
+ setOpenSearchResult(false);
5416
+ setValue(colLabel, item[column_ref]);
5417
+ return;
5418
+ }
5419
+ // For multiple selection, don't add if already selected
5420
+ if (selected)
5421
+ return;
5422
+ const newSet = new Set([
5423
+ ...(watchIds ?? []),
5424
+ item[column_ref],
5425
+ ]);
5426
+ setValue(colLabel, [...newSet]);
5427
+ }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
5428
+ ? {
5429
+ color: 'colorPalette.400/50',
5430
+ fontWeight: 'bold',
5431
+ }
5432
+ : {}), children: !!renderDisplay === true
5433
+ ? renderDisplay(item)
5434
+ : item[display_column] }, item[column_ref]));
5435
+ }) })) : (jsxRuntime.jsx(react.Text, { children: searchText
5436
+ ? idPickerLabels?.emptySearchResult ??
5437
+ formI18n.t('empty_search_result')
5438
+ : idPickerLabels?.initialResults ??
5439
+ formI18n.t('initial_results') })) }), jsxRuntime.jsx(PaginationRoot, { justifySelf: 'center', count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] })] }));
4407
5440
  };
4408
5441
 
4409
5442
  const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
4410
5443
  const { children, ...rest } = props;
4411
- return (jsxRuntime.jsxs(react.NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: [children, jsxRuntime.jsxs(react.NumberInput.Control, { children: [jsxRuntime.jsx(react.NumberInput.IncrementTrigger, {}), jsxRuntime.jsx(react.NumberInput.DecrementTrigger, {})] })] }));
5444
+ return (jsxRuntime.jsx(react.NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: children }));
4412
5445
  });
4413
5446
  const NumberInputField$1 = react.NumberInput.Input;
4414
5447
  react.NumberInput.Scrubber;
4415
5448
  react.NumberInput.Label;
4416
5449
 
5450
+ /**
5451
+ * Gets the error message for a specific field from react-hook-form errors
5452
+ * Prioritizes required errors (#.required) over field-specific validation errors
5453
+ */
5454
+ const getFieldError = (errors, fieldName) => {
5455
+ // Check for form-level required errors first (highest priority)
5456
+ const requiredError = errors['#.required'];
5457
+ if (requiredError) {
5458
+ const requiredErrorMessage = extractErrorMessage(requiredError);
5459
+ if (requiredErrorMessage) {
5460
+ return requiredErrorMessage;
5461
+ }
5462
+ }
5463
+ // If no required errors, return field-specific error
5464
+ const fieldError = errors[fieldName];
5465
+ if (fieldError) {
5466
+ const fieldErrorMessage = extractErrorMessage(fieldError);
5467
+ if (fieldErrorMessage) {
5468
+ return fieldErrorMessage;
5469
+ }
5470
+ }
5471
+ return undefined;
5472
+ };
5473
+ /**
5474
+ * Helper function to extract error message from various error formats
5475
+ * Only returns message if explicitly provided, no fallback text
5476
+ */
5477
+ const extractErrorMessage = (error) => {
5478
+ if (!error) {
5479
+ return undefined;
5480
+ }
5481
+ // If it's a simple string error
5482
+ if (typeof error === 'string') {
5483
+ return error;
5484
+ }
5485
+ // If it's an error object with a message property
5486
+ if (error && typeof error === 'object' && 'message' in error) {
5487
+ return error.message;
5488
+ }
5489
+ // If it's an array of errors, get the first one
5490
+ if (Array.isArray(error) && error.length > 0) {
5491
+ const firstError = error[0];
5492
+ if (typeof firstError === 'string') {
5493
+ return firstError;
5494
+ }
5495
+ if (firstError &&
5496
+ typeof firstError === 'object' &&
5497
+ 'message' in firstError) {
5498
+ return firstError.message;
5499
+ }
5500
+ }
5501
+ // No fallback - return undefined if no message provided
5502
+ return undefined;
5503
+ };
5504
+
4417
5505
  const NumberInputField = ({ schema, column, prefix, }) => {
4418
5506
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
4419
5507
  const { translate } = useSchemaContext();
4420
- const { required, gridColumn, gridRow } = schema;
5508
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
4421
5509
  const isRequired = required?.some((columnId) => columnId === column);
4422
5510
  const colLabel = `${prefix}${column}`;
4423
5511
  const value = watch(`${colLabel}`);
4424
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn, gridRow, children: [jsxRuntime.jsx(NumberInputRoot, { children: jsxRuntime.jsx(NumberInputField$1, { required: isRequired, value: value, onChange: (event) => {
4425
- setValue(`${colLabel}`, Number(event.target.value));
4426
- } }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5512
+ const fieldError = getFieldError(errors, colLabel);
5513
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
5514
+ ? fieldError.includes('required')
5515
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5516
+ : fieldError
5517
+ : undefined, invalid: !!fieldError, children: jsxRuntime.jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
5518
+ // Store as string or number based on configuration, default to number
5519
+ const value = numberStorageType === 'string'
5520
+ ? details.value
5521
+ : details.valueAsNumber;
5522
+ setValue(`${colLabel}`, value);
5523
+ }, min: schema.minimum, max: schema.maximum, step: schema.multipleOf || 0.01, allowOverflow: false, clampValueOnBlur: false, inputMode: "decimal", formatOptions: schema.formatOptions, children: jsxRuntime.jsx(NumberInputField$1, { required: isRequired }) }) }));
4427
5524
  };
4428
5525
 
4429
5526
  const ObjectInput = ({ schema, column, prefix }) => {
4430
- const { properties, gridRow, gridColumn = "1/span 12", required } = schema;
5527
+ const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
4431
5528
  const { translate } = useSchemaContext();
4432
5529
  const colLabel = `${prefix}${column}`;
4433
5530
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4435,26 +5532,32 @@ const ObjectInput = ({ schema, column, prefix }) => {
4435
5532
  if (properties === undefined) {
4436
5533
  throw new Error(`properties is undefined when using ObjectInput`);
4437
5534
  }
4438
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: Object.keys(properties ?? {}).map((key) => {
5535
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
5536
+ base: 'colorPalette.200',
5537
+ _dark: 'colorPalette.800',
5538
+ }, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
4439
5539
  return (
4440
5540
  // @ts-expect-error find suitable types
4441
5541
  jsxRuntime.jsx(ColumnRenderer, { column: `${key}`,
4442
5542
  prefix: `${prefix}${column}.`,
4443
- properties }, `form-${colLabel}-${key}`));
4444
- }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5543
+ properties,
5544
+ parentRequired: required }, `form-${colLabel}-${key}`));
5545
+ }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4445
5546
  };
4446
5547
 
4447
5548
  const RecordInput$1 = ({ column, schema, prefix }) => {
4448
5549
  const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
4449
5550
  const { translate } = useSchemaContext();
4450
- const { required, gridColumn, gridRow } = schema;
5551
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4451
5552
  const isRequired = required?.some((columnId) => columnId === column);
4452
5553
  const entries = Object.entries(getValues(column) ?? {});
4453
5554
  const [showNewEntries, setShowNewEntries] = React.useState(false);
4454
5555
  const [newKey, setNewKey] = React.useState();
4455
5556
  const [newValue, setNewValue] = React.useState();
4456
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.fieldLabel`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4457
- return (jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
5557
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
5558
+ ? translate.t(`${column}.field_required`)
5559
+ : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
5560
+ return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
4458
5561
  const filtered = entries.filter(([target]) => {
4459
5562
  return target !== key;
4460
5563
  });
@@ -4464,17 +5567,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
4464
5567
  ...getValues(column),
4465
5568
  [key]: e.target.value,
4466
5569
  });
4467
- }, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant: "ghost", onClick: () => {
5570
+ }, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant: 'ghost', onClick: () => {
4468
5571
  const filtered = entries.filter(([target]) => {
4469
5572
  return target !== key;
4470
5573
  });
4471
5574
  setValue(column, Object.fromEntries([...filtered]));
4472
5575
  }, children: jsxRuntime.jsx(cg.CgClose, {}) })] }));
4473
- }), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: newKey, onChange: (e) => {
5576
+ }), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: newKey, onChange: (e) => {
4474
5577
  setNewKey(e.target.value);
4475
5578
  }, autoComplete: "off" }), jsxRuntime.jsx(react.Input, { value: newValue, onChange: (e) => {
4476
5579
  setNewValue(e.target.value);
4477
- }, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant: "subtle", onClick: () => {
5580
+ }, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant: 'subtle', onClick: () => {
4478
5581
  setShowNewEntries(false);
4479
5582
  setNewKey(undefined);
4480
5583
  setNewValue(undefined);
@@ -4493,16 +5596,17 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
4493
5596
  setShowNewEntries(true);
4494
5597
  setNewKey(undefined);
4495
5598
  setNewValue(undefined);
4496
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.fieldRequired`) }))] }));
5599
+ }, children: translate.t(`${column}.addNew`) })] }));
4497
5600
  };
4498
5601
 
4499
5602
  const StringInputField = ({ column, schema, prefix, }) => {
4500
5603
  const { register, formState: { errors }, } = reactHookForm.useFormContext();
4501
5604
  const { translate } = useSchemaContext();
4502
- const { required, gridColumn, gridRow } = schema;
5605
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4503
5606
  const isRequired = required?.some((columnId) => columnId === column);
4504
5607
  const colLabel = `${prefix}${column}`;
4505
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }) }));
5608
+ const fieldError = getFieldError(errors, colLabel);
5609
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
4506
5610
  };
4507
5611
 
4508
5612
  const RadioCardItem = React__namespace.forwardRef(function RadioCardItem(props, ref) {
@@ -4600,145 +5704,796 @@ const TagPicker = ({ column, schema, prefix }) => {
4600
5704
  }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
4601
5705
  };
4602
5706
 
5707
+ const Textarea = React.forwardRef(({ value, defaultValue, placeholder, onChange, onFocus, onBlur, disabled = false, readOnly = false, className, rows = 4, maxLength, autoFocus = false, invalid = false, required = false, label, helperText, errorText, ...props }, ref) => {
5708
+ const contentEditableRef = React.useRef(null);
5709
+ const isControlled = value !== undefined;
5710
+ // Handle input changes
5711
+ const handleInput = (e) => {
5712
+ const text = e.currentTarget.textContent || "";
5713
+ // Check maxLength if specified
5714
+ if (maxLength && text.length > maxLength) {
5715
+ e.currentTarget.textContent = text.slice(0, maxLength);
5716
+ // Move cursor to end
5717
+ const selection = window.getSelection();
5718
+ if (selection) {
5719
+ selection.selectAllChildren(e.currentTarget);
5720
+ selection.collapseToEnd();
5721
+ }
5722
+ return;
5723
+ }
5724
+ onChange?.(text);
5725
+ };
5726
+ // Handle paste events to strip formatting and respect maxLength
5727
+ const handlePaste = (e) => {
5728
+ e.preventDefault();
5729
+ const text = e.clipboardData.getData('text/plain');
5730
+ const currentText = e.currentTarget.textContent || "";
5731
+ let pasteText = text;
5732
+ if (maxLength) {
5733
+ const remainingLength = maxLength - currentText.length;
5734
+ pasteText = text.slice(0, remainingLength);
5735
+ }
5736
+ document.execCommand('insertText', false, pasteText);
5737
+ };
5738
+ // Set initial content
5739
+ React.useEffect(() => {
5740
+ if (contentEditableRef.current && !isControlled) {
5741
+ const initialValue = defaultValue || "";
5742
+ if (contentEditableRef.current.textContent !== initialValue) {
5743
+ contentEditableRef.current.textContent = initialValue;
5744
+ }
5745
+ }
5746
+ }, [defaultValue, isControlled]);
5747
+ // Update content when value changes (controlled mode)
5748
+ React.useEffect(() => {
5749
+ if (contentEditableRef.current && isControlled && value !== undefined) {
5750
+ if (contentEditableRef.current.textContent !== value) {
5751
+ contentEditableRef.current.textContent = value;
5752
+ }
5753
+ }
5754
+ }, [value, isControlled]);
5755
+ // Auto focus
5756
+ React.useEffect(() => {
5757
+ if (autoFocus && contentEditableRef.current) {
5758
+ contentEditableRef.current.focus();
5759
+ }
5760
+ }, [autoFocus]);
5761
+ // Forward ref
5762
+ React.useEffect(() => {
5763
+ if (typeof ref === 'function') {
5764
+ ref(contentEditableRef.current);
5765
+ }
5766
+ else if (ref) {
5767
+ ref.current = contentEditableRef.current;
5768
+ }
5769
+ }, [ref]);
5770
+ const textareaElement = (jsxRuntime.jsx(react.Box, { ref: contentEditableRef, contentEditable: !disabled && !readOnly, onInput: handleInput, onPaste: handlePaste, onFocus: onFocus, onBlur: onBlur, className: className, minHeight: `${rows * 1.5}em`, padding: "2", border: "1px solid", borderColor: invalid ? "red.500" : "gray.200", borderRadius: "md", outline: "none", _focus: {
5771
+ borderColor: invalid ? "red.500" : "blue.500",
5772
+ boxShadow: `0 0 0 1px ${invalid ? "red.500" : "blue.500"}`,
5773
+ }, _disabled: {
5774
+ opacity: 0.6,
5775
+ cursor: "not-allowed",
5776
+ bg: "gray.50",
5777
+ }, _empty: {
5778
+ _before: {
5779
+ content: placeholder ? `"${placeholder}"` : undefined,
5780
+ color: "gray.400",
5781
+ pointerEvents: "none",
5782
+ }
5783
+ }, whiteSpace: "pre-wrap", overflowWrap: "break-word", overflow: "auto", maxHeight: `${rows * 4}em`, suppressContentEditableWarning: true, ...props }));
5784
+ // If we have additional field props, wrap in Field component
5785
+ if (label || helperText || errorText || required) {
5786
+ return (jsxRuntime.jsxs(react.Field.Root, { invalid: invalid, required: required, children: [label && (jsxRuntime.jsxs(react.Field.Label, { children: [label, required && jsxRuntime.jsx(react.Field.RequiredIndicator, {})] })), textareaElement, helperText && jsxRuntime.jsx(react.Field.HelperText, { children: helperText }), errorText && jsxRuntime.jsx(react.Field.ErrorText, { children: errorText })] }));
5787
+ }
5788
+ return textareaElement;
5789
+ });
5790
+ Textarea.displayName = "Textarea";
5791
+
5792
+ const TextAreaInput = ({ column, schema, prefix, }) => {
5793
+ const { register, formState: { errors }, } = reactHookForm.useFormContext();
5794
+ const { translate } = useSchemaContext();
5795
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5796
+ const isRequired = required?.some((columnId) => columnId === column);
5797
+ const colLabel = `${prefix}${column}`;
5798
+ const form = reactHookForm.useFormContext();
5799
+ const { setValue, watch } = form;
5800
+ const fieldError = getFieldError(errors, colLabel);
5801
+ const watchValue = watch(colLabel);
5802
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
5803
+ ? fieldError.includes('required')
5804
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5805
+ : fieldError
5806
+ : undefined, invalid: !!fieldError, children: jsxRuntime.jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
5807
+ };
5808
+
5809
+ function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
5810
+ am: "am",
5811
+ pm: "pm",
5812
+ }, onChange = (_newValue) => { }, timezone = "Asia/Hong_Kong", }) {
5813
+ const handleClear = () => {
5814
+ setHour(null);
5815
+ setMinute(null);
5816
+ setMeridiem(null);
5817
+ setInputValue("");
5818
+ setShowInput(false);
5819
+ onChange({ hour: null, minute: null, meridiem: null });
5820
+ };
5821
+ const getTimeString = (hour, minute, meridiem) => {
5822
+ if (hour === null || minute === null || meridiem === null) {
5823
+ return "";
5824
+ }
5825
+ // if the hour is 24, set the hour to 0
5826
+ if (hour === 24) {
5827
+ return dayjs().tz(timezone).hour(0).minute(minute).format("HH:mmZ");
5828
+ }
5829
+ // use dayjs to format the time at current timezone
5830
+ // if meridiem is pm, add 12 hours
5831
+ let newHour = hour;
5832
+ if (meridiem === "pm" && hour !== 12) {
5833
+ newHour = hour + 12;
5834
+ }
5835
+ // if the hour is 12, set the meridiem to am, and set the hour to 0
5836
+ else if (meridiem === "am" && hour === 12) {
5837
+ newHour = 0;
5838
+ }
5839
+ return dayjs().tz(timezone).hour(newHour).minute(minute).format("HH:mmZ");
5840
+ };
5841
+ const stringTime = getTimeString(hour, minute, meridiem);
5842
+ const [inputValue, setInputValue] = React.useState("");
5843
+ const [showInput, setShowInput] = React.useState(false);
5844
+ const handleBlur = (text) => {
5845
+ // ignore all non-numeric characters
5846
+ if (!text) {
5847
+ return;
5848
+ }
5849
+ const value = text.replace(/[^0-9apm]/g, "");
5850
+ if (value === "") {
5851
+ handleClear();
5852
+ return;
5853
+ }
5854
+ // if the value is a valid time, parse it and set the hour, minute, and meridiem
5855
+ // if the value is not a valid time, set the stringTime to the value
5856
+ // first two characters are the hour
5857
+ // next two characters are the minute
5858
+ // final two characters are the meridiem
5859
+ const hour = parseInt(value.slice(0, 2));
5860
+ const minute = parseInt(value.slice(2, 4));
5861
+ const meridiem = value.slice(4, 6);
5862
+ // validate the hour and minute
5863
+ if (isNaN(hour) || isNaN(minute)) {
5864
+ setInputValue("");
5865
+ return;
5866
+ }
5867
+ // if the hour is larger than 24, set the hour to 24
5868
+ if (hour > 24) {
5869
+ setInputValue("");
5870
+ return;
5871
+ }
5872
+ let newHour = hour;
5873
+ let newMinute = minute;
5874
+ let newMeridiem = meridiem;
5875
+ // if the hour is 24, set the meridiem to am, and set the hour to 0
5876
+ if (hour === 24) {
5877
+ newMeridiem = "am";
5878
+ newHour = 0;
5879
+ }
5880
+ // if the hour is greater than 12, set the meridiem to pm, and subtract 12 from the hour
5881
+ else if (hour > 12) {
5882
+ newMeridiem = "pm";
5883
+ newHour = hour - 12;
5884
+ }
5885
+ // if the hour is 12, set the meridiem to pm, and set the hour to 12
5886
+ else if (hour === 12) {
5887
+ newMeridiem = "pm";
5888
+ newHour = 12;
5889
+ }
5890
+ // if the hour is 0, set the meridiem to am, and set the hour to 12
5891
+ else if (hour === 0) {
5892
+ newMeridiem = "am";
5893
+ newHour = 12;
5894
+ }
5895
+ else {
5896
+ newMeridiem = meridiem ?? "am";
5897
+ newHour = hour;
5898
+ }
5899
+ if (minute > 59) {
5900
+ newMinute = 0;
5901
+ }
5902
+ else {
5903
+ newMinute = minute;
5904
+ }
5905
+ onChange({
5906
+ hour: newHour,
5907
+ minute: newMinute,
5908
+ meridiem: newMeridiem,
5909
+ });
5910
+ setShowInput(false);
5911
+ };
5912
+ const handleKeyDown = (e) => {
5913
+ if (e.key === "Enter") {
5914
+ handleBlur(e.currentTarget.value);
5915
+ }
5916
+ };
5917
+ const inputRef = React.useRef(null);
5918
+ return (jsxRuntime.jsxs(react.Grid, { justifyContent: "center", alignItems: "center", templateColumns: "200px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsxRuntime.jsx(react.Input, { onKeyDown: handleKeyDown, onChange: (e) => {
5919
+ setInputValue(e.currentTarget.value);
5920
+ }, onBlur: (e) => {
5921
+ handleBlur(e.currentTarget.value);
5922
+ }, onFocus: (e) => {
5923
+ e.currentTarget.select();
5924
+ }, value: inputValue, display: showInput ? undefined : "none", ref: inputRef }), jsxRuntime.jsxs(react.Button, { onClick: () => {
5925
+ setShowInput(true);
5926
+ setInputValue(dayjs(`1970-01-01T${getTimeString(hour, minute, meridiem)}`, "hh:mmZ").format("HH:mm"));
5927
+ inputRef.current?.focus();
5928
+ }, display: showInput ? "none" : "flex", alignItems: "center", justifyContent: "start", variant: "outline", gap: 2, children: [jsxRuntime.jsx(react.Icon, { size: "sm", children: jsxRuntime.jsx(bs.BsClock, {}) }), jsxRuntime.jsx(react.Text, { fontSize: "sm", children: stringTime
5929
+ ? dayjs(`1970-01-01T${stringTime}`, "hh:mmZ").format("hh:mm a")
5930
+ : "" })] }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(md.MdCancel, {}) })] }));
5931
+ }
5932
+
5933
+ dayjs.extend(timezone);
5934
+ const TimePicker = ({ column, schema, prefix }) => {
5935
+ const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
5936
+ const { translate, timezone } = useSchemaContext();
5937
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
5938
+ const isRequired = required?.some((columnId) => columnId === column);
5939
+ const colLabel = `${prefix}${column}`;
5940
+ const [open, setOpen] = React.useState(false);
5941
+ const value = watch(colLabel);
5942
+ const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
5943
+ ? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
5944
+ : '';
5945
+ // Parse the initial time parts from the time string (HH:mm:ssZ)
5946
+ const parseTime = (time) => {
5947
+ if (!time)
5948
+ return { hour: 12, minute: 0, meridiem: 'am' };
5949
+ const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
5950
+ if (!parsed.isValid()) {
5951
+ return { hour: 12, minute: 0, meridiem: 'am' };
5952
+ }
5953
+ let hour = parsed.hour();
5954
+ const minute = parsed.minute();
5955
+ const meridiem = hour >= 12 ? 'pm' : 'am';
5956
+ if (hour === 0)
5957
+ hour = 12;
5958
+ else if (hour > 12)
5959
+ hour -= 12;
5960
+ return { hour, minute, meridiem };
5961
+ };
5962
+ const initialTime = parseTime(value);
5963
+ const [hour, setHour] = React.useState(initialTime.hour);
5964
+ const [minute, setMinute] = React.useState(initialTime.minute);
5965
+ const [meridiem, setMeridiem] = React.useState(initialTime.meridiem);
5966
+ React.useEffect(() => {
5967
+ const { hour, minute, meridiem } = parseTime(value);
5968
+ setHour(hour);
5969
+ setMinute(minute);
5970
+ setMeridiem(meridiem);
5971
+ }, [value]);
5972
+ const getTimeString = (hour, minute, meridiem) => {
5973
+ if (hour === null || minute === null || meridiem === null)
5974
+ return null;
5975
+ let newHour = hour;
5976
+ if (meridiem === 'pm' && hour !== 12) {
5977
+ newHour = hour + 12;
5978
+ }
5979
+ return dayjs()
5980
+ .tz(timezone)
5981
+ .hour(newHour)
5982
+ .minute(minute)
5983
+ .second(0)
5984
+ .format(timeFormat);
5985
+ };
5986
+ // Handle changes to time parts
5987
+ const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
5988
+ setHour(newHour);
5989
+ setMinute(newMinute);
5990
+ setMeridiem(newMeridiem);
5991
+ const timeString = getTimeString(newHour, newMinute, newMeridiem);
5992
+ setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
5993
+ };
5994
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
5995
+ gridRow, errorText: errors[`${colLabel}`]
5996
+ ? translate.t(removeIndex(`${colLabel}.field_required`))
5997
+ : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5998
+ setOpen(true);
5999
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
6000
+ am: translate.t(`common.am`, { defaultValue: 'AM' }),
6001
+ pm: translate.t(`common.pm`, { defaultValue: 'PM' }),
6002
+ } }) }) }) })] }) }));
6003
+ };
6004
+
6005
+ function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
6006
+ // Refs for focus management
6007
+ const hourInputRef = React.useRef(null);
6008
+ const minuteInputRef = React.useRef(null);
6009
+ const secondInputRef = React.useRef(null);
6010
+ // Centralized handler for key events, value changes, and focus management
6011
+ const handleKeyDown = (e, field) => {
6012
+ const input = e.target;
6013
+ const value = input.value;
6014
+ // Handle navigation between fields
6015
+ if (e.key === "Tab") {
6016
+ return;
6017
+ }
6018
+ if (e.key === ":" && field === "hour") {
6019
+ e.preventDefault();
6020
+ minuteInputRef.current?.focus();
6021
+ return;
6022
+ }
6023
+ if (e.key === ":" && field === "minute") {
6024
+ e.preventDefault();
6025
+ secondInputRef.current?.focus();
6026
+ return;
6027
+ }
6028
+ if (e.key === "Backspace" && value === "") {
6029
+ e.preventDefault();
6030
+ if (field === "minute") {
6031
+ hourInputRef.current?.focus();
6032
+ }
6033
+ else if (field === "second") {
6034
+ minuteInputRef.current?.focus();
6035
+ }
6036
+ return;
6037
+ }
6038
+ // Handle number inputs
6039
+ if (field === "hour") {
6040
+ if (e.key.match(/^[0-9]$/)) {
6041
+ const newValue = value + e.key;
6042
+ const numValue = parseInt(newValue, 10);
6043
+ if (numValue > 23) {
6044
+ const digitValue = parseInt(e.key, 10);
6045
+ setHour(digitValue);
6046
+ onChange({ hour: digitValue, minute, second });
6047
+ return;
6048
+ }
6049
+ if (numValue >= 0 && numValue <= 23) {
6050
+ setHour(numValue);
6051
+ onChange({ hour: numValue, minute, second });
6052
+ e.preventDefault();
6053
+ minuteInputRef.current?.focus();
6054
+ }
6055
+ }
6056
+ }
6057
+ else if (field === "minute") {
6058
+ if (e.key.match(/^[0-9]$/)) {
6059
+ const newValue = value + e.key;
6060
+ const numValue = parseInt(newValue, 10);
6061
+ if (numValue > 59) {
6062
+ const digitValue = parseInt(e.key, 10);
6063
+ setMinute(digitValue);
6064
+ onChange({ hour, minute: digitValue, second });
6065
+ return;
6066
+ }
6067
+ if (numValue >= 0 && numValue <= 59) {
6068
+ setMinute(numValue);
6069
+ onChange({ hour, minute: numValue, second });
6070
+ e.preventDefault();
6071
+ secondInputRef.current?.focus();
6072
+ }
6073
+ }
6074
+ }
6075
+ else if (field === "second") {
6076
+ if (e.key.match(/^[0-9]$/)) {
6077
+ const newValue = value + e.key;
6078
+ const numValue = parseInt(newValue, 10);
6079
+ if (numValue > 59) {
6080
+ const digitValue = parseInt(e.key, 10);
6081
+ setSecond(digitValue);
6082
+ onChange({ hour, minute, second: digitValue });
6083
+ return;
6084
+ }
6085
+ if (numValue >= 0 && numValue <= 59) {
6086
+ setSecond(numValue);
6087
+ onChange({ hour, minute, second: numValue });
6088
+ }
6089
+ }
6090
+ }
6091
+ };
6092
+ const handleClear = () => {
6093
+ setHour(null);
6094
+ setMinute(null);
6095
+ setSecond(null);
6096
+ onChange({ hour: null, minute: null, second: null });
6097
+ hourInputRef.current?.focus();
6098
+ };
6099
+ return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 10px 60px auto", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsx(react.Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsx(react.Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsx(react.Input, { ref: secondInputRef, type: "text", value: second === null ? "" : second.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "second"), placeholder: "SS", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(md.MdCancel, {}) })] }) }));
6100
+ }
6101
+
6102
+ function DateTimePicker$1({ value, onChange, format = "date-time", showSeconds = false, labels = {
6103
+ monthNamesShort: [
6104
+ "Jan",
6105
+ "Feb",
6106
+ "Mar",
6107
+ "Apr",
6108
+ "May",
6109
+ "Jun",
6110
+ "Jul",
6111
+ "Aug",
6112
+ "Sep",
6113
+ "Oct",
6114
+ "Nov",
6115
+ "Dec",
6116
+ ],
6117
+ weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
6118
+ backButtonLabel: "Back",
6119
+ forwardButtonLabel: "Next",
6120
+ }, timezone = "Asia/Hong_Kong", }) {
6121
+ const [selectedDate, setSelectedDate] = React.useState(value || "");
6122
+ // Time state for 12-hour format
6123
+ const [hour12, setHour12] = React.useState(value ? dayjs(value).hour() % 12 || 12 : null);
6124
+ const [minute, setMinute] = React.useState(value ? dayjs(value).minute() : null);
6125
+ const [meridiem, setMeridiem] = React.useState(value ? (dayjs(value).hour() >= 12 ? "pm" : "am") : null);
6126
+ // Time state for 24-hour format
6127
+ const [hour24, setHour24] = React.useState(value ? dayjs(value).hour() : null);
6128
+ const [second, setSecond] = React.useState(value ? dayjs(value).second() : null);
6129
+ const handleDateChange = (date) => {
6130
+ setSelectedDate(date);
6131
+ updateDateTime(dayjs(date).tz(timezone).toISOString());
6132
+ };
6133
+ const handleTimeChange = (timeData) => {
6134
+ if (format === "iso-date-time") {
6135
+ setHour24(timeData.hour);
6136
+ setMinute(timeData.minute);
6137
+ if (showSeconds)
6138
+ setSecond(timeData.second);
6139
+ }
6140
+ else {
6141
+ setHour12(timeData.hour);
6142
+ setMinute(timeData.minute);
6143
+ setMeridiem(timeData.meridiem);
6144
+ }
6145
+ updateDateTime(dayjs(selectedDate).tz(timezone).toISOString(), timeData);
6146
+ };
6147
+ const updateDateTime = (date, timeData) => {
6148
+ if (!date) {
6149
+ onChange?.(undefined);
6150
+ return;
6151
+ }
6152
+ // use dayjs to convert the date to the timezone
6153
+ const newDate = dayjs(date).tz(timezone).toDate();
6154
+ if (format === "iso-date-time") {
6155
+ const h = timeData?.hour ?? hour24;
6156
+ const m = timeData?.minute ?? minute;
6157
+ const s = showSeconds ? timeData?.second ?? second : 0;
6158
+ if (h !== null)
6159
+ newDate.setHours(h);
6160
+ if (m !== null)
6161
+ newDate.setMinutes(m);
6162
+ if (s !== null)
6163
+ newDate.setSeconds(s);
6164
+ }
6165
+ else {
6166
+ const h = timeData?.hour ?? hour12;
6167
+ const m = timeData?.minute ?? minute;
6168
+ const mer = timeData?.meridiem ?? meridiem;
6169
+ if (h !== null && mer !== null) {
6170
+ let hour24 = h;
6171
+ if (mer === "am" && h === 12)
6172
+ hour24 = 0;
6173
+ else if (mer === "pm" && h < 12)
6174
+ hour24 = h + 12;
6175
+ newDate.setHours(hour24);
6176
+ }
6177
+ if (m !== null)
6178
+ newDate.setMinutes(m);
6179
+ newDate.setSeconds(0);
6180
+ }
6181
+ onChange?.(dayjs(newDate).tz(timezone).toISOString());
6182
+ };
6183
+ const handleClear = () => {
6184
+ setSelectedDate("");
6185
+ setHour12(null);
6186
+ setHour24(null);
6187
+ setMinute(null);
6188
+ setSecond(null);
6189
+ setMeridiem(null);
6190
+ onChange?.(undefined);
6191
+ };
6192
+ const isISO = format === "iso-date-time";
6193
+ return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsxRuntime.jsx(DatePicker$1, { selected: selectedDate
6194
+ ? dayjs(selectedDate).tz(timezone).toDate()
6195
+ : new Date(), onDateSelected: ({ date }) => handleDateChange(dayjs(date).tz(timezone).toISOString()), monthsToDisplay: 1, labels: labels }), jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsxRuntime.jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: second, setSecond: setSecond, onChange: handleTimeChange })) : (jsxRuntime.jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsxRuntime.jsx(react.Icon, { as: fa6.FaTrash }) })] }), selectedDate && (jsxRuntime.jsxs(react.Flex, { gap: 2, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).format(isISO
6196
+ ? showSeconds
6197
+ ? "YYYY-MM-DD HH:mm:ss"
6198
+ : "YYYY-MM-DD HH:mm"
6199
+ : "YYYY-MM-DD hh:mm A ") }), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).tz(timezone).format("Z") }), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: timezone })] }))] }));
6200
+ }
6201
+
6202
+ dayjs.extend(utc);
6203
+ dayjs.extend(timezone);
6204
+ const DateTimePicker = ({ column, schema, prefix, }) => {
6205
+ const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
6206
+ const { timezone, dateTimePickerLabels } = useSchemaContext();
6207
+ const formI18n = useFormI18n(column, prefix);
6208
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
6209
+ // with timezone
6210
+ dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
6211
+ const isRequired = required?.some((columnId) => columnId === column);
6212
+ const colLabel = formI18n.colLabel;
6213
+ const [open, setOpen] = React.useState(false);
6214
+ const selectedDate = watch(colLabel);
6215
+ const displayDate = dayjs(selectedDate)
6216
+ .tz(timezone)
6217
+ .format(displayDateFormat);
6218
+ React.useEffect(() => {
6219
+ try {
6220
+ if (selectedDate) {
6221
+ // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
6222
+ // For example, parse as UTC:
6223
+ const parsedDate = dayjs(selectedDate).tz(timezone);
6224
+ if (!parsedDate.isValid())
6225
+ return;
6226
+ // Format according to dateFormat from schema
6227
+ const formatted = parsedDate.format(dateFormat);
6228
+ // Update the form value only if different to avoid loops
6229
+ if (formatted !== selectedDate) {
6230
+ setValue(colLabel, formatted, {
6231
+ shouldValidate: true,
6232
+ shouldDirty: true,
6233
+ });
6234
+ }
6235
+ }
6236
+ }
6237
+ catch (e) {
6238
+ console.error(e);
6239
+ }
6240
+ }, [selectedDate, dateFormat, colLabel, setValue]);
6241
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6242
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
6243
+ setOpen(true);
6244
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), jsxRuntime.jsx(PopoverContent, { minW: '450px', children: jsxRuntime.jsxs(PopoverBody, { children: [jsxRuntime.jsx(PopoverTitle, {}), jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
6245
+ setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
6246
+ }, timezone: timezone, labels: {
6247
+ monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
6248
+ formI18n.translate.t(`common.month_1`, {
6249
+ defaultValue: 'January',
6250
+ }),
6251
+ formI18n.translate.t(`common.month_2`, {
6252
+ defaultValue: 'February',
6253
+ }),
6254
+ formI18n.translate.t(`common.month_3`, {
6255
+ defaultValue: 'March',
6256
+ }),
6257
+ formI18n.translate.t(`common.month_4`, {
6258
+ defaultValue: 'April',
6259
+ }),
6260
+ formI18n.translate.t(`common.month_5`, {
6261
+ defaultValue: 'May',
6262
+ }),
6263
+ formI18n.translate.t(`common.month_6`, {
6264
+ defaultValue: 'June',
6265
+ }),
6266
+ formI18n.translate.t(`common.month_7`, {
6267
+ defaultValue: 'July',
6268
+ }),
6269
+ formI18n.translate.t(`common.month_8`, {
6270
+ defaultValue: 'August',
6271
+ }),
6272
+ formI18n.translate.t(`common.month_9`, {
6273
+ defaultValue: 'September',
6274
+ }),
6275
+ formI18n.translate.t(`common.month_10`, {
6276
+ defaultValue: 'October',
6277
+ }),
6278
+ formI18n.translate.t(`common.month_11`, {
6279
+ defaultValue: 'November',
6280
+ }),
6281
+ formI18n.translate.t(`common.month_12`, {
6282
+ defaultValue: 'December',
6283
+ }),
6284
+ ],
6285
+ weekdayNamesShort: dateTimePickerLabels?.weekdayNamesShort ?? [
6286
+ formI18n.translate.t(`common.weekday_1`, {
6287
+ defaultValue: 'Sun',
6288
+ }),
6289
+ formI18n.translate.t(`common.weekday_2`, {
6290
+ defaultValue: 'Mon',
6291
+ }),
6292
+ formI18n.translate.t(`common.weekday_3`, {
6293
+ defaultValue: 'Tue',
6294
+ }),
6295
+ formI18n.translate.t(`common.weekday_4`, {
6296
+ defaultValue: 'Wed',
6297
+ }),
6298
+ formI18n.translate.t(`common.weekday_5`, {
6299
+ defaultValue: 'Thu',
6300
+ }),
6301
+ formI18n.translate.t(`common.weekday_6`, {
6302
+ defaultValue: 'Fri',
6303
+ }),
6304
+ formI18n.translate.t(`common.weekday_7`, {
6305
+ defaultValue: 'Sat',
6306
+ }),
6307
+ ],
6308
+ backButtonLabel: dateTimePickerLabels?.backButtonLabel ??
6309
+ formI18n.translate.t(`common.back_button`, {
6310
+ defaultValue: 'Back',
6311
+ }),
6312
+ forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ??
6313
+ formI18n.translate.t(`common.forward_button`, {
6314
+ defaultValue: 'Forward',
6315
+ }),
6316
+ } })] }) })] }) }));
6317
+ };
6318
+
4603
6319
  const SchemaRenderer = ({ schema, prefix, column, }) => {
4604
6320
  const colSchema = schema;
4605
- const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
4606
- if (type === "string") {
6321
+ const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
6322
+ if (variant === 'custom-input') {
6323
+ return jsxRuntime.jsx(CustomInput, { schema: colSchema, prefix, column });
6324
+ }
6325
+ if (type === 'string') {
4607
6326
  if ((schema.enum ?? []).length > 0) {
4608
6327
  return jsxRuntime.jsx(EnumPicker, { schema: colSchema, prefix, column });
4609
6328
  }
4610
- if (variant === "id-picker") {
6329
+ if (variant === 'id-picker') {
4611
6330
  idPickerSanityCheck(column, foreign_key);
4612
6331
  return jsxRuntime.jsx(IdPicker, { schema: colSchema, prefix, column });
4613
6332
  }
4614
- if (variant === "date-picker") {
6333
+ if (format === 'date') {
4615
6334
  return jsxRuntime.jsx(DatePicker, { schema: colSchema, prefix, column });
4616
6335
  }
6336
+ if (format === 'time') {
6337
+ return jsxRuntime.jsx(TimePicker, { schema: colSchema, prefix, column });
6338
+ }
6339
+ if (format === 'date-time') {
6340
+ return jsxRuntime.jsx(DateTimePicker, { schema: colSchema, prefix, column });
6341
+ }
6342
+ if (variant === 'text-area') {
6343
+ return jsxRuntime.jsx(TextAreaInput, { schema: colSchema, prefix, column });
6344
+ }
4617
6345
  return jsxRuntime.jsx(StringInputField, { schema: colSchema, prefix, column });
4618
6346
  }
4619
- if (type === "number" || type === "integer") {
6347
+ if (type === 'number' || type === 'integer') {
4620
6348
  return jsxRuntime.jsx(NumberInputField, { schema: colSchema, prefix, column });
4621
6349
  }
4622
- if (type === "boolean") {
6350
+ if (type === 'boolean') {
4623
6351
  return jsxRuntime.jsx(BooleanPicker, { schema: colSchema, prefix, column });
4624
6352
  }
4625
- if (type === "object") {
6353
+ if (type === 'object') {
4626
6354
  if (innerProperties) {
4627
6355
  return jsxRuntime.jsx(ObjectInput, { schema: colSchema, prefix, column });
4628
6356
  }
4629
6357
  return jsxRuntime.jsx(RecordInput$1, { schema: colSchema, prefix, column });
4630
6358
  }
4631
- if (type === "array") {
4632
- if (variant === "id-picker") {
6359
+ if (type === 'array') {
6360
+ if (variant === 'id-picker') {
4633
6361
  idPickerSanityCheck(column, foreign_key);
4634
6362
  return (jsxRuntime.jsx(IdPicker, { schema: colSchema, prefix, column, isMultiple: true }));
4635
6363
  }
4636
- if (variant === "tag-picker") {
6364
+ if (variant === 'tag-picker') {
4637
6365
  return jsxRuntime.jsx(TagPicker, { schema: colSchema, prefix, column });
4638
6366
  }
4639
- if (variant === "file-picker") {
6367
+ if (variant === 'file-picker') {
4640
6368
  return jsxRuntime.jsx(FilePicker, { schema: colSchema, prefix, column });
4641
6369
  }
6370
+ if (variant === 'date-range') {
6371
+ return jsxRuntime.jsx(DateRangePicker, { schema: colSchema, prefix, column });
6372
+ }
6373
+ if (variant === 'enum-picker') {
6374
+ const { items } = colSchema;
6375
+ const { enum: enumItems } = items;
6376
+ const enumSchema = {
6377
+ type: 'string',
6378
+ enum: enumItems,
6379
+ };
6380
+ return (jsxRuntime.jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
6381
+ }
4642
6382
  if (items) {
4643
6383
  return jsxRuntime.jsx(ArrayRenderer, { schema: colSchema, prefix, column });
4644
6384
  }
4645
6385
  return jsxRuntime.jsx(react.Text, { children: `array ${column}` });
4646
6386
  }
4647
- if (type === "null") {
6387
+ if (type === 'null') {
4648
6388
  return jsxRuntime.jsx(react.Text, { children: `null ${column}` });
4649
6389
  }
4650
6390
  return jsxRuntime.jsx(react.Text, { children: "missing type" });
4651
6391
  };
4652
6392
 
4653
- const ColumnRenderer = ({ column, properties, prefix, }) => {
6393
+ const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
4654
6394
  const colSchema = properties[column];
4655
6395
  const colLabel = `${prefix}${column}`;
4656
6396
  if (colSchema === undefined) {
4657
6397
  throw new Error(`${colLabel} does not exist when using ColumnRenderer`);
4658
6398
  }
4659
- return jsxRuntime.jsx(SchemaRenderer, { schema: colSchema, prefix, column });
6399
+ // Merge parent's required array with the schema's required array
6400
+ const schemaWithRequired = {
6401
+ ...colSchema,
6402
+ required: parentRequired || colSchema.required,
6403
+ };
6404
+ return jsxRuntime.jsx(SchemaRenderer, { schema: schemaWithRequired, prefix, column });
4660
6405
  };
4661
6406
 
4662
6407
  const ArrayViewer = ({ schema, column, prefix }) => {
4663
- const { gridRow, gridColumn = "1/span 12", required, items } = schema;
6408
+ const { gridColumn = "span 12", gridRow = "span 1", required, items, } = schema;
4664
6409
  const { translate } = useSchemaContext();
4665
6410
  const colLabel = `${prefix}${column}`;
4666
6411
  const isRequired = required?.some((columnId) => columnId === column);
4667
6412
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4668
6413
  const values = watch(colLabel) ?? [];
4669
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), values.map((field, index) => (jsxRuntime.jsx(react.Flex, { flexFlow: "column", children: jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: jsxRuntime.jsx(SchemaViewer, { column: `${index}`,
4670
- prefix: `${colLabel}.`,
4671
- schema: items }) }) }, `form-${prefix}${column}.${index}`))), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6414
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: values.map((field, index) => (jsxRuntime.jsx(react.Flex, { flexFlow: "column", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "2", borderRadius: "md", borderWidth: "thin", borderColor: {
6415
+ base: "colorPalette.200",
6416
+ _dark: "colorPalette.800",
6417
+ }, children: jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsxRuntime.jsx(SchemaViewer, { column: `${index}`,
6418
+ prefix: `${colLabel}.`,
6419
+ // @ts-expect-error find suitable types
6420
+ schema: { showLabel: false, ...(items ?? {}) } }) }) }, `form-${prefix}${column}.${index}`))) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4672
6421
  };
4673
6422
 
4674
6423
  const BooleanViewer = ({ schema, column, prefix, }) => {
4675
6424
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4676
6425
  const { translate } = useSchemaContext();
4677
- const { required, gridColumn, gridRow } = schema;
6426
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4678
6427
  const isRequired = required?.some((columnId) => columnId === column);
4679
6428
  const colLabel = `${prefix}${column}`;
4680
6429
  const value = watch(colLabel);
4681
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6430
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4682
6431
  gridRow, children: [jsxRuntime.jsx(react.Text, { children: value
4683
6432
  ? translate.t(removeIndex(`${colLabel}.true`))
4684
- : translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6433
+ : translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
6434
+ };
6435
+
6436
+ const CustomViewer = ({ column, schema, prefix }) => {
6437
+ const formContext = reactHookForm.useFormContext();
6438
+ const { inputViewerRender } = schema;
6439
+ return (inputViewerRender &&
6440
+ inputViewerRender({
6441
+ column,
6442
+ schema,
6443
+ prefix,
6444
+ formContext,
6445
+ }));
4685
6446
  };
4686
6447
 
4687
6448
  const DateViewer = ({ column, schema, prefix }) => {
4688
6449
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4689
- const { translate } = useSchemaContext();
4690
- const { required, gridColumn, gridRow } = schema;
6450
+ const { translate, timezone } = useSchemaContext();
6451
+ const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
4691
6452
  const isRequired = required?.some((columnId) => columnId === column);
4692
6453
  const colLabel = `${prefix}${column}`;
4693
6454
  const selectedDate = watch(colLabel);
4694
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4695
- gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? selectedDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.fieldRequired`) }))] }));
6455
+ const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
6456
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6457
+ gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
4696
6458
  };
4697
6459
 
4698
6460
  const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
4699
6461
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4700
- const { translate } = useSchemaContext();
6462
+ const formI18n = useFormI18n(column, prefix);
4701
6463
  const { required } = schema;
4702
6464
  const isRequired = required?.some((columnId) => columnId === column);
4703
- const { gridColumn, gridRow, renderDisplay } = schema;
4704
- const colLabel = `${prefix}${column}`;
6465
+ const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
6466
+ const colLabel = formI18n.colLabel;
4705
6467
  const watchEnum = watch(colLabel);
4706
6468
  const watchEnums = (watch(colLabel) ?? []);
4707
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6469
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
4708
6470
  gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 1, children: watchEnums.map((enumValue) => {
4709
6471
  const item = enumValue;
4710
6472
  if (item === undefined) {
4711
6473
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "undefined" });
4712
6474
  }
4713
- return (jsxRuntime.jsx(Tag, { closable: true, children: !!renderDisplay === true
6475
+ return (jsxRuntime.jsx(Tag, { size: "lg", children: !!renderDisplay === true
4714
6476
  ? renderDisplay(item)
4715
- : translate.t(removeIndex(`${colLabel}.${item}`)) }));
4716
- }) })), !isMultiple && (jsxRuntime.jsx(react.Text, { children: translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6477
+ : formI18n.t(item) }, item));
6478
+ }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: formI18n.required() }))] }));
4717
6479
  };
4718
6480
 
4719
6481
  const FileViewer = ({ column, schema, prefix }) => {
4720
- const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
6482
+ const { watch } = reactHookForm.useFormContext();
4721
6483
  const { translate } = useSchemaContext();
4722
- const { required, gridColumn, gridRow } = schema;
6484
+ const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
4723
6485
  const isRequired = required?.some((columnId) => columnId === column);
4724
6486
  const currentFiles = (watch(column) ?? []);
4725
6487
  const colLabel = `${prefix}${column}`;
4726
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${colLabel}.fieldLabel`)}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: [jsxRuntime.jsx(FileDropzone, { onDrop: ({ files }) => {
4727
- const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4728
- setValue(colLabel, [...currentFiles, ...newFiles]);
4729
- }, placeholder: translate.t(`${colLabel}.fileDropzone`) }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
4730
- return (jsxRuntime.jsx(react.Card.Root, { variant: "subtle", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
4731
- setValue(column, currentFiles.filter(({ name }) => {
4732
- return name !== file.name;
4733
- }));
4734
- }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [jsxRuntime.jsx(react.Box, { children: file.name }), jsxRuntime.jsx(ti.TiDeleteOutline, {})] }) }, file.name));
4735
- }) }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6488
+ return (jsxRuntime.jsx(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
6489
+ return (jsxRuntime.jsx(react.Card.Root, { variant: "subtle", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsxRuntime.jsx(react.Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsxRuntime.jsx(react.Box, { children: file.name })] }) }, file.name));
6490
+ }) }) }));
4736
6491
  };
4737
6492
 
4738
6493
  const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
4739
6494
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4740
6495
  const { idMap, translate } = useSchemaContext();
4741
- const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
6496
+ const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
4742
6497
  const isRequired = required?.some((columnId) => columnId === column);
4743
6498
  const { display_column } = foreign_key;
4744
6499
  const colLabel = `${prefix}${column}`;
@@ -4754,7 +6509,7 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
4754
6509
  }
4755
6510
  return record[display_column];
4756
6511
  };
4757
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6512
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4758
6513
  gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 1, children: watchIds.map((id) => {
4759
6514
  const item = idMap[id];
4760
6515
  if (item === undefined) {
@@ -4763,21 +6518,39 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
4763
6518
  return (jsxRuntime.jsx(Tag, { closable: true, children: !!renderDisplay === true
4764
6519
  ? renderDisplay(item)
4765
6520
  : item[display_column] }, id));
4766
- }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6521
+ }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4767
6522
  };
4768
6523
 
4769
6524
  const NumberViewer = ({ schema, column, prefix, }) => {
4770
6525
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4771
6526
  const { translate } = useSchemaContext();
4772
- const { required, gridColumn, gridRow } = schema;
6527
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
4773
6528
  const isRequired = required?.some((columnId) => columnId === column);
4774
6529
  const colLabel = `${prefix}${column}`;
4775
6530
  const value = watch(colLabel);
4776
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn, gridRow, children: [jsxRuntime.jsx(react.Text, { children: value }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6531
+ // Format the value for display if formatOptions are provided
6532
+ const formatValue = (val) => {
6533
+ if (val === undefined || val === null || val === '')
6534
+ return '';
6535
+ const numValue = typeof val === 'string' ? parseFloat(val) : val;
6536
+ if (isNaN(numValue))
6537
+ return String(val);
6538
+ // Use formatOptions if available, otherwise display as-is
6539
+ if (schema.formatOptions) {
6540
+ try {
6541
+ return new Intl.NumberFormat(undefined, schema.formatOptions).format(numValue);
6542
+ }
6543
+ catch {
6544
+ return String(val);
6545
+ }
6546
+ }
6547
+ return String(val);
6548
+ };
6549
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsxRuntime.jsx(react.Text, { children: formatValue(value) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4777
6550
  };
4778
6551
 
4779
6552
  const ObjectViewer = ({ schema, column, prefix }) => {
4780
- const { properties, gridRow, gridColumn = "1/span 12", required } = schema;
6553
+ const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
4781
6554
  const { translate } = useSchemaContext();
4782
6555
  const colLabel = `${prefix}${column}`;
4783
6556
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4785,25 +6558,28 @@ const ObjectViewer = ({ schema, column, prefix }) => {
4785
6558
  if (properties === undefined) {
4786
6559
  throw new Error(`properties is undefined when using ObjectInput`);
4787
6560
  }
4788
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: Object.keys(properties ?? {}).map((key) => {
6561
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "1", borderRadius: "md", borderWidth: "thin", borderColor: {
6562
+ base: "colorPalette.200",
6563
+ _dark: "colorPalette.800",
6564
+ }, children: Object.keys(properties ?? {}).map((key) => {
4789
6565
  return (
4790
6566
  // @ts-expect-error find suitable types
4791
6567
  jsxRuntime.jsx(ColumnViewer, { column: `${key}`,
4792
6568
  prefix: `${prefix}${column}.`,
4793
6569
  properties }, `form-objectviewer-${colLabel}-${key}`));
4794
- }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
6570
+ }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4795
6571
  };
4796
6572
 
4797
6573
  const RecordInput = ({ column, schema, prefix }) => {
4798
6574
  const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
4799
6575
  const { translate } = useSchemaContext();
4800
- const { required, gridColumn, gridRow } = schema;
6576
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4801
6577
  const isRequired = required?.some((columnId) => columnId === column);
4802
6578
  const entries = Object.entries(getValues(column) ?? {});
4803
6579
  const [showNewEntries, setShowNewEntries] = React.useState(false);
4804
6580
  const [newKey, setNewKey] = React.useState();
4805
6581
  const [newValue, setNewValue] = React.useState();
4806
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.fieldLabel`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
6582
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4807
6583
  return (jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
4808
6584
  const filtered = entries.filter(([target]) => {
4809
6585
  return target !== key;
@@ -4843,7 +6619,17 @@ const RecordInput = ({ column, schema, prefix }) => {
4843
6619
  setShowNewEntries(true);
4844
6620
  setNewKey(undefined);
4845
6621
  setNewValue(undefined);
4846
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.fieldRequired`) }))] }));
6622
+ }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
6623
+ };
6624
+
6625
+ const StringViewer = ({ column, schema, prefix, }) => {
6626
+ const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6627
+ const { translate } = useSchemaContext();
6628
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
6629
+ const isRequired = required?.some((columnId) => columnId === column);
6630
+ const colLabel = `${prefix}${column}`;
6631
+ const value = watch(colLabel);
6632
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsxRuntime.jsx(react.Text, { children: value }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
4847
6633
  };
4848
6634
 
4849
6635
  const TagViewer = ({ column, schema, prefix }) => {
@@ -4931,19 +6717,50 @@ const TagViewer = ({ column, schema, prefix }) => {
4931
6717
  }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
4932
6718
  };
4933
6719
 
4934
- const StringViewer = ({ column, schema, prefix, }) => {
6720
+ const TextAreaViewer = ({ column, schema, prefix, }) => {
4935
6721
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
4936
6722
  const { translate } = useSchemaContext();
4937
- const { required, gridColumn, gridRow } = schema;
6723
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4938
6724
  const isRequired = required?.some((columnId) => columnId === column);
4939
6725
  const colLabel = `${prefix}${column}`;
4940
6726
  const value = watch(colLabel);
4941
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsxRuntime.jsx(react.Text, { children: value }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }) }));
6727
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsxRuntime.jsx(react.Text, { whiteSpace: "pre-wrap", children: value }), " ", errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
6728
+ };
6729
+
6730
+ const TimeViewer = ({ column, schema, prefix }) => {
6731
+ const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6732
+ const { translate, timezone } = useSchemaContext();
6733
+ const { required, gridColumn = "span 12", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
6734
+ const isRequired = required?.some((columnId) => columnId === column);
6735
+ const colLabel = `${prefix}${column}`;
6736
+ const selectedDate = watch(colLabel);
6737
+ const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
6738
+ .tz(timezone)
6739
+ .isValid()
6740
+ ? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
6741
+ : "";
6742
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6743
+ gridRow, children: [jsxRuntime.jsx(react.Text, { children: displayedTime }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
6744
+ };
6745
+
6746
+ const DateTimeViewer = ({ column, schema, prefix }) => {
6747
+ const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6748
+ const { translate, timezone } = useSchemaContext();
6749
+ const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
6750
+ const isRequired = required?.some((columnId) => columnId === column);
6751
+ const colLabel = `${prefix}${column}`;
6752
+ const selectedDate = watch(colLabel);
6753
+ const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
6754
+ return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6755
+ gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
4942
6756
  };
4943
6757
 
4944
6758
  const SchemaViewer = ({ schema, prefix, column, }) => {
4945
6759
  const colSchema = schema;
4946
- const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
6760
+ const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
6761
+ if (variant === "custom-input") {
6762
+ return jsxRuntime.jsx(CustomViewer, { schema: colSchema, prefix, column });
6763
+ }
4947
6764
  if (type === "string") {
4948
6765
  if ((schema.enum ?? []).length > 0) {
4949
6766
  return jsxRuntime.jsx(EnumViewer, { schema: colSchema, prefix, column });
@@ -4952,9 +6769,18 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
4952
6769
  idPickerSanityCheck(column, foreign_key);
4953
6770
  return jsxRuntime.jsx(IdViewer, { schema: colSchema, prefix, column });
4954
6771
  }
4955
- if (variant === "date-picker") {
6772
+ if (format === "time") {
6773
+ return jsxRuntime.jsx(TimeViewer, { schema: colSchema, prefix, column });
6774
+ }
6775
+ if (format === "date") {
4956
6776
  return jsxRuntime.jsx(DateViewer, { schema: colSchema, prefix, column });
4957
6777
  }
6778
+ if (format === "date-time") {
6779
+ return jsxRuntime.jsx(DateTimeViewer, { schema: colSchema, prefix, column });
6780
+ }
6781
+ if (variant === "text-area") {
6782
+ return jsxRuntime.jsx(TextAreaViewer, { schema: colSchema, prefix, column });
6783
+ }
4958
6784
  return jsxRuntime.jsx(StringViewer, { schema: colSchema, prefix, column });
4959
6785
  }
4960
6786
  if (type === "number" || type === "integer") {
@@ -4980,6 +6806,15 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
4980
6806
  if (variant === "file-picker") {
4981
6807
  return jsxRuntime.jsx(FileViewer, { schema: colSchema, prefix, column });
4982
6808
  }
6809
+ if (variant === "enum-picker") {
6810
+ const { items } = schema;
6811
+ const { enum: enumItems } = items;
6812
+ const enumSchema = {
6813
+ type: "string",
6814
+ enum: enumItems,
6815
+ };
6816
+ return (jsxRuntime.jsx(EnumViewer, { isMultiple: true, schema: enumSchema, prefix, column }));
6817
+ }
4983
6818
  if (items) {
4984
6819
  return jsxRuntime.jsx(ArrayViewer, { schema: colSchema, prefix, column });
4985
6820
  }
@@ -5003,66 +6838,43 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
5003
6838
  };
5004
6839
 
5005
6840
  const SubmitButton = () => {
5006
- const { translate, setValidatedData, setIsError, setIsConfirming } = useSchemaContext();
6841
+ const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, requireConfirmation, onFormSubmit, } = useSchemaContext();
5007
6842
  const methods = reactHookForm.useFormContext();
5008
6843
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5009
6844
  const onValid = (data) => {
5010
- setValidatedData(data);
5011
- setIsError(false);
5012
- setIsConfirming(true);
6845
+ // const { isValid, errors } = validateData(data, schema);
6846
+ // if (!isValid) {
6847
+ // setError({
6848
+ // type: 'validation',
6849
+ // errors,
6850
+ // });
6851
+ // setIsError(true);
6852
+ // return;
6853
+ // }
6854
+ // If validation passes, check if confirmation is required
6855
+ if (requireConfirmation) {
6856
+ // Show confirmation (existing behavior)
6857
+ setValidatedData(data);
6858
+ setIsError(false);
6859
+ setIsConfirming(true);
6860
+ }
6861
+ else {
6862
+ // Skip confirmation and submit directly
6863
+ setValidatedData(data);
6864
+ setIsError(false);
6865
+ onFormSubmit(data);
6866
+ }
5013
6867
  };
5014
6868
  return (jsxRuntime.jsx(react.Button, { onClick: () => {
5015
6869
  methods.handleSubmit(onValid)();
5016
- }, formNoValidate: true, children: translate.t("submit") }));
6870
+ }, formNoValidate: true, children: translate.t('submit') }));
5017
6871
  };
5018
6872
 
5019
6873
  const FormBody = () => {
5020
- const { schema, requestUrl, order, ignore, include, onSubmit, rowNumber, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, } = useSchemaContext();
6874
+ const { schema, order, ignore, include, translate, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, onFormSubmit, } = useSchemaContext();
6875
+ const { showSubmitButton, showResetButton } = displayConfig;
5021
6876
  const methods = reactHookForm.useFormContext();
5022
6877
  const { properties } = schema;
5023
- const onBeforeSubmit = () => {
5024
- setIsSubmiting(true);
5025
- };
5026
- const onAfterSubmit = () => {
5027
- setIsSubmiting(false);
5028
- };
5029
- const onSubmitError = (error) => {
5030
- setIsError(true);
5031
- setError(error);
5032
- };
5033
- const onSubmitSuccess = () => {
5034
- setIsSuccess(true);
5035
- };
5036
- const defaultOnSubmit = async (promise) => {
5037
- try {
5038
- onBeforeSubmit();
5039
- await promise;
5040
- onSubmitSuccess();
5041
- }
5042
- catch (error) {
5043
- onSubmitError(error);
5044
- }
5045
- finally {
5046
- onAfterSubmit();
5047
- }
5048
- };
5049
- const defaultSubmitPromise = (data) => {
5050
- const options = {
5051
- method: "POST",
5052
- url: `${requestUrl}`,
5053
- data: clearEmptyString(data),
5054
- ...requestOptions,
5055
- };
5056
- return axios.request(options);
5057
- };
5058
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5059
- const onFormSubmit = async (data) => {
5060
- if (onSubmit === undefined) {
5061
- await defaultOnSubmit(defaultSubmitPromise(data));
5062
- return;
5063
- }
5064
- await defaultOnSubmit(onSubmit(data));
5065
- };
5066
6878
  const renderColumns = ({ order, keys, ignore, include, }) => {
5067
6879
  const included = include.length > 0 ? include : keys;
5068
6880
  const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
@@ -5077,38 +6889,42 @@ const FormBody = () => {
5077
6889
  include,
5078
6890
  });
5079
6891
  if (isSuccess) {
5080
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Title, { children: translate.t("submitSuccess") })] }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { onClick: async () => {
5081
- setIsError(false);
5082
- setIsSubmiting(false);
5083
- setIsSuccess(false);
5084
- setIsConfirming(false);
5085
- setValidatedData(undefined);
5086
- const data = await getUpdatedData();
5087
- methods.reset(data);
5088
- }, formNoValidate: true, children: translate.t("submitAgain") }) })] }));
6892
+ const resetHandler = async () => {
6893
+ setIsError(false);
6894
+ setIsSubmiting(false);
6895
+ setIsSuccess(false);
6896
+ setIsConfirming(false);
6897
+ setValidatedData(undefined);
6898
+ const data = await getUpdatedData();
6899
+ methods.reset(data);
6900
+ };
6901
+ if (customSuccessRenderer) {
6902
+ return customSuccessRenderer(resetHandler);
6903
+ }
6904
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t('submit_success') }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: 'end', children: jsxRuntime.jsx(react.Button, { onClick: resetHandler, formNoValidate: true, children: translate.t('submit_again') }) })] }));
5089
6905
  }
5090
6906
  if (isConfirming) {
5091
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat(${rowNumber ?? "auto-fit"}, auto)`, children: ordered.map((column) => {
6907
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
5092
6908
  return (jsxRuntime.jsx(ColumnViewer
5093
6909
  // @ts-expect-error find suitable types
5094
6910
  , {
5095
6911
  // @ts-expect-error find suitable types
5096
6912
  properties: properties, prefix: ``, column }, `form-viewer-${column}`));
5097
- }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: "end", gap: "2", children: [jsxRuntime.jsx(react.Button, { onClick: () => {
6913
+ }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: '2', children: [jsxRuntime.jsx(react.Button, { onClick: () => {
5098
6914
  setIsConfirming(false);
5099
- }, variant: "subtle", children: translate.t("cancel") }), jsxRuntime.jsx(react.Button, { onClick: () => {
6915
+ }, variant: 'subtle', children: translate.t('cancel') }), jsxRuntime.jsx(react.Button, { onClick: () => {
5100
6916
  onFormSubmit(validatedData);
5101
- }, children: translate.t("confirm") })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(react.Alert.Root, { status: "error", children: jsxRuntime.jsx(react.Alert.Title, { children: jsxRuntime.jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxRuntime.jsxs(AccordionItem, { value: "b", children: [jsxRuntime.jsxs(AccordionItemTrigger, { children: [jsxRuntime.jsx(react.Alert.Indicator, {}), `${error}`] }), jsxRuntime.jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) }) }) }))] }));
6917
+ }, children: translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
5102
6918
  }
5103
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: "column", gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat(${rowNumber ?? "auto-fit"}, auto)`, children: ordered.map((column) => {
6919
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
5104
6920
  return (jsxRuntime.jsx(ColumnRenderer
5105
6921
  // @ts-expect-error find suitable types
5106
6922
  , {
5107
6923
  // @ts-expect-error find suitable types
5108
- properties: properties, prefix: ``, column }, `form-input-${column}`));
5109
- }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: "end", gap: "2", children: [jsxRuntime.jsx(react.Button, { onClick: () => {
6924
+ properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
6925
+ }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsxRuntime.jsx(react.Button, { onClick: () => {
5110
6926
  methods.reset();
5111
- }, variant: "subtle", children: translate.t("reset") }), jsxRuntime.jsx(SubmitButton, {})] })] }));
6927
+ }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
5112
6928
  };
5113
6929
 
5114
6930
  const FormTitle = () => {
@@ -5117,15 +6933,19 @@ const FormTitle = () => {
5117
6933
  };
5118
6934
 
5119
6935
  const DefaultForm = ({ formConfig, }) => {
5120
- return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
6936
+ const { showTitle } = formConfig.displayConfig ?? {};
6937
+ return (jsxRuntime.jsx(FormRoot, { ...formConfig, children: jsxRuntime.jsxs(react.Grid, { gap: "2", children: [showTitle && jsxRuntime.jsx(FormTitle, {}), jsxRuntime.jsx(FormBody, {})] }) }));
5121
6938
  };
5122
6939
 
5123
- const useForm = ({ preLoadedValues, keyPrefix }) => {
6940
+ const useForm = ({ preLoadedValues, keyPrefix, namespace, schema, }) => {
5124
6941
  const form = reactHookForm.useForm({
5125
6942
  values: preLoadedValues,
6943
+ resolver: schema ? ajvResolver(schema) : undefined,
6944
+ mode: 'onBlur',
6945
+ reValidateMode: 'onBlur',
5126
6946
  });
5127
6947
  const [idMap, setIdMap] = React.useState({});
5128
- const translate = reactI18next.useTranslation("", { keyPrefix });
6948
+ const translate = reactI18next.useTranslation(namespace || '', { keyPrefix });
5129
6949
  return {
5130
6950
  form,
5131
6951
  idMap,
@@ -5134,6 +6954,250 @@ const useForm = ({ preLoadedValues, keyPrefix }) => {
5134
6954
  };
5135
6955
  };
5136
6956
 
6957
+ /**
6958
+ * Type definitions for error message configuration
6959
+ */
6960
+ /**
6961
+ * Schema-level error message builder
6962
+ *
6963
+ * Builds a complete errorMessage object compatible with ajv-errors plugin.
6964
+ * Supports both i18n translation keys and plain string messages.
6965
+ *
6966
+ * @param config - Error message configuration
6967
+ * @returns Complete errorMessage object for JSON Schema
6968
+ *
6969
+ * @example
6970
+ * ```typescript
6971
+ * // Simple required field errors
6972
+ * const errorMessage = buildErrorMessages({
6973
+ * required: {
6974
+ * username: "Username is required",
6975
+ * email: "user.email.field_required" // i18n key
6976
+ * }
6977
+ * });
6978
+ *
6979
+ * // With validation rules
6980
+ * const errorMessage = buildErrorMessages({
6981
+ * required: {
6982
+ * password: "Password is required"
6983
+ * },
6984
+ * properties: {
6985
+ * password: {
6986
+ * minLength: "Password must be at least 8 characters",
6987
+ * pattern: "Password must contain letters and numbers"
6988
+ * },
6989
+ * age: {
6990
+ * minimum: "Must be 18 or older",
6991
+ * maximum: "Must be under 120"
6992
+ * }
6993
+ * }
6994
+ * });
6995
+ *
6996
+ * // With global fallbacks
6997
+ * const errorMessage = buildErrorMessages({
6998
+ * required: {
6999
+ * email: "Email is required"
7000
+ * },
7001
+ * minLength: "This field is too short", // applies to all fields
7002
+ * minimum: "Value is too small"
7003
+ * });
7004
+ * ```
7005
+ */
7006
+ const buildErrorMessages = (config) => {
7007
+ const result = {};
7008
+ // Add required field errors
7009
+ if (config.required && Object.keys(config.required).length > 0) {
7010
+ result.required = config.required;
7011
+ }
7012
+ // Add field-specific validation errors
7013
+ if (config.properties && Object.keys(config.properties).length > 0) {
7014
+ result.properties = config.properties;
7015
+ }
7016
+ // Add global fallback error messages
7017
+ const globalKeys = [
7018
+ 'minLength',
7019
+ 'maxLength',
7020
+ 'pattern',
7021
+ 'minimum',
7022
+ 'maximum',
7023
+ 'multipleOf',
7024
+ 'format',
7025
+ 'type',
7026
+ 'enum',
7027
+ ];
7028
+ globalKeys.forEach((key) => {
7029
+ if (config[key]) {
7030
+ result[key] = config[key];
7031
+ }
7032
+ });
7033
+ return result;
7034
+ };
7035
+ /**
7036
+ * Converts buildErrorMessages result to ajv-errors compatible format
7037
+ */
7038
+ const convertToAjvErrorsFormat = (errorMessages) => {
7039
+ const result = {};
7040
+ // Convert required field errors
7041
+ if (errorMessages.required) {
7042
+ result.required = errorMessages.required;
7043
+ }
7044
+ // Convert properties errors to ajv-errors format
7045
+ if (errorMessages.properties) {
7046
+ result.properties = {};
7047
+ Object.keys(errorMessages.properties).forEach((fieldName) => {
7048
+ const fieldErrors = errorMessages.properties[fieldName];
7049
+ result.properties[fieldName] = {};
7050
+ Object.keys(fieldErrors).forEach((keyword) => {
7051
+ result.properties[fieldName][keyword] =
7052
+ fieldErrors[keyword];
7053
+ });
7054
+ });
7055
+ }
7056
+ // Add global fallback errors
7057
+ const globalKeys = [
7058
+ 'minLength',
7059
+ 'maxLength',
7060
+ 'pattern',
7061
+ 'minimum',
7062
+ 'maximum',
7063
+ 'multipleOf',
7064
+ 'format',
7065
+ 'type',
7066
+ 'enum',
7067
+ ];
7068
+ globalKeys.forEach((key) => {
7069
+ if (errorMessages[key]) {
7070
+ result[key] = errorMessages[key];
7071
+ }
7072
+ });
7073
+ return result;
7074
+ };
7075
+ /**
7076
+ * Helper function to build required field errors
7077
+ *
7078
+ * Simplifies creating required field error messages, especially useful
7079
+ * for generating i18n translation keys following a pattern.
7080
+ *
7081
+ * @param fields - Array of required field names
7082
+ * @param messageOrGenerator - Either a string template or function to generate messages
7083
+ * @returns Required field error configuration
7084
+ *
7085
+ * @example
7086
+ * ```typescript
7087
+ * // Plain string messages
7088
+ * const required = buildRequiredErrors(
7089
+ * ["username", "email", "password"],
7090
+ * (field) => `${field} is required`
7091
+ * );
7092
+ * // Result: { username: "username is required", email: "email is required", ... }
7093
+ *
7094
+ * // i18n translation keys
7095
+ * const required = buildRequiredErrors(
7096
+ * ["username", "email"],
7097
+ * (field) => `user.${field}.field_required`
7098
+ * );
7099
+ * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
7100
+ *
7101
+ * // Same message for all fields
7102
+ * const required = buildRequiredErrors(
7103
+ * ["username", "email"],
7104
+ * "This field is required"
7105
+ * );
7106
+ * // Result: { username: "This field is required", email: "This field is required" }
7107
+ *
7108
+ * // With keyPrefix for i18n
7109
+ * const required = buildRequiredErrors(
7110
+ * ["username", "email"],
7111
+ * (field) => `${field}.field_required`,
7112
+ * "user"
7113
+ * );
7114
+ * // Result: { username: "user.username.field_required", email: "user.email.field_required" }
7115
+ * ```
7116
+ */
7117
+ const buildRequiredErrors = (fields, messageOrGenerator, keyPrefix = '') => {
7118
+ const result = {};
7119
+ fields.forEach((field) => {
7120
+ if (typeof messageOrGenerator === 'function') {
7121
+ const message = messageOrGenerator(field);
7122
+ result[field] = keyPrefix ? `${keyPrefix}.${message}` : message;
7123
+ }
7124
+ else {
7125
+ result[field] = messageOrGenerator;
7126
+ }
7127
+ });
7128
+ return result;
7129
+ };
7130
+ /**
7131
+ * Helper function to build field-specific validation errors
7132
+ *
7133
+ * Creates property-specific error messages for multiple fields at once.
7134
+ *
7135
+ * @param config - Maps field names to their validation error configurations
7136
+ * @returns Properties error configuration
7137
+ *
7138
+ * @example
7139
+ * ```typescript
7140
+ * const properties = buildFieldErrors({
7141
+ * username: {
7142
+ * minLength: "Username must be at least 3 characters",
7143
+ * pattern: "Username can only contain letters and numbers"
7144
+ * },
7145
+ * age: {
7146
+ * minimum: "Must be 18 or older",
7147
+ * maximum: "Must be under 120"
7148
+ * },
7149
+ * email: {
7150
+ * format: "Please enter a valid email address"
7151
+ * }
7152
+ * });
7153
+ * ```
7154
+ */
7155
+ const buildFieldErrors = (config) => {
7156
+ return config;
7157
+ };
7158
+ /**
7159
+ * Helper function to create a complete error message configuration in one call
7160
+ *
7161
+ * Convenient wrapper that combines required and validation errors.
7162
+ *
7163
+ * @param required - Required field error messages
7164
+ * @param properties - Field-specific validation error messages
7165
+ * @param globalFallbacks - Global fallback error messages
7166
+ * @returns Complete error message configuration
7167
+ *
7168
+ * @example
7169
+ * ```typescript
7170
+ * const errorMessage = createErrorMessage(
7171
+ * {
7172
+ * username: "Username is required",
7173
+ * email: "Email is required"
7174
+ * },
7175
+ * {
7176
+ * username: {
7177
+ * minLength: "Username must be at least 3 characters"
7178
+ * },
7179
+ * email: {
7180
+ * format: "Please enter a valid email"
7181
+ * }
7182
+ * },
7183
+ * {
7184
+ * minLength: "This field is too short",
7185
+ * format: "Invalid format"
7186
+ * }
7187
+ * );
7188
+ * ```
7189
+ */
7190
+ const createErrorMessage = (required, properties, globalFallbacks) => {
7191
+ const config = {
7192
+ required,
7193
+ properties,
7194
+ };
7195
+ if (globalFallbacks) {
7196
+ Object.assign(config, globalFallbacks);
7197
+ }
7198
+ return buildErrorMessages(config);
7199
+ };
7200
+
5137
7201
  const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) => {
5138
7202
  if (!selectable) {
5139
7203
  return [...selectedDates];
@@ -5157,12 +7221,12 @@ exports.DataTableServer = DataTableServer;
5157
7221
  exports.DefaultCardTitle = DefaultCardTitle;
5158
7222
  exports.DefaultForm = DefaultForm;
5159
7223
  exports.DefaultTable = DefaultTable;
7224
+ exports.DefaultTableServer = DefaultTableServer;
5160
7225
  exports.DensityToggleButton = DensityToggleButton;
5161
7226
  exports.EditSortingButton = EditSortingButton;
5162
7227
  exports.EmptyState = EmptyState$1;
5163
7228
  exports.ErrorAlert = ErrorAlert;
5164
7229
  exports.FilterDialog = FilterDialog;
5165
- exports.FilterOptions = FilterOptions;
5166
7230
  exports.FormBody = FormBody;
5167
7231
  exports.FormRoot = FormRoot;
5168
7232
  exports.FormTitle = FormTitle;
@@ -5192,6 +7256,11 @@ exports.TableSorter = TableSorter;
5192
7256
  exports.TableViewer = TableViewer;
5193
7257
  exports.TextCell = TextCell;
5194
7258
  exports.ViewDialog = ViewDialog;
7259
+ exports.buildErrorMessages = buildErrorMessages;
7260
+ exports.buildFieldErrors = buildFieldErrors;
7261
+ exports.buildRequiredErrors = buildRequiredErrors;
7262
+ exports.convertToAjvErrorsFormat = convertToAjvErrorsFormat;
7263
+ exports.createErrorMessage = createErrorMessage;
5195
7264
  exports.getColumns = getColumns;
5196
7265
  exports.getMultiDates = getMultiDates;
5197
7266
  exports.getRangeDates = getRangeDates;