@bsol-oss/react-datatable5 12.0.0-beta.7 → 12.0.0-beta.71

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 (53) hide show
  1. package/README.md +192 -0
  2. package/dist/index.d.ts +282 -83
  3. package/dist/index.js +1637 -475
  4. package/dist/index.mjs +1645 -483
  5. package/dist/types/components/DataTable/DataTable.d.ts +3 -1
  6. package/dist/types/components/DataTable/DataTableServer.d.ts +6 -4
  7. package/dist/types/components/DataTable/DefaultTable.d.ts +6 -9
  8. package/dist/types/components/DataTable/context/DataTableContext.d.ts +21 -3
  9. package/dist/types/components/DataTable/context/useDataTableContext.d.ts +2 -2
  10. package/dist/types/components/DataTable/controls/ReloadButton.d.ts +1 -2
  11. package/dist/types/components/DataTable/controls/ResetFilteringButton.d.ts +1 -4
  12. package/dist/types/components/DataTable/controls/ResetSelectionButton.d.ts +1 -4
  13. package/dist/types/components/DataTable/controls/ResetSortingButton.d.ts +1 -4
  14. package/dist/types/components/DataTable/controls/TableControls.d.ts +10 -2
  15. package/dist/types/components/DataTable/display/TableBody.d.ts +1 -2
  16. package/dist/types/components/DataTable/display/TableCardContainer.d.ts +6 -3
  17. package/dist/types/components/DataTable/display/TableDataDisplay.d.ts +6 -1
  18. package/dist/types/components/DataTable/display/TableFooter.d.ts +1 -5
  19. package/dist/types/components/DataTable/display/TableHeader.d.ts +46 -8
  20. package/dist/types/components/DataTable/useDataTableServer.d.ts +55 -3
  21. package/dist/types/components/DatePicker/DatePicker.d.ts +23 -0
  22. package/dist/types/components/DatePicker/DateTimePicker.d.ts +11 -0
  23. package/dist/types/components/DatePicker/DurationPicker.d.ts +12 -0
  24. package/dist/types/components/DatePicker/IsoTimePicker.d.ts +16 -0
  25. package/dist/types/components/DatePicker/PickerDemo.d.ts +1 -0
  26. package/dist/types/components/DatePicker/UniversalPicker.d.ts +9 -0
  27. package/dist/types/components/DatePicker/index.d.ts +7 -0
  28. package/dist/types/components/Filter/TagFilter.d.ts +5 -1
  29. package/dist/types/components/Form/SchemaFormContext.d.ts +8 -1
  30. package/dist/types/components/Form/components/core/DefaultForm.d.ts +1 -0
  31. package/dist/types/components/Form/components/core/FormRoot.d.ts +9 -2
  32. package/dist/types/components/Form/components/fields/CustomInput.d.ts +8 -0
  33. package/dist/types/components/Form/components/fields/DatePicker.d.ts +2 -7
  34. package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +2 -0
  35. package/dist/types/components/Form/components/fields/EnumPicker.d.ts +2 -1
  36. package/dist/types/components/Form/components/fields/FilePicker.d.ts +2 -5
  37. package/dist/types/components/Form/components/fields/StringInputField.d.ts +19 -5
  38. package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +12 -0
  39. package/dist/types/components/Form/components/fields/TimePicker.d.ts +7 -0
  40. package/dist/types/components/Form/components/fields/types.d.ts +6 -0
  41. package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +19 -1
  42. package/dist/types/components/Form/components/viewers/CustomViewer.d.ts +8 -0
  43. package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +7 -0
  44. package/dist/types/components/Form/components/viewers/TextAreaViewer.d.ts +12 -0
  45. package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +7 -0
  46. package/dist/types/components/Form/utils/translateWrapper.d.ts +6 -0
  47. package/dist/types/components/Form/utils/useFormI18n.d.ts +53 -0
  48. package/dist/types/components/Form/utils/validateData.d.ts +9 -0
  49. package/dist/types/components/Form/utils/validation.d.ts +104 -0
  50. package/dist/types/components/TextArea/TextArea.d.ts +22 -0
  51. package/dist/types/components/TimePicker/TimePicker.d.ts +21 -0
  52. package/dist/types/index.d.ts +18 -2
  53. package/package.json +9 -2
package/dist/index.mjs CHANGED
@@ -1,26 +1,26 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Checkbox as Checkbox$1, Table as Table$1, Tooltip as Tooltip$1, Group, InputElement, Icon, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, List, Accordion, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading } from '@chakra-ui/react';
2
+ import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Group, InputElement, Tooltip as Tooltip$1, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Accordion, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Center, Heading } from '@chakra-ui/react';
3
3
  import { AiOutlineColumnWidth } from 'react-icons/ai';
4
4
  import * as React from 'react';
5
- import React__default, { createContext, useContext, useState, useEffect, useRef } from 'react';
5
+ import React__default, { createContext, useContext, useState, useEffect, useRef, forwardRef } from 'react';
6
6
  import { LuX, LuCheck, LuChevronRight, LuChevronDown } from 'react-icons/lu';
7
- import { MdOutlineSort, MdFilterAlt, MdSearch, MdClose, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist } from 'react-icons/md';
8
- import { FaUpDown, FaGripLinesVertical } from 'react-icons/fa6';
7
+ import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist, MdDateRange } from 'react-icons/md';
8
+ import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
9
9
  import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
10
- import { CgClose } from 'react-icons/cg';
10
+ import { CgClose, CgTrash } from 'react-icons/cg';
11
11
  import Dayzed from '@bsol-oss/dayzed-react19';
12
12
  import { HiMiniEllipsisHorizontal, HiChevronLeft, HiChevronRight } from 'react-icons/hi2';
13
- import { IoMdEye, IoMdCheckbox } from 'react-icons/io';
13
+ import { IoMdEye, IoMdCheckbox, IoMdClock } from 'react-icons/io';
14
14
  import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
15
15
  import { bind, bindAll } from 'bind-event-listener';
16
16
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
17
17
  import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
18
18
  import rafSchd from 'raf-schd';
19
19
  import invariant from 'tiny-invariant';
20
- import { HiColorSwatch } from 'react-icons/hi';
20
+ import { HiColorSwatch, HiOutlineInformationCircle } from 'react-icons/hi';
21
21
  import { flexRender, makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel, createColumnHelper } from '@tanstack/react-table';
22
22
  import { rankItem } from '@tanstack/match-sorter-utils';
23
- import { BsExclamationCircleFill } from 'react-icons/bs';
23
+ import { BsExclamationCircleFill, BsClock } from 'react-icons/bs';
24
24
  import { useDebounce } from '@uidotdev/usehooks';
25
25
  import { useQueryClient, useQuery } from '@tanstack/react-query';
26
26
  import { IoReload } from 'react-icons/io5';
@@ -28,7 +28,12 @@ import { GrAscend, GrDescend } from 'react-icons/gr';
28
28
  import { useTranslation } from 'react-i18next';
29
29
  import axios from 'axios';
30
30
  import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
31
+ import Ajv from 'ajv';
32
+ import addFormats from 'ajv-formats';
33
+ import addErrors from 'ajv-errors';
31
34
  import dayjs from 'dayjs';
35
+ import utc from 'dayjs/plugin/utc';
36
+ import timezone from 'dayjs/plugin/timezone';
32
37
  import { TiDeleteOutline } from 'react-icons/ti';
33
38
 
34
39
  const DataTableContext = createContext({
@@ -37,6 +42,56 @@ const DataTableContext = createContext({
37
42
  setGlobalFilter: () => { },
38
43
  type: "client",
39
44
  translate: {},
45
+ data: [],
46
+ columns: [],
47
+ columnOrder: [],
48
+ columnFilters: [],
49
+ density: "sm",
50
+ sorting: [],
51
+ setPagination: function () {
52
+ throw new Error("Function not implemented.");
53
+ },
54
+ setSorting: function () {
55
+ throw new Error("Function not implemented.");
56
+ },
57
+ setColumnFilters: function () {
58
+ throw new Error("Function not implemented.");
59
+ },
60
+ setRowSelection: function () {
61
+ throw new Error("Function not implemented.");
62
+ },
63
+ setColumnOrder: function () {
64
+ throw new Error("Function not implemented.");
65
+ },
66
+ setDensity: function () {
67
+ throw new Error("Function not implemented.");
68
+ },
69
+ setColumnVisibility: function () {
70
+ throw new Error("Function not implemented.");
71
+ },
72
+ pagination: {
73
+ pageIndex: 0,
74
+ pageSize: 10,
75
+ },
76
+ rowSelection: {},
77
+ columnVisibility: {},
78
+ tableLabel: {
79
+ view: "View",
80
+ edit: "Edit",
81
+ filterButtonText: "Filter",
82
+ filterTitle: "Filter",
83
+ filterReset: "Reset",
84
+ filterClose: "Close",
85
+ reloadTooltip: "Reload",
86
+ reloadButtonText: "Reload",
87
+ resetSelection: "Reset Selection",
88
+ resetSorting: "Reset Sorting",
89
+ rowCountText: "Row Count",
90
+ hasErrorText: "Has Error",
91
+ globalFilterPlaceholder: "Search",
92
+ trueLabel: "True",
93
+ falseLabel: "False",
94
+ },
40
95
  });
41
96
 
42
97
  const useDataTableContext = () => {
@@ -92,11 +147,13 @@ const TableSorter = () => {
92
147
  }) }))) }));
93
148
  };
94
149
 
95
- const ResetSortingButton = ({ text = "Reset Sorting", }) => {
150
+ const ResetSortingButton = () => {
96
151
  const { table } = useDataTableContext();
152
+ const { tableLabel } = useDataTableContext();
153
+ const { resetSorting } = tableLabel;
97
154
  return (jsx(Button$1, { onClick: () => {
98
155
  table.resetSorting();
99
- }, children: text }));
156
+ }, children: resetSorting }));
100
157
  };
101
158
 
102
159
  const EditSortingButton = ({ text, icon = jsx(MdOutlineSort, {}), title = "Edit Sorting", }) => {
@@ -124,7 +181,7 @@ const monthNamesFull = [
124
181
  "November",
125
182
  "December",
126
183
  ];
127
- const weekdayNamesShort$1 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
184
+ const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
128
185
  function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, selected = [], firstDayOfWeek = 0, }) {
129
186
  const [hoveredDate, setHoveredDate] = useState();
130
187
  const onMouseLeave = () => {
@@ -159,7 +216,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
159
216
  offset: 12,
160
217
  }), children: ">>" })] }), jsx(Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", gap: 4, children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: "center", children: [monthNamesFull[calendar.month], " ", calendar.year] }), jsx(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
161
218
  const weekday = (weekdayNum + firstDayOfWeek) % 7;
162
- return (jsx(Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort$1[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
219
+ return (jsx(Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
163
220
  }) }), jsx(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: calendar.weeks.map((week, windex) => week.map((dateObj, index) => {
164
221
  const key = `${calendar.month}${calendar.year}${windex}${index}`;
165
222
  if (!dateObj) {
@@ -280,8 +337,17 @@ const Tag = React.forwardRef(function Tag(props, ref) {
280
337
  return (jsxs(Tag$1.Root, { ref: ref, ...rest, children: [startElement && (jsx(Tag$1.StartElement, { children: startElement })), jsx(Tag$1.Label, { children: children }), endElement && (jsx(Tag$1.EndElement, { children: endElement })), closable && (jsx(Tag$1.EndElement, { children: jsx(Tag$1.CloseTrigger, { onClick: onClose }) }))] }));
281
338
  });
282
339
 
283
- const TagFilter = ({ availableTags, selectedTags, onTagChange, }) => {
340
+ const TagFilter = ({ availableTags, selectedTags, onTagChange, selectOne = false, }) => {
284
341
  const toggleTag = (tag) => {
342
+ if (selectOne) {
343
+ if (selectedTags.includes(tag)) {
344
+ onTagChange([]);
345
+ }
346
+ else {
347
+ onTagChange([tag]);
348
+ }
349
+ return;
350
+ }
285
351
  if (selectedTags.includes(tag)) {
286
352
  onTagChange(selectedTags.filter((t) => t !== tag));
287
353
  }
@@ -289,10 +355,14 @@ const TagFilter = ({ availableTags, selectedTags, onTagChange, }) => {
289
355
  onTagChange([...selectedTags, tag]);
290
356
  }
291
357
  };
292
- return (jsx(Flex, { flexFlow: "wrap", p: "0.5rem", gap: "0.5rem", children: availableTags.map((tag) => (jsx(Tag, { variant: selectedTags.includes(tag) ? "solid" : "outline", cursor: "pointer", closable: selectedTags.includes(tag) ? true : undefined, onClick: () => toggleTag(tag), children: tag }))) }));
358
+ return (jsx(Flex, { flexFlow: "wrap", p: "0.5rem", gap: "0.5rem", children: availableTags.map((tag) => {
359
+ const { label, value } = tag;
360
+ return (jsx(Tag, { variant: selectedTags.includes(value) ? "solid" : "outline", cursor: "pointer", closable: selectedTags.includes(value) ? true : undefined, onClick: () => toggleTag(value), children: label ?? value }));
361
+ }) }));
293
362
  };
294
363
 
295
364
  const Filter = ({ column }) => {
365
+ const { tableLabel } = useDataTableContext();
296
366
  const { filterVariant } = column.columnDef.meta ?? {};
297
367
  const displayName = column.columnDef.meta?.displayName ?? column.id;
298
368
  const filterOptions = column.columnDef.meta?.filterOptions ?? [];
@@ -307,10 +377,14 @@ const Filter = ({ column }) => {
307
377
  if (filterVariant === "select") {
308
378
  return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(RadioGroup, { value: column.getFilterValue() ? String(column.getFilterValue()) : "", onValueChange: (details) => {
309
379
  column.setFilterValue(details.value);
310
- }, children: jsx(Flex, { flexFlow: "wrap", gap: "0.5rem", children: filterOptions.map((item) => (jsx(Radio, { value: item, children: item }, item))) }) })] }, column.id));
380
+ }, children: jsxs(Flex, { flexFlow: "wrap", gap: "0.5rem", children: [filterOptions.length === 0 && jsx(Text, { children: "No filter options" }), filterOptions.length > 0 &&
381
+ filterOptions.map((item) => (jsx(Radio, { value: item.value, children: item.label }, item.value)))] }) })] }, column.id));
311
382
  }
312
383
  if (filterVariant === "tag") {
313
- return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: filterOptions, selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
384
+ return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: filterOptions.map((item) => ({
385
+ label: item.label,
386
+ value: item.value,
387
+ })), selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
314
388
  if (tags.length === 0) {
315
389
  return column.setFilterValue(undefined);
316
390
  }
@@ -318,7 +392,11 @@ const Filter = ({ column }) => {
318
392
  } })] }, column.id));
319
393
  }
320
394
  if (filterVariant === "boolean") {
321
- return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: ["true", "false"], selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
395
+ const { trueLabel, falseLabel } = tableLabel;
396
+ return (jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(Text, { children: displayName }), jsx(TagFilter, { availableTags: [
397
+ { label: trueLabel, value: "true" },
398
+ { label: falseLabel, value: "false" },
399
+ ], selectedTags: (column.getFilterValue() ?? []), onTagChange: (tags) => {
322
400
  if (tags.length === 0) {
323
401
  return column.setFilterValue(undefined);
324
402
  }
@@ -373,17 +451,20 @@ const TableFilter = () => {
373
451
  }) }));
374
452
  };
375
453
 
376
- const ResetFilteringButton = ({ text = "Reset Filtering", }) => {
454
+ const ResetFilteringButton = () => {
377
455
  const { table } = useDataTableContext();
456
+ const { tableLabel } = useDataTableContext();
457
+ const { filterReset } = tableLabel;
378
458
  return (jsx(Button$1, { onClick: () => {
379
459
  table.resetColumnFilters();
380
- }, children: text }));
460
+ }, children: filterReset }));
381
461
  };
382
462
 
383
463
  const FilterDialog = ({ icon = jsx(MdFilterAlt, {}), }) => {
384
464
  const filterModal = useDisclosure();
385
- const { translate } = useDataTableContext();
386
- return (jsxs(DialogRoot, { size: ["full", "full", "md", "md"], open: filterModal.open, children: [jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: filterModal.onOpen, children: [icon, " ", translate.t("filterDialog.buttonText")] }) }), jsxs(DialogContent, { children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: translate.t("filterDialog.title") }) }), jsx(DialogBody, { display: "flex", flexFlow: "column", children: jsx(TableFilter, {}) }), jsxs(DialogFooter, { children: [jsx(ResetFilteringButton, { text: translate.t("filterDialog.reset") }), jsx(Button$1, { onClick: filterModal.onClose, variant: "subtle", children: translate.t("filterDialog.close") })] }), jsx(DialogCloseTrigger, { onClick: filterModal.onClose })] })] }));
465
+ const { tableLabel } = useDataTableContext();
466
+ const { filterButtonText, filterTitle, filterClose } = tableLabel;
467
+ return (jsxs(DialogRoot, { size: ["full", "full", "md", "md"], open: filterModal.open, children: [jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: filterModal.onOpen, children: [icon, " ", filterButtonText] }) }), jsxs(DialogContent, { children: [jsx(DialogHeader, { children: jsx(DialogTitle, { children: filterTitle }) }), jsx(DialogBody, { display: "flex", flexFlow: "column", children: jsx(TableFilter, {}) }), jsxs(DialogFooter, { children: [jsx(ResetFilteringButton, {}), jsx(Button$1, { onClick: filterModal.onClose, variant: "subtle", children: filterClose })] }), jsx(DialogCloseTrigger, { onClick: filterModal.onClose })] })] }));
387
468
  };
388
469
 
389
470
  const MenuContent = React.forwardRef(function MenuContent(props, ref) {
@@ -502,11 +583,13 @@ const Pagination = () => {
502
583
  }, children: jsxs(HStack, { children: [jsx(PaginationPrevTrigger, {}), jsx(PaginationItems, {}), jsx(PaginationNextTrigger, {})] }) }));
503
584
  };
504
585
 
505
- const ResetSelectionButton = ({ text = "Reset Selection", }) => {
586
+ const ResetSelectionButton = () => {
506
587
  const { table } = useDataTableContext();
588
+ const { tableLabel } = useDataTableContext();
589
+ const { resetSelection } = tableLabel;
507
590
  return (jsx(Button$1, { onClick: () => {
508
591
  table.resetRowSelection();
509
- }, children: text }));
592
+ }, children: resetSelection }));
510
593
  };
511
594
 
512
595
  const RowCountText = () => {
@@ -2421,8 +2504,8 @@ CheckboxCard$1.Indicator;
2421
2504
  function ColumnCard({ columnId }) {
2422
2505
  const ref = useRef(null);
2423
2506
  const [dragging, setDragging] = useState(false); // NEW
2424
- const { table } = useDataTableContext();
2425
- const displayName = columnId;
2507
+ const { table, translate } = useDataTableContext();
2508
+ const displayName = translate.t(columnId);
2426
2509
  const column = table.getColumn(columnId);
2427
2510
  invariant(column);
2428
2511
  useEffect(() => {
@@ -2437,7 +2520,7 @@ function ColumnCard({ columnId }) {
2437
2520
  onDrop: () => setDragging(false), // NEW
2438
2521
  });
2439
2522
  }, [columnId, table]);
2440
- return (jsxs(Grid, { ref: ref, templateColumns: "auto 1fr", gap: "0.5rem", alignItems: "center", style: dragging ? { opacity: 0.4 } : {}, children: [jsx(Flex, { alignItems: "center", padding: "0", cursor: "grab", children: jsx(FaGripLinesVertical, { color: "gray.400" }) }), jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: jsx(CheckboxCard, { variant: "surface", label: displayName, checked: column.getIsVisible(), onChange: column.getToggleVisibilityHandler() }) })] }));
2523
+ return (jsxs(Grid, { ref: ref, templateColumns: "auto 1fr", gap: "0.5rem", alignItems: "center", style: dragging ? { opacity: 0.4 } : {}, children: [jsx(Flex, { alignItems: "center", padding: "0", cursor: "grab", children: jsx(FaGripLinesVertical, { color: "colorPalette.400" }) }), jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: jsx(CheckboxCard, { variant: "surface", label: displayName, checked: column.getIsVisible(), onChange: column.getToggleVisibilityHandler() }) })] }));
2441
2524
  }
2442
2525
  function CardContainer({ location, children }) {
2443
2526
  const ref = useRef(null);
@@ -2456,7 +2539,6 @@ function CardContainer({ location, children }) {
2456
2539
  onDrop: () => setIsDraggedOver(false),
2457
2540
  });
2458
2541
  }, [location]);
2459
- // const isDark = (location + location) % 2 === 1;
2460
2542
  function getColor(isDraggedOver) {
2461
2543
  if (isDraggedOver) {
2462
2544
  return {
@@ -2466,7 +2548,6 @@ function CardContainer({ location, children }) {
2466
2548
  },
2467
2549
  };
2468
2550
  }
2469
- // return isDark ? "lightgrey" : "white";
2470
2551
  return {
2471
2552
  backgroundColor: undefined,
2472
2553
  _dark: {
@@ -2517,8 +2598,9 @@ const TableViewer = () => {
2517
2598
 
2518
2599
  const ViewDialog = ({ icon = jsx(IoMdEye, {}) }) => {
2519
2600
  const viewModel = useDisclosure();
2520
- const { translate } = useDataTableContext();
2521
- return (jsxs(DialogRoot, { children: [jsx(DialogBackdrop, {}), jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", translate.t("viewDialog.buttonText")] }) }), jsxs(DialogContent, { children: [jsx(DialogCloseTrigger, {}), jsx(DialogHeader, { children: jsx(DialogTitle, { children: translate.t("viewDialog.title") }) }), jsx(DialogBody, { children: jsx(TableViewer, {}) }), jsx(DialogFooter, {})] })] }));
2601
+ const { tableLabel } = useDataTableContext();
2602
+ const { view } = tableLabel;
2603
+ return (jsxs(DialogRoot, { children: [jsx(DialogBackdrop, {}), jsx(DialogTrigger, { asChild: true, children: jsxs(Button$1, { as: Box, variant: "ghost", onClick: viewModel.onOpen, children: [icon, " ", view] }) }), jsxs(DialogContent, { children: [jsx(DialogCloseTrigger, {}), jsx(DialogHeader, { children: jsx(DialogTitle, { children: view }) }), jsx(DialogBody, { children: jsx(TableViewer, {}) }), jsx(DialogFooter, {})] })] }));
2522
2604
  };
2523
2605
 
2524
2606
  const CardHeader = ({ row, imageColumnId = undefined, titleColumnId = undefined, tagColumnId = undefined, tagIcon = undefined, showTag = true, imageProps = {}, }) => {
@@ -2569,7 +2651,7 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = "", }) => {
2569
2651
  return jsx(Fragment, { children: "null" });
2570
2652
  }
2571
2653
  return (jsx(Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
2572
- return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "gray.400", children: getColumn({ field }) }), typeof value === "object" ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsx(Text, { children: JSON.stringify(value) }))] }, field));
2654
+ return (jsxs(Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsx(Text, { color: "colorPalette.400", children: getColumn({ field }) }), typeof value === "object" ? (jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsx(Text, { children: JSON.stringify(value) }))] }, field));
2573
2655
  }) }));
2574
2656
  };
2575
2657
 
@@ -2619,7 +2701,7 @@ const CellRenderer = ({ cell }) => {
2619
2701
  paddingY: 2,
2620
2702
  }, object: value })] }, cell.id));
2621
2703
  }
2622
- return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { color: 'gray.400', children: getLabel({ columnId: cell.column.id }) }), jsx(Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
2704
+ return (jsxs(Box, { gridColumn, gridRow, children: [jsx(Box, { color: "colorPalette.400", children: getLabel({ columnId: cell.column.id }) }), jsx(Box, { wordBreak: "break-word", textOverflow: "ellipsis", overflow: "hidden", children: `${formatValue(cell.getValue())}` })] }, cell.id));
2623
2705
  };
2624
2706
  const DataDisplay = ({ variant = "" }) => {
2625
2707
  const { table, translate } = useDataTableContext();
@@ -2741,7 +2823,23 @@ const fuzzyFilter = (row, columnId, value, addMeta) => {
2741
2823
  *
2742
2824
  * @link https://tanstack.com/table/latest/docs/guide/column-defs
2743
2825
  */
2744
- 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, }) {
2826
+ 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 = {
2827
+ view: "View",
2828
+ edit: "Edit",
2829
+ filterButtonText: "Filter",
2830
+ filterTitle: "Filter",
2831
+ filterReset: "Reset",
2832
+ filterClose: "Close",
2833
+ reloadTooltip: "Reload",
2834
+ reloadButtonText: "Reload",
2835
+ resetSelection: "Reset Selection",
2836
+ resetSorting: "Reset Sorting",
2837
+ rowCountText: "Row Count",
2838
+ hasErrorText: "Has Error",
2839
+ globalFilterPlaceholder: "Search",
2840
+ trueLabel: "True",
2841
+ falseLabel: "False",
2842
+ }, }) {
2745
2843
  const table = useReactTable({
2746
2844
  _features: [DensityFeature],
2747
2845
  data: data,
@@ -2794,7 +2892,7 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2794
2892
  setGlobalFilter,
2795
2893
  type: "client",
2796
2894
  translate,
2797
- columns,
2895
+ columns: columns,
2798
2896
  sorting,
2799
2897
  setSorting,
2800
2898
  columnFilters,
@@ -2809,6 +2907,8 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2809
2907
  setDensity,
2810
2908
  columnVisibility,
2811
2909
  setColumnVisibility,
2910
+ data,
2911
+ tableLabel,
2812
2912
  }, children: children }));
2813
2913
  }
2814
2914
 
@@ -2823,10 +2923,26 @@ function DataTable({ columns, data, enableRowSelection = true, enableMultiRowSel
2823
2923
  *
2824
2924
  * @link https://tanstack.com/table/latest/docs/guide/column-defs
2825
2925
  */
2826
- 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, }) {
2926
+ 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 = {
2927
+ view: "View",
2928
+ edit: "Edit",
2929
+ filterButtonText: "Filter",
2930
+ filterTitle: "Filter",
2931
+ filterReset: "Reset",
2932
+ filterClose: "Close",
2933
+ reloadTooltip: "Reload",
2934
+ reloadButtonText: "Reload",
2935
+ resetSelection: "Reset Selection",
2936
+ resetSorting: "Reset Sorting",
2937
+ rowCountText: "Row Count",
2938
+ hasErrorText: "Has Error",
2939
+ globalFilterPlaceholder: "Search",
2940
+ trueLabel: "True",
2941
+ falseLabel: "False",
2942
+ }, }) {
2827
2943
  const table = useReactTable({
2828
2944
  _features: [DensityFeature],
2829
- data: query.data?.data ?? [],
2945
+ data: (query.data?.data ?? []),
2830
2946
  rowCount: query.data?.count ?? 0,
2831
2947
  columns: columns,
2832
2948
  getCoreRowModel: getCoreRowModel(),
@@ -2872,12 +2988,12 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
2872
2988
  // for tanstack-table ts bug end
2873
2989
  });
2874
2990
  return (jsx(DataTableContext.Provider, { value: {
2875
- table: { ...table },
2991
+ table: table,
2876
2992
  globalFilter,
2877
2993
  setGlobalFilter,
2878
2994
  type: "server",
2879
2995
  translate,
2880
- columns,
2996
+ columns: columns,
2881
2997
  sorting,
2882
2998
  setSorting,
2883
2999
  columnFilters,
@@ -2892,98 +3008,11 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
2892
3008
  setDensity,
2893
3009
  columnVisibility,
2894
3010
  setColumnVisibility,
3011
+ data: query.data?.data ?? [],
3012
+ tableLabel,
2895
3013
  }, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
2896
3014
  }
2897
3015
 
2898
- const Checkbox = React.forwardRef(function Checkbox(props, ref) {
2899
- const { icon, children, inputProps, rootRef, ...rest } = props;
2900
- return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
2901
- });
2902
-
2903
- const TableBody = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, alwaysShowSelector = true, canResize = true, }) => {
2904
- "use no memo";
2905
- const { table } = useDataTableContext();
2906
- const SELECTION_BOX_WIDTH = 20;
2907
- const [hoveredRow, setHoveredRow] = useState(-1);
2908
- const handleRowHover = (index) => {
2909
- setHoveredRow(index);
2910
- };
2911
- const getTdProps = (cell) => {
2912
- const tdProps = cell.column.getIsPinned()
2913
- ? {
2914
- left: showSelector
2915
- ? `${cell.column.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
2916
- : `${cell.column.getStart("left")}px`,
2917
- background: pinnedBgColor.light,
2918
- position: "sticky",
2919
- zIndex: -1,
2920
- _dark: {
2921
- backgroundColor: pinnedBgColor.dark,
2922
- },
2923
- }
2924
- : {};
2925
- return tdProps;
2926
- };
2927
- const getTrProps = ({ hoveredRow, index, }) => {
2928
- if (hoveredRow === -1) {
2929
- return {};
2930
- }
2931
- if (hoveredRow === index) {
2932
- return {
2933
- opacity: "1",
2934
- };
2935
- }
2936
- return {
2937
- opacity: "0.8",
2938
- };
2939
- };
2940
- return (jsx(Table$1.Body, { children: table.getRowModel().rows.map((row, index) => {
2941
- return (jsxs(Table$1.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow, alwaysShowSelector: alwaysShowSelector })), row.getVisibleCells().map((cell, index) => {
2942
- return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
2943
- // styling resize and pinning start
2944
- flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`, backgroundColor: "white", ...getTdProps(cell), _dark: {
2945
- backgroundColor: "gray.950",
2946
- }, children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
2947
- })] }, `chakra-table-row-${row.id}`));
2948
- }) }));
2949
- };
2950
- const TableRowSelector = ({ index, row, hoveredRow, pinnedBgColor = { light: "gray.50", dark: "gray.700" }, alwaysShowSelector = true, }) => {
2951
- const { table } = useDataTableContext();
2952
- const SELECTION_BOX_WIDTH = 20;
2953
- const isCheckBoxVisible = (current_index, current_row) => {
2954
- if (alwaysShowSelector) {
2955
- return true;
2956
- }
2957
- if (current_row.getIsSelected()) {
2958
- return true;
2959
- }
2960
- if (hoveredRow == current_index) {
2961
- return true;
2962
- }
2963
- return false;
2964
- };
2965
- return (jsxs(Table$1.Cell, { padding: `${table.getDensityValue()}px`, ...(table.getIsSomeColumnsPinned("left")
2966
- ? {
2967
- left: `0px`,
2968
- backgroundColor: pinnedBgColor.light,
2969
- position: "sticky",
2970
- zIndex: 1,
2971
- _dark: { backgroundColor: pinnedBgColor.dark },
2972
- }
2973
- : {}),
2974
- // styling resize and pinning end
2975
- display: "grid", children: [!isCheckBoxVisible(index, row) && (jsx(Box, { as: "span", margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` })), isCheckBoxVisible(index, row) && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: row.getIsSelected(),
2976
- disabled: !row.getCanSelect(),
2977
- onChange: row.getToggleSelectedHandler() }) }))] }));
2978
- };
2979
-
2980
- const Tooltip = React.forwardRef(function Tooltip(props, ref) {
2981
- const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
2982
- if (disabled)
2983
- return children;
2984
- return (jsxs(Tooltip$1.Root, { ...rest, children: [jsx(Tooltip$1.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Tooltip$1.Positioner, { children: jsxs(Tooltip$1.Content, { ref: ref, ...contentProps, children: [showArrow && (jsx(Tooltip$1.Arrow, { children: jsx(Tooltip$1.ArrowTip, {}) })), content] }) }) })] }));
2985
- });
2986
-
2987
3016
  const InputGroup = React.forwardRef(function InputGroup(props, ref) {
2988
3017
  const { startElement, startElementProps, endElement, endElementProps, children, startOffset = "6px", endOffset = "6px", ...rest } = props;
2989
3018
  return (jsxs(Group, { ref: ref, ...rest, children: [startElement && (jsx(InputElement, { pointerEvents: "none", ...startElementProps, children: startElement })), React.cloneElement(children, {
@@ -2997,7 +3026,8 @@ const InputGroup = React.forwardRef(function InputGroup(props, ref) {
2997
3026
  });
2998
3027
 
2999
3028
  const GlobalFilter = () => {
3000
- const { table } = useDataTableContext();
3029
+ const { table, tableLabel } = useDataTableContext();
3030
+ const { globalFilterPlaceholder } = tableLabel;
3001
3031
  const [searchTerm, setSearchTerm] = useState("");
3002
3032
  const debouncedSearchTerm = useDebounce(searchTerm, 500);
3003
3033
  useEffect(() => {
@@ -3006,42 +3036,31 @@ const GlobalFilter = () => {
3006
3036
  };
3007
3037
  searchHN();
3008
3038
  }, [debouncedSearchTerm]);
3009
- return (jsx(Fragment, { children: jsx(InputGroup, { flex: "1", startElement: jsx(MdSearch, {}), children: jsx(Input, { placeholder: "Outline", variant: "outline", onChange: (e) => {
3039
+ return (jsx(Fragment, { children: jsx(InputGroup, { flex: "1", startElement: jsx(MdSearch, {}), children: jsx(Input, { placeholder: globalFilterPlaceholder, variant: "outline", onChange: (e) => {
3010
3040
  setSearchTerm(e.target.value);
3011
3041
  } }) }) }));
3012
3042
  };
3013
3043
 
3014
- const ReloadButton = ({ text = "Reload", variant = "icon", }) => {
3044
+ const Tooltip = React.forwardRef(function Tooltip(props, ref) {
3045
+ const { showArrow, children, disabled, portalled, content, contentProps, portalRef, ...rest } = props;
3046
+ if (disabled)
3047
+ return children;
3048
+ return (jsxs(Tooltip$1.Root, { ...rest, children: [jsx(Tooltip$1.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Tooltip$1.Positioner, { children: jsxs(Tooltip$1.Content, { ref: ref, ...contentProps, children: [showArrow && (jsx(Tooltip$1.Arrow, { children: jsx(Tooltip$1.ArrowTip, {}) })), content] }) }) })] }));
3049
+ });
3050
+
3051
+ const ReloadButton = ({ variant = "icon", }) => {
3015
3052
  const { url } = useDataTableServerContext();
3016
3053
  const queryClient = useQueryClient();
3054
+ const { tableLabel } = useDataTableContext();
3055
+ const { reloadTooltip, reloadButtonText } = tableLabel;
3017
3056
  if (variant === "icon") {
3018
- return (jsx(Tooltip, { showArrow: true, content: "This is the tooltip content", children: jsx(Button, { variant: "ghost", onClick: () => {
3057
+ return (jsx(Tooltip, { showArrow: true, content: reloadTooltip, children: jsx(Button, { variant: "ghost", onClick: () => {
3019
3058
  queryClient.invalidateQueries({ queryKey: [url] });
3020
3059
  }, "aria-label": "refresh", children: jsx(IoReload, {}) }) }));
3021
3060
  }
3022
3061
  return (jsxs(Button, { variant: "ghost", onClick: () => {
3023
3062
  queryClient.invalidateQueries({ queryKey: [url] });
3024
- }, children: [jsx(IoReload, {}), " ", text] }));
3025
- };
3026
-
3027
- const FilterOptions = ({ column }) => {
3028
- const { table } = useDataTableContext();
3029
- const tableColumn = table.getColumn(column);
3030
- const options = tableColumn?.columnDef.meta?.filterOptions ?? [];
3031
- return (jsx(Fragment, { children: options.map((option) => {
3032
- const selected = table.getColumn(column)?.getFilterValue() === option;
3033
- return (jsxs(Button$1, { size: "sm", onClick: () => {
3034
- if (selected) {
3035
- table.setColumnFilters((state) => {
3036
- return state.filter((filter) => {
3037
- return filter.id !== column;
3038
- });
3039
- });
3040
- return;
3041
- }
3042
- table.getColumn(column)?.setFilterValue(option);
3043
- }, variant: selected ? "solid" : "outline", display: "flex", gap: "0.25rem", children: [option, selected && jsx(MdClose, {})] }, option));
3044
- }) }));
3063
+ }, children: [jsx(IoReload, {}), " ", reloadButtonText] }));
3045
3064
  };
3046
3065
 
3047
3066
  const TableFilterTags = () => {
@@ -3055,16 +3074,99 @@ const TableFilterTags = () => {
3055
3074
  }) }));
3056
3075
  };
3057
3076
 
3058
- const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterOptions = [], extraItems = jsx(Fragment, {}), loading = false, hasError = false, }) => {
3059
- const { translate } = useDataTableContext();
3060
- return (jsxs(Grid, { templateRows: "auto 1fr auto", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", children: [jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsxs(Flex, { justifyContent: "space-between", children: [jsx(Box, { children: showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsx(Spinner, { size: "sm" }), hasError && (jsx(Tooltip, { content: translate.t("hasError"), children: jsx(Icon, { as: BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterOptions.length > 0 && (jsx(Flex, { flexFlow: "column", gap: "0.5rem", children: filterOptions.map((column) => {
3061
- return (jsxs(Flex, { alignItems: "center", flexFlow: "wrap", gap: "0.5rem", children: [showFilterName && jsxs(Text, { children: [column, ":"] }), jsx(FilterOptions, { column: column })] }, column));
3062
- }) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { overflow: "auto", backgroundColor: "gray.50", _dark: {
3063
- backgroundColor: "gray.900",
3064
- }, children: children }), jsxs(Flex, { justifyContent: "space-between", children: [jsxs(Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && (jsxs(Flex, { children: [jsx(Text, { paddingRight: "0.5rem", children: translate.t("rowcount.total") }), jsx(RowCountText, {})] }))] }), jsx(Box, { justifySelf: "end", children: showPagination && jsx(Pagination, {}) })] })] }));
3077
+ const TableControls = ({ fitTableWidth = false, fitTableHeight = false, children = jsx(Fragment, {}), showGlobalFilter = false, showFilter = false, showFilterName = false, showFilterTags = false, showReload = false, showPagination = true, showPageSizeControl = true, showPageCountText = true, showView = true, filterTagsOptions = [], extraItems = jsx(Fragment, {}), loading = false, hasError = false, gridProps = {}, }) => {
3078
+ const { tableLabel, table } = useDataTableContext();
3079
+ const { rowCountText, hasErrorText } = tableLabel;
3080
+ return (jsxs(Grid, { templateRows: "auto 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", gap: "0.5rem", ...gridProps, children: [jsxs(Flex, { flexFlow: "column", gap: 2, children: [jsxs(Flex, { justifyContent: "space-between", children: [jsx(Box, { children: showView && jsx(ViewDialog, { icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: "0.5rem", alignItems: "center", justifySelf: "end", children: [loading && jsx(Spinner, { size: "sm" }), hasError && (jsx(Tooltip, { content: hasErrorText, children: jsx(Icon, { as: BsExclamationCircleFill, color: "red.400" }) })), showGlobalFilter && jsx(GlobalFilter, {}), showFilter && jsx(FilterDialog, {}), showReload && jsx(ReloadButton, {}), extraItems] })] }), filterTagsOptions.length > 0 && (jsx(Flex, { flexFlow: "column", gap: "0.5rem", children: filterTagsOptions.map((option) => {
3081
+ const { column, options } = option;
3082
+ const tableColumn = table.getColumn(column);
3083
+ return (jsxs(Flex, { alignItems: "center", flexFlow: "wrap", gap: "0.5rem", children: [tableColumn?.columnDef.meta?.displayName && (jsx(Text, { children: tableColumn?.columnDef.meta?.displayName })), jsx(TagFilter, { availableTags: options, selectedTags: tableColumn?.getFilterValue() ?? [], selectOne: true, onTagChange: (tags) => {
3084
+ if (tags.length === 0) {
3085
+ return tableColumn?.setFilterValue(undefined);
3086
+ }
3087
+ tableColumn?.setFilterValue(tags);
3088
+ } })] }, column));
3089
+ }) })), showFilterTags && (jsx(Flex, { children: jsx(TableFilterTags, {}) }))] }), jsx(Grid, { overflow: "auto", bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, children: children }), (showPageSizeControl || showPageCountText || showPagination) && (jsxs(Flex, { justifyContent: "space-between", children: [jsxs(Flex, { gap: "1rem", alignItems: "center", children: [showPageSizeControl && jsx(PageSizeControl, {}), showPageCountText && (jsxs(Flex, { children: [jsx(Text, { paddingRight: "0.5rem", children: rowCountText }), jsx(RowCountText, {})] }))] }), jsx(Box, { justifySelf: "end", children: showPagination && jsx(Pagination, {}) })] }))] }));
3090
+ };
3091
+
3092
+ const EmptyState = React.forwardRef(function EmptyState(props, ref) {
3093
+ const { title, description, icon, children, ...rest } = props;
3094
+ return (jsx(EmptyState$2.Root, { ref: ref, ...rest, children: jsxs(EmptyState$2.Content, { children: [icon && (jsx(EmptyState$2.Indicator, { children: icon })), description ? (jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })) : (jsx(EmptyState$2.Title, { children: title })), children] }) }));
3095
+ });
3096
+
3097
+ const EmptyResult = (jsx(EmptyState, { icon: jsx(HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxs(List.Root, { variant: "marker", children: [jsx(List.Item, { children: "Try removing filters" }), jsx(List.Item, { children: "Try different keywords" })] }) }));
3098
+ const Table = ({ children, emptyComponent = EmptyResult, canResize = true, ...props }) => {
3099
+ const { table } = useDataTableContext();
3100
+ if (table.getRowModel().rows.length <= 0) {
3101
+ return emptyComponent;
3102
+ }
3103
+ return (jsx(Table$1.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 }));
3104
+ };
3105
+
3106
+ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
3107
+ const { icon, children, inputProps, rootRef, ...rest } = props;
3108
+ return (jsxs(Checkbox$1.Root, { ref: rootRef, ...rest, children: [jsx(Checkbox$1.HiddenInput, { ref: ref, ...inputProps }), jsx(Checkbox$1.Control, { children: icon || jsx(Checkbox$1.Indicator, {}) }), children != null && (jsx(Checkbox$1.Label, { children: children }))] }));
3109
+ });
3110
+
3111
+ const TableBody = ({ showSelector = false, canResize = true, }) => {
3112
+ "use no memo";
3113
+ const { table } = useDataTableContext();
3114
+ const SELECTION_BOX_WIDTH = 20;
3115
+ const [hoveredRow, setHoveredRow] = useState(-1);
3116
+ const handleRowHover = (index) => {
3117
+ setHoveredRow(index);
3118
+ };
3119
+ const getTdProps = (cell) => {
3120
+ const tdProps = cell.column.getIsPinned()
3121
+ ? {
3122
+ left: showSelector
3123
+ ? `${cell.column.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
3124
+ : `${cell.column.getStart("left")}px`,
3125
+ position: "relative",
3126
+ }
3127
+ : {};
3128
+ return tdProps;
3129
+ };
3130
+ const getTrProps = ({ hoveredRow, index, }) => {
3131
+ if (hoveredRow === -1) {
3132
+ return {};
3133
+ }
3134
+ if (hoveredRow === index) {
3135
+ return {
3136
+ opacity: "1",
3137
+ };
3138
+ }
3139
+ return {
3140
+ opacity: "0.8",
3141
+ };
3142
+ };
3143
+ return (jsx(Table$1.Body, { children: table.getRowModel().rows.map((row, index) => {
3144
+ return (jsxs(Table$1.Row, { display: "flex", zIndex: 1, onMouseEnter: () => handleRowHover(index), onMouseLeave: () => handleRowHover(-1), ...getTrProps({ hoveredRow, index }), children: [showSelector && (jsx(TableRowSelector, { index: index, row: row, hoveredRow: hoveredRow })), row.getVisibleCells().map((cell, index) => {
3145
+ return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`,
3146
+ // styling resize and pinning start
3147
+ flex: `${canResize ? "0" : "1"} 0 ${cell.column.getSize()}px`,
3148
+ // this is to avoid the cell from being too wide
3149
+ minWidth: `0`, color: {
3150
+ base: "colorPalette.900",
3151
+ _dark: "colorPalette.100",
3152
+ },
3153
+ bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, ...getTdProps(cell), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-rowcell-${cell.id}-${index}`));
3154
+ })] }, `chakra-table-row-${row.id}`));
3155
+ }) }));
3156
+ };
3157
+ const TableRowSelector = ({ row, }) => {
3158
+ const { table } = useDataTableContext();
3159
+ const SELECTION_BOX_WIDTH = 20;
3160
+ return (jsx(Table$1.Cell, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
3161
+ base: "colorPalette.900",
3162
+ _dark: "colorPalette.100",
3163
+ },
3164
+ bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: row.getIsSelected(),
3165
+ disabled: !row.getCanSelect(),
3166
+ onCheckedChange: row.getToggleSelectedHandler() }) }));
3065
3167
  };
3066
3168
 
3067
- const TableFooter = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, alwaysShowSelector = true, }) => {
3169
+ const TableFooter = ({ showSelector = false, alwaysShowSelector = true, }) => {
3068
3170
  const table = useDataTableContext().table;
3069
3171
  const SELECTION_BOX_WIDTH = 20;
3070
3172
  const [hoveredCheckBox, setHoveredCheckBox] = useState(false);
@@ -3083,65 +3185,62 @@ const TableFooter = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, s
3083
3185
  }
3084
3186
  return false;
3085
3187
  };
3086
- const getThProps = (header) => {
3087
- const thProps = header.column.getIsPinned()
3088
- ? {
3089
- left: showSelector
3090
- ? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
3091
- : `${header.getStart("left") + table.getDensityValue() * 2}px`,
3092
- background: pinnedBgColor.light,
3093
- position: "sticky",
3094
- zIndex: 1,
3095
- _dark: {
3096
- backgroundColor: pinnedBgColor.dark,
3097
- },
3098
- }
3099
- : {};
3100
- return thProps;
3101
- };
3102
- return (jsx(Table$1.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.Header
3103
- // styling resize and pinning start
3104
- , {
3105
- // styling resize and pinning start
3106
- padding: `${table.getDensityValue()}px`, ...(table.getIsSomeColumnsPinned("left")
3107
- ? {
3108
- left: `0px`,
3109
- backgroundColor: pinnedBgColor.light,
3110
- position: "sticky",
3111
- zIndex: 1,
3112
- _dark: { backgroundColor: pinnedBgColor.dark },
3113
- }
3114
- : {}),
3115
- // styling resize and pinning end
3116
- onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
3188
+ return (jsx(Table$1.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.Header, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
3117
3189
  // indeterminate: table.getIsSomeRowsSelected(),
3118
3190
  onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsx(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) => (jsx(Table$1.Cell, { padding: "0", columnSpan: `${header.colSpan}`,
3119
3191
  // styling resize and pinning start
3120
- maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", ...getThProps(header), children: jsx(MenuRoot$1, { children: jsx(MenuTrigger$1, { asChild: true, children: jsx(Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", _hover: { backgroundColor: "gray.100" }, children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
3192
+ maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: "grid", children: jsx(MenuRoot$1, { children: jsx(MenuTrigger$1, { asChild: true, children: jsx(Box, { padding: `${table.getDensityValue()}px`, display: "flex", alignItems: "center", justifyContent: "start", borderRadius: "0rem", children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
3121
3193
  ? null
3122
- : flexRender(header.column.columnDef.footer, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && (
3123
- // <UpDownIcon />
3124
- jsx(Fragment, {})), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
3194
+ : flexRender(header.column.columnDef.footer, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) })] }) }) }) }) }, `chakra-table-footer-${header.column.id}-${footerGroup.id}`)))] }, `chakra-table-footergroup-${footerGroup.id}`))) }));
3125
3195
  };
3126
3196
 
3127
- const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dark: "gray.700" }, showSelector = false, isSticky = true, alwaysShowSelector = true, tHeadProps = {}, }) => {
3197
+ // Default text values
3198
+ const DEFAULT_HEADER_TEXTS = {
3199
+ pinColumn: "Pin Column",
3200
+ cancelPin: "Cancel Pin",
3201
+ sortAscending: "Sort Ascending",
3202
+ sortDescending: "Sort Descending",
3203
+ clearSorting: "Clear Sorting",
3204
+ };
3205
+ /**
3206
+ * TableHeader component with configurable text strings.
3207
+ *
3208
+ * @example
3209
+ * // Using default texts
3210
+ * <TableHeader />
3211
+ *
3212
+ * @example
3213
+ * // Customizing default texts for all columns
3214
+ * <TableHeader
3215
+ * defaultTexts={{
3216
+ * pinColumn: "Pin This Column",
3217
+ * sortAscending: "Sort A-Z"
3218
+ * }}
3219
+ * />
3220
+ *
3221
+ * @example
3222
+ * // Customizing texts per column via meta
3223
+ * const columns = [
3224
+ * columnHelper.accessor("name", {
3225
+ * header: "Name",
3226
+ * meta: {
3227
+ * headerTexts: {
3228
+ * pinColumn: "Pin Name Column",
3229
+ * sortAscending: "Sort Names A-Z"
3230
+ * }
3231
+ * }
3232
+ * })
3233
+ * ];
3234
+ */
3235
+ const TableHeader = ({ canResize = true, showSelector = false, isSticky = true, tableHeaderProps = {}, tableRowProps = {}, defaultTexts = {}, }) => {
3128
3236
  const { table } = useDataTableContext();
3129
3237
  const SELECTION_BOX_WIDTH = 20;
3130
- const [hoveredCheckBox, setHoveredCheckBox] = useState(false);
3131
- const handleRowHover = (isHovered) => {
3132
- setHoveredCheckBox(isHovered);
3133
- };
3134
- const isCheckBoxVisible = () => {
3135
- if (alwaysShowSelector) {
3136
- return true;
3137
- }
3138
- if (table.getIsAllRowsSelected()) {
3139
- return true;
3140
- }
3141
- if (hoveredCheckBox) {
3142
- return true;
3143
- }
3144
- return false;
3238
+ // Merge default texts with provided defaults
3239
+ const mergedDefaultTexts = { ...DEFAULT_HEADER_TEXTS, ...defaultTexts };
3240
+ // Helper function to get text for a specific header
3241
+ const getHeaderText = (header, key) => {
3242
+ const columnMeta = header.column.columnDef.meta;
3243
+ return columnMeta?.headerTexts?.[key] || mergedDefaultTexts[key];
3145
3244
  };
3146
3245
  const getThProps = (header) => {
3147
3246
  const thProps = header.column.getIsPinned()
@@ -3149,12 +3248,8 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3149
3248
  left: showSelector
3150
3249
  ? `${header.getStart("left") + SELECTION_BOX_WIDTH + table.getDensityValue() * 2}px`
3151
3250
  : `${header.getStart("left")}px`,
3152
- background: pinnedBgColor.light,
3153
3251
  position: "sticky",
3154
3252
  zIndex: 100 + 1,
3155
- _dark: {
3156
- backgroundColor: pinnedBgColor.dark,
3157
- },
3158
3253
  }
3159
3254
  : {};
3160
3255
  return thProps;
@@ -3163,21 +3258,13 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3163
3258
  position: "sticky",
3164
3259
  top: 0,
3165
3260
  };
3166
- return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}), ...tHeadProps, children: table.getHeaderGroups().map((headerGroup) => (jsxs(Table$1.Row, { display: "flex", children: [showSelector && (jsxs(Table$1.ColumnHeader
3167
- // styling resize and pinning start
3168
- , { ...(table.getIsSomeColumnsPinned("left")
3169
- ? {
3170
- left: `0px`,
3171
- backgroundColor: pinnedBgColor.light,
3172
- position: "sticky",
3173
- zIndex: 1,
3174
- _dark: { backgroundColor: pinnedBgColor.dark },
3175
- }
3176
- : {}),
3177
- // styling resize and pinning end
3178
- padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: "grid", children: [isCheckBoxVisible() && (jsx(Box, { margin: "0rem", display: "grid", justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: table.getIsAllRowsSelected(),
3179
- // indeterminate: table.getIsSomeRowsSelected(),
3180
- onChange: table.getToggleAllRowsSelectedHandler() }) })), !isCheckBoxVisible() && (jsx(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) => {
3261
+ return (jsx(Table$1.Header, { ...(isSticky ? stickyProps : {}), bgColor: "transparent", ...tableHeaderProps, children: table.getHeaderGroups().map((headerGroup) => (jsxs(Table$1.Row, { display: "flex", bgColor: "transparent", ...tableRowProps, children: [showSelector && (jsx(Table$1.ColumnHeader, { padding: `${table.getDensityValue()}px`, display: "grid", color: {
3262
+ base: "colorPalette.900",
3263
+ _dark: "colorPalette.100",
3264
+ },
3265
+ bg: { base: "colorPalette.50", _dark: "colorPalette.950" }, justifyItems: "center", alignItems: "center", children: jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: table.getIsAllRowsSelected(),
3266
+ // indeterminate: table.getIsSomeRowsSelected(),
3267
+ onChange: table.getToggleAllRowsSelectedHandler() }) })), headerGroup.headers.map((header) => {
3181
3268
  const resizeProps = {
3182
3269
  onMouseDown: header.getResizeHandler(),
3183
3270
  onTouchStart: header.getResizeHandler(),
@@ -3185,18 +3272,32 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3185
3272
  };
3186
3273
  return (jsxs(Table$1.ColumnHeader, { padding: 0, columnSpan: `${header.colSpan}`,
3187
3274
  // styling resize and pinning start
3188
- flex: `${canResize ? "0" : "1"} 0 ${header.column.getSize()}px`, display: "grid", gridTemplateColumns: "1fr auto", zIndex: 1500 + header.index, ...getThProps(header), children: [jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Flex, { padding: `${table.getDensityValue()}px`, alignItems: "center", justifyContent: "start", borderRadius: "0rem", overflow: "auto", _hover: {
3189
- backgroundColor: "gray.100",
3190
- _dark: {
3191
- backgroundColor: "gray.700",
3275
+ flex: `${canResize ? "0" : "1"} 0 ${header.column.getSize()}px`, display: "grid", gridTemplateColumns: "1fr auto", zIndex: 1500 + header.index, color: {
3276
+ base: "colorPalette.800",
3277
+ _dark: "colorPalette.200",
3278
+ },
3279
+ bg: { base: "colorPalette.100", _dark: "colorPalette.900" }, ...getThProps(header), children: [jsxs(MenuRoot, { children: [jsx(MenuTrigger, { asChild: true, children: jsx(Flex, { padding: `${table.getDensityValue()}px`, alignItems: "center", justifyContent: "start", borderRadius: "0rem", overflow: "auto", color: {
3280
+ base: "colorPalette.800",
3281
+ _dark: "colorPalette.200",
3282
+ _hover: {
3283
+ base: "colorPalette.700",
3284
+ _dark: "colorPalette.300",
3285
+ },
3286
+ },
3287
+ bg: {
3288
+ base: "colorPalette.100",
3289
+ _dark: "colorPalette.900",
3290
+ _hover: {
3291
+ base: "colorPalette.200",
3292
+ _dark: "colorPalette.800",
3192
3293
  },
3193
3294
  }, children: jsxs(Flex, { gap: "0.5rem", alignItems: "center", children: [header.isPlaceholder
3194
3295
  ? null
3195
3296
  : flexRender(header.column.columnDef.header, header.getContext()), jsx(Box, { children: header.column.getCanSort() && (jsxs(Fragment, { children: [header.column.getIsSorted() === false && jsx(Fragment, {}), header.column.getIsSorted() === "asc" && (jsx(BiUpArrow, {})), header.column.getIsSorted() === "desc" && (jsx(BiDownArrow, {}))] })) }), jsx(Box, { children: header.column.getIsFiltered() && jsx(MdFilterListAlt, {}) })] }) }) }), jsxs(MenuContent, { children: [!header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "pin-column", children: jsxs(Button, { variant: "ghost", onClick: () => {
3196
3297
  header.column.pin("left");
3197
- }, children: [jsx(MdPushPin, {}), "Pin Column"] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: "ghost", onClick: () => {
3298
+ }, children: [jsx(MdPushPin, {}), getHeaderText(header, "pinColumn")] }) })), header.column.getIsPinned() && (jsx(MenuItem, { asChild: true, value: "cancel-pin", children: jsxs(Button, { variant: "ghost", onClick: () => {
3198
3299
  header.column.pin(false);
3199
- }, children: [jsx(MdCancel, {}), "Cancel Pin"] }) })), header.column.getCanSort() && (jsxs(Fragment, { children: [jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxs(Button, { variant: "ghost", onClick: () => {
3300
+ }, children: [jsx(MdCancel, {}), getHeaderText(header, "cancelPin")] }) })), header.column.getCanSort() && (jsxs(Fragment, { children: [jsx(MenuItem, { asChild: true, value: "sort-ascend", children: jsxs(Button, { variant: "ghost", onClick: () => {
3200
3301
  table.setSorting((state) => {
3201
3302
  return [
3202
3303
  ...state.filter((column) => {
@@ -3205,7 +3306,7 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3205
3306
  { id: header.id, desc: false },
3206
3307
  ];
3207
3308
  });
3208
- }, children: [jsx(GrAscend, {}), "Sort Ascending"] }) }), jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxs(Button, { variant: "ghost", onClick: () => {
3309
+ }, children: [jsx(GrAscend, {}), getHeaderText(header, "sortAscending")] }) }), jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxs(Button, { variant: "ghost", onClick: () => {
3209
3310
  table.setSorting((state) => {
3210
3311
  return [
3211
3312
  ...state.filter((column) => {
@@ -3214,42 +3315,30 @@ const TableHeader = ({ canResize = true, pinnedBgColor = { light: "gray.50", dar
3214
3315
  { id: header.id, desc: true },
3215
3316
  ];
3216
3317
  });
3217
- }, children: [jsx(GrDescend, {}), "Sort Descending"] }) }), header.column.getIsSorted() && (jsx(MenuItem, { asChild: true, value: "sort-descend", children: jsxs(Button, { variant: "ghost", onClick: () => {
3318
+ }, children: [jsx(GrDescend, {}), getHeaderText(header, "sortDescending")] }) }), header.column.getIsSorted() && (jsx(MenuItem, { asChild: true, value: "clear-sorting", children: jsxs(Button, { variant: "ghost", onClick: () => {
3218
3319
  header.column.clearSorting();
3219
- }, children: [jsx(MdClear, {}), "Clear Sorting"] }) }))] }))] })] }), canResize && (jsx(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: {
3320
+ }, children: [jsx(MdClear, {}), getHeaderText(header, "clearSorting")] }) }))] }))] })] }), canResize && (jsx(Box, { borderRight: "0.2rem solid", borderRightColor: header.column.getIsResizing()
3321
+ ? "colorPalette.700"
3322
+ : "transparent", position: "relative", right: "0.1rem", width: "2px", height: "100%", userSelect: "none", style: { touchAction: "none" }, _hover: {
3220
3323
  borderRightColor: header.column.getIsResizing()
3221
- ? "gray.700"
3222
- : "gray.400",
3324
+ ? "colorPalette.700"
3325
+ : "colorPalette.400",
3223
3326
  }, ...resizeProps }))] }, `chakra-table-header-${header.id}`));
3224
3327
  })] }, `chakra-table-headergroup-${headerGroup.id}`))) }));
3225
3328
  };
3226
3329
 
3227
- const EmptyState = React.forwardRef(function EmptyState(props, ref) {
3228
- const { title, description, icon, children, ...rest } = props;
3229
- return (jsx(EmptyState$2.Root, { ref: ref, ...rest, children: jsxs(EmptyState$2.Content, { children: [icon && (jsx(EmptyState$2.Indicator, { children: icon })), description ? (jsxs(VStack, { textAlign: "center", children: [jsx(EmptyState$2.Title, { children: title }), jsx(EmptyState$2.Description, { children: description })] })) : (jsx(EmptyState$2.Title, { children: title })), children] }) }));
3230
- });
3231
-
3232
- const EmptyResult = (jsx(EmptyState, { icon: jsx(HiColorSwatch, {}), title: "No results found", description: "Try adjusting your search", children: jsxs(List.Root, { variant: "marker", children: [jsx(List.Item, { children: "Try removing filters" }), jsx(List.Item, { children: "Try different keywords" })] }) }));
3233
- const Table = ({ children, emptyComponent = EmptyResult, canResize = true, ...props }) => {
3234
- const { table } = useDataTableContext();
3235
- if (table.getRowModel().rows.length <= 0) {
3236
- return emptyComponent;
3237
- }
3238
- return (jsx(Table$1.Root, { stickyHeader: true, variant: "outline", width: canResize ? table.getCenterTotalSize() : undefined, display: "grid", alignContent: "start", overflowY: "auto", ...props, children: children }));
3239
- };
3240
-
3241
- const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, controlProps = {}, tableFooterProps = {}, variant = "", }) => {
3330
+ const DefaultTable = ({ showFooter = false, tableProps = {}, tableHeaderProps = {}, tableBodyProps = {}, tableFooterProps = {}, controlProps = {}, variant = "", }) => {
3242
3331
  if (variant === "greedy") {
3243
3332
  return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { canResize: false, ...{ ...tableProps }, children: [jsx(TableHeader, { canResize: false, ...tableHeaderProps }), jsx(TableBody, { canResize: false, ...tableBodyProps }), showFooter && (jsx(TableFooter, { canResize: false, ...tableFooterProps }))] }) }));
3244
3333
  }
3245
3334
  return (jsx(TableControls, { ...controlProps, children: jsxs(Table, { ...tableProps, children: [jsx(TableHeader, { ...tableHeaderProps }), jsx(TableBody, { ...tableBodyProps }), showFooter && jsx(TableFooter, { ...tableFooterProps })] }) }));
3246
3335
  };
3247
3336
 
3248
- const TableCardContainer = ({ children, variant = "", ...props }) => {
3337
+ const TableCardContainer = ({ children, variant = "", gap = "1rem", gridTemplateColumns = "repeat(auto-fit, minmax(20rem, 1fr))", direction = "row", ...props }) => {
3249
3338
  if (variant === "carousel") {
3250
- return (jsx(Flex, { overflow: "scroll", gap: "1rem", children: children }));
3339
+ return (jsx(Flex, { overflow: "auto", gap: gap, direction: direction, ...props, children: children }));
3251
3340
  }
3252
- return (jsx(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(20rem, 1fr))", gap: "0.5rem", ...props, children: children }));
3341
+ return (jsx(Grid, { gridTemplateColumns: gridTemplateColumns, gap: gap, ...props, children: children }));
3253
3342
  };
3254
3343
 
3255
3344
  const DefaultCardTitle = () => {
@@ -3278,8 +3367,8 @@ const TableComponent = ({ render = () => {
3278
3367
  };
3279
3368
 
3280
3369
  const TableLoadingComponent = ({ render, }) => {
3281
- const { loading } = useDataTableContext();
3282
- return jsx(Fragment, { children: render(loading) });
3370
+ const { query } = useDataTableServerContext();
3371
+ return jsx(Fragment, { children: render(query.isLoading) });
3283
3372
  };
3284
3373
 
3285
3374
  const SelectAllRowsToggle = ({ selectAllIcon = jsx(MdOutlineChecklist, {}), clearAllIcon = jsx(MdClear, {}), selectAllText = "", clearAllText = "", }) => {
@@ -3365,50 +3454,43 @@ const useDataTable = ({ default: { sorting: defaultSorting = [], pagination: def
3365
3454
  };
3366
3455
  };
3367
3456
 
3368
- const useDataTableServer = ({ url, default: { sorting: defaultSorting = [], pagination: defaultPagination = {
3369
- pageIndex: 0, //initial page index
3370
- pageSize: 10, //default page size
3371
- }, rowSelection: defaultRowSelection = {}, columnFilters: defaultColumnFilters = [], columnOrder: defaultColumnOrder = [], columnVisibility: defaultColumnVisibility = {}, globalFilter: defaultGlobalFilter = "", density: defaultDensity = "sm", } = {
3372
- sorting: [],
3373
- pagination: {
3457
+ const useDataTableServer = (props) => {
3458
+ const { url, default: defaultProps, keyPrefix, placeholderData, queryFn: customQueryFn, } = props;
3459
+ const { sorting: defaultSorting, pagination: defaultPagination, rowSelection: defaultRowSelection, columnFilters: defaultColumnFilters, columnOrder: defaultColumnOrder, columnVisibility: defaultColumnVisibility, globalFilter: defaultGlobalFilter, density: defaultDensity, } = defaultProps || {};
3460
+ const [sorting, setSorting] = useState(defaultSorting || []);
3461
+ const [columnFilters, setColumnFilters] = useState(defaultColumnFilters || []); // can set initial column filter state here
3462
+ const [pagination, setPagination] = useState(defaultPagination || {
3374
3463
  pageIndex: 0, //initial page index
3375
- pageSize: 10, //age size
3376
- },
3377
- rowSelection: {},
3378
- columnFilters: [],
3379
- columnOrder: [],
3380
- columnVisibility: {},
3381
- globalFilter: "",
3382
- density: "sm",
3383
- }, keyPrefix, }) => {
3384
- const [sorting, setSorting] = useState(defaultSorting);
3385
- const [columnFilters, setColumnFilters] = useState(defaultColumnFilters); // can set initial column filter state here
3386
- const [pagination, setPagination] = useState(defaultPagination);
3387
- const [rowSelection, setRowSelection] = useState(defaultRowSelection);
3388
- const [columnOrder, setColumnOrder] = useState(defaultColumnOrder);
3389
- const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter);
3390
- const [density, setDensity] = useState(defaultDensity);
3391
- const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility);
3464
+ pageSize: 10, //default page size
3465
+ });
3466
+ const [rowSelection, setRowSelection] = useState(defaultRowSelection || {});
3467
+ const [columnOrder, setColumnOrder] = useState(defaultColumnOrder || []);
3468
+ const [globalFilter, setGlobalFilter] = useState(defaultGlobalFilter || "");
3469
+ const [density, setDensity] = useState(defaultDensity || "sm");
3470
+ const [columnVisibility, setColumnVisibility] = useState(defaultColumnVisibility || {});
3471
+ const { pageSize, pageIndex } = pagination;
3392
3472
  const params = {
3393
- offset: pagination.pageIndex * pagination.pageSize,
3394
- limit: pagination.pageSize,
3473
+ offset: pageIndex * pageSize,
3474
+ limit: pageSize,
3395
3475
  sorting,
3396
3476
  where: columnFilters,
3397
3477
  searching: globalFilter,
3398
3478
  };
3479
+ const defaultQueryFn = async () => {
3480
+ if (!url) {
3481
+ throw new Error("url is required");
3482
+ }
3483
+ const response = await axios.get(url, {
3484
+ params,
3485
+ });
3486
+ return response.data;
3487
+ };
3399
3488
  const query = useQuery({
3400
3489
  queryKey: [url, JSON.stringify(params)],
3401
- queryFn: () => {
3402
- return axios
3403
- .get(url, {
3404
- params,
3405
- })
3406
- .then((res) => res.data);
3407
- },
3408
- placeholderData: {
3409
- count: 0,
3410
- data: [],
3411
- },
3490
+ queryFn: customQueryFn !== undefined
3491
+ ? () => customQueryFn(params)
3492
+ : defaultQueryFn,
3493
+ placeholderData,
3412
3494
  });
3413
3495
  const translate = useTranslation("", { keyPrefix });
3414
3496
  return {
@@ -3498,7 +3580,71 @@ const getColumns = ({ schema, include = [], ignore = [], width = [], meta = {},
3498
3580
  return columns;
3499
3581
  };
3500
3582
 
3501
- const AccordionItemTrigger = React.forwardRef(function AccordionItemTrigger(props, ref) {
3583
+ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
3584
+ const { columns, translate, data } = useDataTableContext();
3585
+ const columnsMap = Object.fromEntries(columns.map((def) => {
3586
+ const { accessorKey, id } = def;
3587
+ if (accessorKey) {
3588
+ return [accessorKey, def];
3589
+ }
3590
+ return [id, def];
3591
+ }));
3592
+ const columnHeaders = Object.keys(columnsMap);
3593
+ const totalWidths = columns
3594
+ .map(({ size }) => {
3595
+ if (!!size === false) {
3596
+ return 0;
3597
+ }
3598
+ if (typeof size === "number") {
3599
+ return size;
3600
+ }
3601
+ return 0;
3602
+ })
3603
+ .reduce((previous, current) => previous + current, 0);
3604
+ const columnWidths = columns
3605
+ .map(({ size }) => {
3606
+ if (!!size === false) {
3607
+ return "1fr";
3608
+ }
3609
+ return `minmax(${size}px, ${(size / totalWidths) * 100}%)`;
3610
+ })
3611
+ .join(" ");
3612
+ console.log({ columnWidths }, "hadfg");
3613
+ const cellProps = {
3614
+ flex: "1 0 0%",
3615
+ overflow: "auto",
3616
+ paddingX: "2",
3617
+ py: "1",
3618
+ color: { base: "colorPalette.900", _dark: "colorPalette.100" },
3619
+ bgColor: { base: "colorPalette.50", _dark: "colorPalette.950" },
3620
+ borderBottomColor: { base: "colorPalette.200", _dark: "colorPalette.800" },
3621
+ borderBottomWidth: "1px",
3622
+ ...{ colorPalette },
3623
+ };
3624
+ if (data.length <= 0) {
3625
+ return jsx(Fragment, { children: emptyComponent });
3626
+ }
3627
+ return (jsxs(Grid, { templateColumns: `${columnWidths}`, overflow: "auto", borderWidth: "1px", color: { base: "colorPalette.900", _dark: "colorPalette.100" }, borderColor: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: [jsx(Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: "colorPalette.200", _dark: "colorPalette.800" }, colorPalette, children: columnHeaders.map((header) => {
3628
+ return (jsx(Box, { flex: "1 0 0%", paddingX: "2", py: "1", overflow: "auto", textOverflow: "ellipsis", children: translate.t(`column_header.${header}`) }));
3629
+ }) }), data.map((record) => {
3630
+ return (jsx(Fragment, { children: columnHeaders.map((header) => {
3631
+ const { cell } = columnsMap[header];
3632
+ const value = record[header];
3633
+ if (!!record === false) {
3634
+ return (jsx(Box, { ...cellProps, children: translate.t(`column_cell.placeholder`) }));
3635
+ }
3636
+ if (cell) {
3637
+ return (jsx(Box, { ...cellProps, children: cell({ row: { original: record } }) }));
3638
+ }
3639
+ if (typeof value === "object") {
3640
+ return (jsx(Box, { ...cellProps, children: jsx(RecordDisplay, { object: value }) }));
3641
+ }
3642
+ return jsx(Box, { ...cellProps, children: value });
3643
+ }) }));
3644
+ })] }));
3645
+ };
3646
+
3647
+ const AccordionItemTrigger = React.forwardRef(function AccordionItemTrigger(props, ref) {
3502
3648
  const { children, indicatorPlacement = "end", ...rest } = props;
3503
3649
  return (jsxs(Accordion.ItemTrigger, { ...rest, ref: ref, children: [indicatorPlacement === "start" && (jsx(Accordion.ItemIndicator, { rotate: { base: "-90deg", _open: "0deg" }, children: jsx(LuChevronDown, {}) })), jsx(HStack, { gap: "4", flex: "1", textAlign: "start", width: "full", children: children }), indicatorPlacement === "end" && (jsx(Accordion.ItemIndicator, { children: jsx(LuChevronDown, {}) }))] }));
3504
3650
  });
@@ -3519,6 +3665,12 @@ const SchemaFormContext = createContext({
3519
3665
  onSubmit: async () => { },
3520
3666
  rowNumber: 0,
3521
3667
  requestOptions: {},
3668
+ timezone: 'Asia/Hong_Kong',
3669
+ displayConfig: {
3670
+ showSubmitButton: true,
3671
+ showResetButton: true,
3672
+ showTitle: true,
3673
+ },
3522
3674
  });
3523
3675
 
3524
3676
  const useSchemaContext = () => {
@@ -3529,6 +3681,24 @@ const clearEmptyString = (object) => {
3529
3681
  return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
3530
3682
  };
3531
3683
 
3684
+ const validateData = (data, schema) => {
3685
+ const ajv = new Ajv({
3686
+ strict: false,
3687
+ allErrors: true,
3688
+ });
3689
+ addFormats(ajv);
3690
+ addErrors(ajv);
3691
+ const validate = ajv.compile(schema);
3692
+ const validationResult = validate(data);
3693
+ const errors = validate.errors;
3694
+ console.log(errors, data);
3695
+ return {
3696
+ isValid: validationResult,
3697
+ validate,
3698
+ errors,
3699
+ };
3700
+ };
3701
+
3532
3702
  const idPickerSanityCheck = (column, foreign_key) => {
3533
3703
  if (!!foreign_key == false) {
3534
3704
  throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
@@ -3544,7 +3714,11 @@ const idPickerSanityCheck = (column, foreign_key) => {
3544
3714
  throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
3545
3715
  }
3546
3716
  };
3547
- const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, }) => {
3717
+ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, displayConfig = {
3718
+ showSubmitButton: true,
3719
+ showResetButton: true,
3720
+ showTitle: true,
3721
+ }, }) => {
3548
3722
  const [isSuccess, setIsSuccess] = useState(false);
3549
3723
  const [isError, setIsError] = useState(false);
3550
3724
  const [isSubmiting, setIsSubmiting] = useState(false);
@@ -3577,11 +3751,13 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3577
3751
  error,
3578
3752
  setError,
3579
3753
  getUpdatedData,
3754
+ customErrorRenderer,
3755
+ displayConfig,
3580
3756
  }, children: jsx(FormProvider, { ...form, children: children }) }));
3581
3757
  };
3582
3758
 
3583
3759
  function removeIndex(str) {
3584
- return str.replace(/\.\d+\./g, '.');
3760
+ return str.replace(/\.\d+\./g, ".");
3585
3761
  }
3586
3762
 
3587
3763
  const ArrayRenderer = ({ schema, column, prefix, }) => {
@@ -3593,13 +3769,17 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3593
3769
  const isRequired = required?.some((columnId) => columnId === column);
3594
3770
  const { formState: { errors }, setValue, watch, } = useFormContext();
3595
3771
  const fields = (watch(colLabel) ?? []);
3596
- return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsx("span", { children: "*" })] }), fields.map((field, index) => (jsxs(Flex, { flexFlow: "column", children: [jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: jsx(SchemaRenderer, { column: `${index}`,
3597
- prefix: `${colLabel}.`,
3598
- schema: items }) }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { variant: "ghost", onClick: () => {
3599
- setValue(colLabel, fields.filter((_, curIndex) => {
3600
- return curIndex === index;
3601
- }));
3602
- }, children: translate.t(removeIndex(`${colLabel}.remove`)) }) })] }, `${colLabel}.${index}`))), jsx(Flex, { children: jsx(Button$1, { onClick: () => {
3772
+ return (jsxs(Flex, { gridRow, gridColumn, flexFlow: "column", gap: 2, children: [jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Flex, { flexFlow: "column", gap: 2, children: fields.map((field, index) => (jsxs(Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
3773
+ base: "colorPalette.200",
3774
+ _dark: "colorPalette.800",
3775
+ }, children: [jsx(Grid, { gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsx(SchemaRenderer, { column: `${index}`,
3776
+ prefix: `${colLabel}.`,
3777
+ // @ts-expect-error find suitable types
3778
+ schema: { showLabel: false, ...(items ?? {}) } }) }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { variant: "ghost", onClick: () => {
3779
+ setValue(colLabel, fields.filter((_, curIndex) => {
3780
+ return curIndex !== index;
3781
+ }));
3782
+ }, children: jsx(Icon, { children: jsx(CgTrash, {}) }) }) })] }, `${colLabel}.${index}`))) }), jsx(Flex, { children: jsx(Button$1, { onClick: () => {
3603
3783
  if (type === "number") {
3604
3784
  setValue(colLabel, [...fields, 0]);
3605
3785
  return;
@@ -3613,7 +3793,7 @@ const ArrayRenderer = ({ schema, column, prefix, }) => {
3613
3793
  return;
3614
3794
  }
3615
3795
  setValue(colLabel, [...fields, {}]);
3616
- }, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
3796
+ }, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
3617
3797
  };
3618
3798
 
3619
3799
  const Field = React.forwardRef(function Field(props, ref) {
@@ -3624,37 +3804,36 @@ const Field = React.forwardRef(function Field(props, ref) {
3624
3804
  const BooleanPicker = ({ schema, column, prefix }) => {
3625
3805
  const { watch, formState: { errors }, setValue, } = useFormContext();
3626
3806
  const { translate } = useSchemaContext();
3627
- const { required, gridColumn, gridRow } = schema;
3807
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
3628
3808
  const isRequired = required?.some((columnId) => columnId === column);
3629
3809
  const colLabel = `${prefix}${column}`;
3630
3810
  const value = watch(colLabel);
3631
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3811
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3632
3812
  gridRow, children: [jsx(CheckboxCard, { checked: value, variant: "surface", onChange: () => {
3633
3813
  setValue(colLabel, !value);
3634
- } }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
3814
+ } }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
3815
+ };
3816
+
3817
+ const CustomInput = ({ column, schema, prefix }) => {
3818
+ const formContext = useFormContext();
3819
+ const { inputRender } = schema;
3820
+ return (inputRender &&
3821
+ inputRender({
3822
+ column,
3823
+ schema,
3824
+ prefix,
3825
+ formContext,
3826
+ }));
3635
3827
  };
3636
3828
 
3637
- const monthNamesShort = [
3638
- "Jan",
3639
- "Feb",
3640
- "Mar",
3641
- "Apr",
3642
- "May",
3643
- "Jun",
3644
- "Jul",
3645
- "Aug",
3646
- "Sep",
3647
- "Oct",
3648
- "Nov",
3649
- "Dec",
3650
- ];
3651
- const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
3652
3829
  const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
3830
+ const { labels } = useContext(DatePickerContext);
3831
+ const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
3653
3832
  if (calendars.length) {
3654
3833
  return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns: "repeat(4, auto)", justifyContent: "center", children: [jsx(Button$1, { variant: "ghost", ...getBackProps({
3655
3834
  calendars,
3656
3835
  offset: 12,
3657
- }), children: "<<" }), jsx(Button$1, { variant: "ghost", ...getBackProps({ calendars }), children: "Back" }), jsx(Button$1, { variant: "ghost", ...getForwardProps({ calendars }), children: "Next" }), jsx(Button$1, { variant: "ghost", ...getForwardProps({
3836
+ }), children: "<<" }), jsx(Button$1, { variant: "ghost", ...getBackProps({ calendars }), children: backButtonLabel }), jsx(Button$1, { variant: "ghost", ...getForwardProps({ calendars }), children: forwardButtonLabel }), jsx(Button$1, { variant: "ghost", ...getForwardProps({
3658
3837
  calendars,
3659
3838
  offset: 12,
3660
3839
  }), children: ">>" })] }), jsx(Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: "center", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxs(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [[0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
@@ -3697,9 +3876,52 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
3697
3876
  }
3698
3877
  return null;
3699
3878
  };
3879
+ const DatePickerContext = createContext({
3880
+ labels: {
3881
+ monthNamesShort: [
3882
+ "Jan",
3883
+ "Feb",
3884
+ "Mar",
3885
+ "Apr",
3886
+ "May",
3887
+ "Jun",
3888
+ "Jul",
3889
+ "Aug",
3890
+ "Sep",
3891
+ "Oct",
3892
+ "Nov",
3893
+ "Dec",
3894
+ ],
3895
+ weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
3896
+ backButtonLabel: "Back",
3897
+ forwardButtonLabel: "Next",
3898
+ },
3899
+ });
3700
3900
  let DatePicker$1 = class DatePicker extends React__default.Component {
3701
3901
  render() {
3702
- return (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) => (jsx(Calendar, { ...dayzedData, firstDayOfWeek: this.props.firstDayOfWeek })) }));
3902
+ const { labels = {
3903
+ monthNamesShort: [
3904
+ "Jan",
3905
+ "Feb",
3906
+ "Mar",
3907
+ "Apr",
3908
+ "May",
3909
+ "Jun",
3910
+ "Jul",
3911
+ "Aug",
3912
+ "Sep",
3913
+ "Oct",
3914
+ "Nov",
3915
+ "Dec",
3916
+ ],
3917
+ weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
3918
+ backButtonLabel: "Back",
3919
+ forwardButtonLabel: "Next",
3920
+ }, } = this.props;
3921
+ return (jsx(DatePickerContext.Provider, { value: { labels }, children: 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:
3922
+ // @ts-expect-error - Dayzed types need to be fixed
3923
+ (dayzedData) => (jsx(Calendar, { ...dayzedData,
3924
+ firstDayOfWeek: this.props.firstDayOfWeek })) }) }));
3703
3925
  }
3704
3926
  };
3705
3927
 
@@ -3721,28 +3943,144 @@ const PopoverRoot = Popover.Root;
3721
3943
  const PopoverBody = Popover.Body;
3722
3944
  const PopoverTrigger = Popover.Trigger;
3723
3945
 
3946
+ /**
3947
+ * Custom hook to simplify i18n translation for form fields.
3948
+ * Automatically handles colLabel construction and removeIndex logic.
3949
+ *
3950
+ * @param column - The column name
3951
+ * @param prefix - The prefix for the field (usually empty string or parent path)
3952
+ * @returns Object with translation helper functions
3953
+ *
3954
+ * @example
3955
+ * ```tsx
3956
+ * const formI18n = useFormI18n(column, prefix);
3957
+ *
3958
+ * // Get field label
3959
+ * <Field label={formI18n.label()} />
3960
+ *
3961
+ * // Get error message
3962
+ * <Text>{formI18n.required()}</Text>
3963
+ *
3964
+ * // Get custom translation key
3965
+ * <Text>{formI18n.t('add_more')}</Text>
3966
+ *
3967
+ * // Access the raw colLabel
3968
+ * const colLabel = formI18n.colLabel;
3969
+ * ```
3970
+ */
3971
+ const useFormI18n = (column, prefix = "") => {
3972
+ const { translate } = useSchemaContext();
3973
+ const colLabel = `${prefix}${column}`;
3974
+ return {
3975
+ /**
3976
+ * The constructed column label (prefix + column)
3977
+ */
3978
+ colLabel,
3979
+ /**
3980
+ * Get the field label translation
3981
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.field_label`))
3982
+ */
3983
+ label: (options) => {
3984
+ return translate.t(removeIndex(`${colLabel}.field_label`), options);
3985
+ },
3986
+ /**
3987
+ * Get the required error message translation
3988
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
3989
+ */
3990
+ required: (options) => {
3991
+ return translate.t(removeIndex(`${colLabel}.field_required`), options);
3992
+ },
3993
+ /**
3994
+ * Get a translation for any custom key relative to the field
3995
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
3996
+ *
3997
+ * @param key - The translation key suffix (e.g., 'add_more', 'total', etc.)
3998
+ * @param options - Optional translation options (e.g., defaultValue, interpolation variables)
3999
+ */
4000
+ t: (key, options) => {
4001
+ return translate.t(removeIndex(`${colLabel}.${key}`), options);
4002
+ },
4003
+ /**
4004
+ * Access to the original translate object for edge cases
4005
+ */
4006
+ translate,
4007
+ };
4008
+ };
4009
+
4010
+ dayjs.extend(utc);
4011
+ dayjs.extend(timezone);
3724
4012
  const DatePicker = ({ column, schema, prefix }) => {
3725
4013
  const { watch, formState: { errors }, setValue, } = useFormContext();
3726
- const { translate } = useSchemaContext();
3727
- const { required, gridColumn, gridRow } = schema;
4014
+ const { timezone } = useSchemaContext();
4015
+ const formI18n = useFormI18n(column, prefix);
4016
+ const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD", } = schema;
3728
4017
  const isRequired = required?.some((columnId) => columnId === column);
3729
- const colLabel = `${prefix}${column}`;
4018
+ const colLabel = formI18n.colLabel;
3730
4019
  const [open, setOpen] = useState(false);
3731
4020
  const selectedDate = watch(colLabel);
3732
- const formatedDate = dayjs(selectedDate).format("YYYY-MM-DD");
3733
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3734
- gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsx(Button, { size: "sm", variant: "outline", onClick: () => {
4021
+ const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
4022
+ useEffect(() => {
4023
+ try {
4024
+ if (selectedDate) {
4025
+ // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
4026
+ // For example, parse as UTC:
4027
+ const parsedDate = dayjs(selectedDate).tz(timezone);
4028
+ if (!parsedDate.isValid())
4029
+ return;
4030
+ // Format according to dateFormat from schema
4031
+ const formatted = parsedDate.format(dateFormat);
4032
+ // Update the form value only if different to avoid loops
4033
+ if (formatted !== selectedDate) {
4034
+ setValue(colLabel, formatted, {
4035
+ shouldValidate: true,
4036
+ shouldDirty: true,
4037
+ });
4038
+ }
4039
+ }
4040
+ }
4041
+ catch (e) {
4042
+ console.error(e);
4043
+ }
4044
+ }, [selectedDate, dateFormat, colLabel, setValue]);
4045
+ return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
4046
+ gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
3735
4047
  setOpen(true);
3736
- }, children: selectedDate !== undefined ? `${formatedDate}` : "" }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1
3737
- // @ts-expect-error TODO: find appropriate types
3738
- , {
3739
- // @ts-expect-error TODO: find appropriate types
3740
- selected: new Date(selectedDate),
3741
- // @ts-expect-error TODO: find appropriate types
3742
- onDateSelected: ({ date }) => {
3743
- setValue(colLabel, dayjs(date).format("YYYY-MM-DD"));
4048
+ }, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4049
+ setValue(colLabel, dayjs(date).format(dateFormat));
3744
4050
  setOpen(false);
3745
- } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4051
+ }, labels: {
4052
+ monthNamesShort: [
4053
+ formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
4054
+ formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
4055
+ formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
4056
+ formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
4057
+ formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
4058
+ formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
4059
+ formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
4060
+ formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
4061
+ formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
4062
+ formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
4063
+ formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
4064
+ formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
4065
+ ],
4066
+ weekdayNamesShort: [
4067
+ formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
4068
+ formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
4069
+ formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
4070
+ formI18n.translate.t(`common.weekday_4`, {
4071
+ defaultValue: "Wed",
4072
+ }),
4073
+ formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
4074
+ formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
4075
+ formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
4076
+ ],
4077
+ backButtonLabel: formI18n.translate.t(`common.back_button`, {
4078
+ defaultValue: "Back",
4079
+ }),
4080
+ forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
4081
+ defaultValue: "Forward",
4082
+ }),
4083
+ } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
3746
4084
  };
3747
4085
 
3748
4086
  function filterArray(array, searchTerm) {
@@ -3755,12 +4093,12 @@ function filterArray(array, searchTerm) {
3755
4093
  });
3756
4094
  }
3757
4095
 
3758
- const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
4096
+ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
3759
4097
  const { watch, formState: { errors }, setValue, } = useFormContext();
3760
4098
  const { translate } = useSchemaContext();
3761
- const { required } = schema;
4099
+ const { required, variant } = schema;
3762
4100
  const isRequired = required?.some((columnId) => columnId === column);
3763
- const { gridColumn, gridRow, renderDisplay } = schema;
4101
+ const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
3764
4102
  const [searchText, setSearchText] = useState();
3765
4103
  const [limit, setLimit] = useState(10);
3766
4104
  const [openSearchResult, setOpenSearchResult] = useState();
@@ -3775,28 +4113,61 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
3775
4113
  setSearchText(event.target.value);
3776
4114
  setLimit(10);
3777
4115
  };
3778
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4116
+ if (variant === "radio") {
4117
+ return (jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4118
+ gridRow, children: jsx(RadioGroup$1.Root, { defaultValue: "1", children: jsx(HStack, { gap: "6", children: filterArray(dataList, searchText ?? "").map((item) => {
4119
+ return (jsxs(RadioGroup$1.Item, { onClick: () => {
4120
+ if (!isMultiple) {
4121
+ setOpenSearchResult(false);
4122
+ setValue(colLabel, item);
4123
+ return;
4124
+ }
4125
+ const newSet = new Set([...(watchEnums ?? []), item]);
4126
+ setValue(colLabel, [...newSet]);
4127
+ }, value: item, children: [jsx(RadioGroup$1.ItemHiddenInput, {}), jsx(RadioGroup$1.ItemIndicator, {}), jsx(RadioGroup$1.ItemText, { children: !!renderDisplay === true
4128
+ ? renderDisplay(item)
4129
+ : translate.t(removeIndex(`${colLabel}.${item}`)) })] }, `${colLabel}-${item}`));
4130
+ }) }) }) }));
4131
+ }
4132
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
3779
4133
  gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchEnums.map((enumValue) => {
3780
4134
  const item = enumValue;
3781
- if (item === undefined) {
3782
- return jsx(Fragment, { children: "undefined" });
4135
+ if (!!item === false) {
4136
+ return jsx(Fragment, {});
3783
4137
  }
3784
- return (jsx(Tag, { closable: true, onClick: () => {
3785
- // setSelectedEnums((state) => state.filter((id) => id != item));
4138
+ return (jsx(Tag, { size: "lg", closable: true, onClick: () => {
3786
4139
  setValue(column, watchEnums.filter((id) => id != item));
3787
4140
  }, children: !!renderDisplay === true
3788
4141
  ? renderDisplay(item)
3789
- : translate.t(removeIndex(`${colLabel}.${item}`)) }));
3790
- }), jsx(Tag, { cursor: "pointer", onClick: () => {
4142
+ : translate.t(removeIndex(`${colLabel}.${item}`)) }, item));
4143
+ }), jsx(Tag, { size: "lg", cursor: "pointer", onClick: () => {
3791
4144
  setOpenSearchResult(true);
3792
- }, children: translate.t(removeIndex(`${colLabel}.addMore`)) })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
4145
+ }, children: translate.t(removeIndex(`${colLabel}.add_more`)) }, `${colLabel}-add-more-tag`)] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
3793
4146
  setOpenSearchResult(true);
3794
- }, children: watchEnum === undefined
4147
+ }, justifyContent: "start", children: !!watchEnum === false
3795
4148
  ? ""
3796
- : translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${column}.typeToSearch`), onChange: (event) => {
4149
+ : translate.t(removeIndex(`${colLabel}.${watchEnum ?? "null"}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { portalled: false, children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
3797
4150
  onSearchChange(event);
3798
4151
  setOpenSearchResult(true);
3799
- }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), jsx(Text, { children: `${translate.t(`${column}.total`)}: ${count}, ${translate.t(`${column}.showing`)} ${limit}` }), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children: filterArray(dataList, searchText ?? "").map((item) => {
4152
+ }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), showTotalAndLimit && (jsx(Text, { children: `${translate.t(removeIndex(`${colLabel}.total`))}: ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` })), jsxs(Grid, { overflow: "auto", maxHeight: "20rem", children: [jsx(Flex, { flexFlow: "column wrap", children: dataList
4153
+ .filter((item) => {
4154
+ const searchTerm = (searchText || "").toLowerCase();
4155
+ if (!searchTerm)
4156
+ return true;
4157
+ // Check if the original enum value contains the search text
4158
+ const enumValueMatch = item
4159
+ .toLowerCase()
4160
+ .includes(searchTerm);
4161
+ // Check if the display value (translation) contains the search text
4162
+ const displayValue = !!renderDisplay === true
4163
+ ? renderDisplay(item)
4164
+ : translate.t(removeIndex(`${colLabel}.${item}`));
4165
+ // Convert to string and check if it includes the search term
4166
+ const displayValueString = String(displayValue).toLowerCase();
4167
+ const displayValueMatch = displayValueString.includes(searchTerm);
4168
+ return enumValueMatch || displayValueMatch;
4169
+ })
4170
+ .map((item) => {
3800
4171
  const selected = isMultiple
3801
4172
  ? watchEnums.some((enumValue) => item === enumValue)
3802
4173
  : watchEnum == item;
@@ -3808,10 +4179,10 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, }) => {
3808
4179
  }
3809
4180
  const newSet = new Set([...(watchEnums ?? []), item]);
3810
4181
  setValue(colLabel, [...newSet]);
3811
- }, ...(selected ? { color: "gray.400/50" } : {}), children: !!renderDisplay === true
4182
+ }, ...(selected ? { color: "colorPalette.400/50" } : {}), children: !!renderDisplay === true
3812
4183
  ? renderDisplay(item)
3813
4184
  : translate.t(removeIndex(`${colLabel}.${item}`)) }, `${colLabel}-${item}`));
3814
- }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: translate.t(removeIndex(`${colLabel}.emptySearchResult`)) })) }))] })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4185
+ }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Fragment, { children: translate.t(removeIndex(`${colLabel}.empty_search_result`)) })) }))] })] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
3815
4186
  };
3816
4187
 
3817
4188
  function isEnteringWindow(_ref) {
@@ -4163,17 +4534,17 @@ const FileDropzone = ({ children = undefined, gridProps = {}, onDrop = () => { }
4163
4534
  const filesArray = [...event.target.files];
4164
4535
  onDrop({ files: filesArray });
4165
4536
  };
4166
- return (jsxs(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 && (jsxs(Fragment, { children: [jsx(Flex, { children: placeholder }), jsx(Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
4537
+ return (jsxs(Grid, { ...getColor(isDraggedOver), ref: ref, cursor: "pointer", onClick: handleClick, borderStyle: "dashed", borderColor: "colorPalette.400", alignContent: "center", justifyContent: "center", borderWidth: 1, borderRadius: 4, ...gridProps, children: [children, !!children === false && (jsxs(Fragment, { children: [jsx(Flex, { children: placeholder }), jsx(Input, { type: "file", multiple: true, style: { display: "none" }, ref: fileInput, onChange: handleChange })] }))] }));
4167
4538
  };
4168
4539
 
4169
4540
  const FilePicker = ({ column, schema, prefix }) => {
4170
4541
  const { setValue, formState: { errors }, watch, } = useFormContext();
4171
4542
  const { translate } = useSchemaContext();
4172
- const { required, gridColumn, gridRow } = schema;
4543
+ const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
4173
4544
  const isRequired = required?.some((columnId) => columnId === column);
4174
4545
  const currentFiles = (watch(column) ?? []);
4175
4546
  const colLabel = `${prefix}${column}`;
4176
- return (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: [jsx(FileDropzone, { onDrop: ({ files }) => {
4547
+ return (jsxs(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: [jsx(FileDropzone, { onDrop: ({ files }) => {
4177
4548
  const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4178
4549
  setValue(colLabel, [...currentFiles, ...newFiles]);
4179
4550
  }, placeholder: translate.t(removeIndex(`${colLabel}.fileDropzone`)) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
@@ -4181,10 +4552,19 @@ const FilePicker = ({ column, schema, prefix }) => {
4181
4552
  setValue(column, currentFiles.filter(({ name }) => {
4182
4553
  return name !== file.name;
4183
4554
  }));
4184
- }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
4185
- }) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4555
+ }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
4556
+ }) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4186
4557
  };
4187
4558
 
4559
+ const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
4560
+ const { showArrow, children, portalled = true, content, portalRef, ...rest } = props;
4561
+ return (jsxs(Popover.Root, { ...rest, positioning: { ...rest.positioning, gutter: 4 }, children: [jsx(Popover.Trigger, { asChild: true, children: children }), jsx(Portal, { disabled: !portalled, container: portalRef, children: jsx(Popover.Positioner, { children: jsxs(Popover.Content, { width: "auto", px: "2", py: "1", textStyle: "xs", rounded: "sm", ref: ref, children: [showArrow && (jsx(Popover.Arrow, { children: jsx(Popover.ArrowTip, {}) })), content] }) }) })] }));
4562
+ });
4563
+ const InfoTip = React.forwardRef(function InfoTip(props, ref) {
4564
+ const { children, ...rest } = props;
4565
+ return (jsx(ToggleTip, { content: children, ...rest, ref: ref, children: jsx(IconButton, { variant: "ghost", "aria-label": "info", size: "2xs", colorPalette: "colorPalette", children: jsx(HiOutlineInformationCircle, {}) }) }));
4566
+ });
4567
+
4188
4568
  const getTableData = async ({ serverUrl, in_table, searching = "", where = [], limit = 10, offset = 0, }) => {
4189
4569
  if (serverUrl === undefined || serverUrl.length == 0) {
4190
4570
  throw new Error("The serverUrl is missing");
@@ -4215,25 +4595,40 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
4215
4595
 
4216
4596
  const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4217
4597
  const { watch, formState: { errors }, setValue, } = useFormContext();
4218
- const { serverUrl, idMap, setIdMap, translate, schema: parentSchema, } = useSchemaContext();
4219
- const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
4598
+ const { serverUrl, idMap, setIdMap, schema: parentSchema, } = useSchemaContext();
4599
+ const formI18n = useFormI18n(column, prefix);
4600
+ const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
4220
4601
  const isRequired = required?.some((columnId) => columnId === column);
4221
- const { table, column: column_ref, display_column, } = foreign_key;
4222
- const [searchText, setSearchText] = useState();
4602
+ const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
4603
+ const [searchText, setSearchText] = useState("");
4223
4604
  const [limit, setLimit] = useState(10);
4224
4605
  const [openSearchResult, setOpenSearchResult] = useState();
4225
4606
  const [page, setPage] = useState(0);
4226
4607
  const ref = useRef(null);
4227
- const colLabel = `${prefix}${column}`;
4608
+ const colLabel = formI18n.colLabel;
4609
+ const watchId = watch(colLabel);
4610
+ const watchIds = isMultiple ? (watch(colLabel) ?? []) : [];
4611
+ // Query for search results
4228
4612
  const query = useQuery({
4229
4613
  queryKey: [`idpicker`, { column, searchText, limit, page }],
4230
4614
  queryFn: async () => {
4615
+ if (customQueryFn) {
4616
+ const { data, idMap } = await customQueryFn({
4617
+ searching: searchText ?? "",
4618
+ limit: limit,
4619
+ offset: page * limit,
4620
+ });
4621
+ setIdMap((state) => {
4622
+ return { ...state, ...idMap };
4623
+ });
4624
+ return data;
4625
+ }
4231
4626
  const data = await getTableData({
4232
4627
  serverUrl,
4233
4628
  searching: searchText ?? "",
4234
4629
  in_table: table,
4235
4630
  limit: limit,
4236
- offset: page * 10,
4631
+ offset: page * limit,
4237
4632
  });
4238
4633
  const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
4239
4634
  return [
@@ -4248,27 +4643,38 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4248
4643
  });
4249
4644
  return data;
4250
4645
  },
4251
- enabled: (searchText ?? "")?.length > 0,
4646
+ enabled: openSearchResult === true,
4252
4647
  staleTime: 300000,
4253
4648
  });
4254
- const { isLoading, isFetching, data, isPending, isError } = query;
4255
- const dataList = data?.data ?? [];
4256
- const count = data?.count ?? 0;
4257
- const isDirty = (searchText?.length ?? 0) > 0;
4258
- const watchId = watch(colLabel);
4259
- const watchIds = (watch(colLabel) ?? []);
4260
- useQuery({
4649
+ // Query for currently selected items (to display them properly)
4650
+ const queryDefault = useQuery({
4261
4651
  queryKey: [
4262
- `idpicker`,
4263
- { form: parentSchema.title, column, searchText, limit, page },
4652
+ `idpicker-default`,
4653
+ { form: parentSchema.title, column, id: isMultiple ? watchIds : watchId },
4264
4654
  ],
4265
4655
  queryFn: async () => {
4656
+ if (customQueryFn) {
4657
+ const { data, idMap } = await customQueryFn({
4658
+ searching: watchIds.join(","),
4659
+ limit: isMultiple ? watchIds.length : 1,
4660
+ offset: 0,
4661
+ });
4662
+ setIdMap((state) => {
4663
+ return { ...state, ...idMap };
4664
+ });
4665
+ return data;
4666
+ }
4667
+ if (!watchId && (!watchIds || watchIds.length === 0)) {
4668
+ return { data: [] };
4669
+ }
4670
+ const searchValue = isMultiple ? watchIds.join(",") : watchId;
4266
4671
  const data = await getTableData({
4267
4672
  serverUrl,
4268
- searching: watchId,
4673
+ searching: searchValue,
4269
4674
  in_table: table,
4270
- limit: limit,
4271
- offset: page * 10,
4675
+ where: [{ id: column_ref, value: isMultiple ? watchIds : watchId }],
4676
+ limit: isMultiple ? watchIds.length : 1,
4677
+ offset: 0,
4272
4678
  });
4273
4679
  const newMap = Object.fromEntries((data ?? { data: [] }).data.map((item) => {
4274
4680
  return [
@@ -4283,12 +4689,45 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4283
4689
  });
4284
4690
  return data;
4285
4691
  },
4692
+ enabled: isMultiple
4693
+ ? Array.isArray(watchIds) && watchIds.length > 0
4694
+ : !!watchId,
4286
4695
  });
4696
+ // Effect to load selected values when component mounts
4697
+ useEffect(() => {
4698
+ if (isMultiple ? watchIds.length > 0 : !!watchId) {
4699
+ queryDefault.refetch();
4700
+ }
4701
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4702
+ }, []);
4703
+ // Effect to trigger initial data fetch when popover opens
4704
+ useEffect(() => {
4705
+ if (openSearchResult) {
4706
+ // Reset search text when opening the popover
4707
+ setSearchText("");
4708
+ // Reset page to first page
4709
+ setPage(0);
4710
+ // Fetch initial data
4711
+ query.refetch();
4712
+ }
4713
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4714
+ }, [openSearchResult]);
4287
4715
  const onSearchChange = async (event) => {
4288
4716
  setSearchText(event.target.value);
4289
4717
  setPage(0);
4290
- setLimit(10);
4718
+ query.refetch();
4719
+ };
4720
+ const handleLimitChange = (event) => {
4721
+ const newLimit = Number(event.target.value);
4722
+ setLimit(newLimit);
4723
+ // Reset to first page when changing limit
4724
+ setPage(0);
4725
+ // Trigger a new search with the updated limit
4726
+ query.refetch();
4291
4727
  };
4728
+ const { isLoading, isFetching, data, isPending, isError } = query;
4729
+ const dataList = data?.data ?? [];
4730
+ const count = data?.count ?? 0;
4292
4731
  const getPickedValue = () => {
4293
4732
  if (Object.keys(idMap).length <= 0) {
4294
4733
  return "";
@@ -4297,52 +4736,67 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4297
4736
  if (record === undefined) {
4298
4737
  return "";
4299
4738
  }
4739
+ if (!!renderDisplay === true) {
4740
+ return renderDisplay(record);
4741
+ }
4300
4742
  return record[display_column];
4301
4743
  };
4302
- return (jsxs(Field, { label: `${translate.t(removeIndex(removeIndex(`${column}.fieldLabel`)))}`, required: isRequired, alignItems: "stretch", gridColumn,
4744
+ return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
4303
4745
  gridRow, children: [isMultiple && (jsxs(Flex, { flexFlow: "wrap", gap: 1, children: [watchIds.map((id) => {
4304
4746
  const item = idMap[id];
4305
4747
  if (item === undefined) {
4306
- return (jsx(Text, { children: translate.t(removeIndex(`${colLabel}.undefined`)) }, id));
4748
+ return (jsx(Text, { children: formI18n.t('undefined') }, id));
4307
4749
  }
4308
4750
  return (jsx(Tag, { closable: true, onClick: () => {
4309
- setValue(column, watchIds.filter((id) => id != item[column_ref]));
4751
+ setValue(colLabel, watchIds.filter((itemId) => itemId !== item[column_ref]));
4310
4752
  }, children: !!renderDisplay === true
4311
4753
  ? renderDisplay(item)
4312
4754
  : item[display_column] }, id));
4313
4755
  }), jsx(Tag, { cursor: "pointer", onClick: () => {
4314
4756
  setOpenSearchResult(true);
4315
- }, children: translate.t(removeIndex(`${colLabel}.addMore`)) })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
4757
+ }, children: formI18n.t('add_more') })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
4316
4758
  setOpenSearchResult(true);
4317
- }, children: getPickedValue() })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(removeIndex(`${colLabel}.typeToSearch`)), onChange: (event) => {
4318
- onSearchChange(event);
4319
- setOpenSearchResult(true);
4320
- }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), (searchText?.length ?? 0) > 0 && (jsxs(Fragment, { children: [isFetching && jsx(Fragment, { children: "isFetching" }), isLoading && jsx(Fragment, { children: "isLoading" }), isPending && jsx(Fragment, { children: "isPending" }), (isFetching || isLoading || isPending) && jsx(Spinner, {}), isError && (jsx(Icon, { color: "red.400", children: jsx(BiError, {}) })), jsx(Text, { justifySelf: "center", children: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit}` }), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children:
4321
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4322
- dataList.map((item) => {
4323
- const selected = isMultiple
4324
- ? watchIds.some((id) => item[column_ref] === id)
4325
- : watchId === item[column_ref];
4326
- return (jsx(Box, { cursor: "pointer", onClick: () => {
4327
- if (!isMultiple) {
4328
- setOpenSearchResult(false);
4329
- setValue(colLabel, item[column_ref]);
4330
- return;
4331
- }
4332
- const newSet = new Set([
4333
- ...(watchIds ?? []),
4334
- item[column_ref],
4335
- ]);
4336
- setValue(colLabel, [...newSet]);
4337
- }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected ? { color: "gray.400/50" } : {}), children: !!renderDisplay === true
4338
- ? renderDisplay(item)
4339
- : item[display_column] }, item[column_ref]));
4340
- }) }), isDirty && (jsx(Fragment, { children: dataList.length <= 0 && (jsx(Text, { children: translate.t(removeIndex(`${colLabel}.emptySearchResult`)) })) }))] }), jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: 10, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4759
+ }, justifyContent: "start", children: queryDefault.isLoading ? jsx(Spinner, { size: "sm" }) : getPickedValue() })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { portalled: false, children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: formI18n.t('type_to_search'), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsx(PopoverTitle, {}), openSearchResult && (jsxs(Fragment, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, {}), isError && (jsx(Icon, { color: "red.400", children: jsx(BiError, {}) })), jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxs(Flex, { alignItems: "center", gap: "2", children: [jsx(InfoTip, { children: `${formI18n.t('total')} ${count}, ${formI18n.t('showing')} ${limit} ${formI18n.t('per_page', { defaultValue: 'per page' })}` }), jsxs(Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxs(Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/", " ", count > 0
4760
+ ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}`
4761
+ : "0"] })] })] }), jsx(Box, { children: jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4762
+ padding: "4px 8px",
4763
+ borderRadius: "4px",
4764
+ border: "1px solid #ccc",
4765
+ fontSize: "14px",
4766
+ }, children: [jsx("option", { value: "5", children: "5" }), jsx("option", { value: "10", children: "10" }), jsx("option", { value: "20", children: "20" }), jsx("option", { value: "30", children: "30" })] }) })] }), jsx(Grid, { overflowY: "auto", children: dataList.length > 0 ? (jsx(Flex, { flexFlow: "column wrap", gap: 1, children: dataList.map((item) => {
4767
+ const selected = isMultiple
4768
+ ? watchIds.some((id) => item[column_ref] === id)
4769
+ : watchId === item[column_ref];
4770
+ return (jsx(Box, { cursor: "pointer", onClick: () => {
4771
+ if (!isMultiple) {
4772
+ setOpenSearchResult(false);
4773
+ setValue(colLabel, item[column_ref]);
4774
+ return;
4775
+ }
4776
+ // For multiple selection, don't add if already selected
4777
+ if (selected)
4778
+ return;
4779
+ const newSet = new Set([
4780
+ ...(watchIds ?? []),
4781
+ item[column_ref],
4782
+ ]);
4783
+ setValue(colLabel, [...newSet]);
4784
+ }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
4785
+ ? {
4786
+ color: "colorPalette.400/50",
4787
+ fontWeight: "bold",
4788
+ }
4789
+ : {}), children: !!renderDisplay === true
4790
+ ? renderDisplay(item)
4791
+ : item[display_column] }, item[column_ref]));
4792
+ }) })) : (jsx(Text, { children: searchText
4793
+ ? formI18n.t('empty_search_result')
4794
+ : formI18n.t('initial_results') })) }), jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
4341
4795
  };
4342
4796
 
4343
4797
  const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
4344
4798
  const { children, ...rest } = props;
4345
- return (jsxs(NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: [children, jsxs(NumberInput.Control, { children: [jsx(NumberInput.IncrementTrigger, {}), jsx(NumberInput.DecrementTrigger, {})] })] }));
4799
+ return (jsx(NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: children }));
4346
4800
  });
4347
4801
  const NumberInputField$1 = NumberInput.Input;
4348
4802
  NumberInput.Scrubber;
@@ -4351,17 +4805,17 @@ NumberInput.Label;
4351
4805
  const NumberInputField = ({ schema, column, prefix, }) => {
4352
4806
  const { setValue, formState: { errors }, watch, } = useFormContext();
4353
4807
  const { translate } = useSchemaContext();
4354
- const { required, gridColumn, gridRow } = schema;
4808
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4355
4809
  const isRequired = required?.some((columnId) => columnId === column);
4356
4810
  const colLabel = `${prefix}${column}`;
4357
4811
  const value = watch(`${colLabel}`);
4358
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { children: jsx(NumberInputField$1, { required: isRequired, value: value, onChange: (event) => {
4812
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(NumberInputRoot, { children: jsx(NumberInputField$1, { required: isRequired, value: value, onChange: (event) => {
4359
4813
  setValue(`${colLabel}`, Number(event.target.value));
4360
- } }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4814
+ } }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4361
4815
  };
4362
4816
 
4363
4817
  const ObjectInput = ({ schema, column, prefix }) => {
4364
- const { properties, gridRow, gridColumn = "1/span 12", required } = schema;
4818
+ const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
4365
4819
  const { translate } = useSchemaContext();
4366
4820
  const colLabel = `${prefix}${column}`;
4367
4821
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4369,25 +4823,28 @@ const ObjectInput = ({ schema, column, prefix }) => {
4369
4823
  if (properties === undefined) {
4370
4824
  throw new Error(`properties is undefined when using ObjectInput`);
4371
4825
  }
4372
- return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: Object.keys(properties ?? {}).map((key) => {
4826
+ return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(Grid, { bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
4827
+ base: "colorPalette.200",
4828
+ _dark: "colorPalette.800",
4829
+ }, gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
4373
4830
  return (
4374
4831
  // @ts-expect-error find suitable types
4375
4832
  jsx(ColumnRenderer, { column: `${key}`,
4376
4833
  prefix: `${prefix}${column}.`,
4377
4834
  properties }, `form-${colLabel}-${key}`));
4378
- }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
4835
+ }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4379
4836
  };
4380
4837
 
4381
4838
  const RecordInput$1 = ({ column, schema, prefix }) => {
4382
4839
  const { formState: { errors }, setValue, getValues, } = useFormContext();
4383
4840
  const { translate } = useSchemaContext();
4384
- const { required, gridColumn, gridRow } = schema;
4841
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4385
4842
  const isRequired = required?.some((columnId) => columnId === column);
4386
4843
  const entries = Object.entries(getValues(column) ?? {});
4387
4844
  const [showNewEntries, setShowNewEntries] = useState(false);
4388
4845
  const [newKey, setNewKey] = useState();
4389
4846
  const [newValue, setNewValue] = useState();
4390
- return (jsxs(Field, { label: `${translate.t(`${column}.fieldLabel`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4847
+ return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4391
4848
  return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
4392
4849
  const filtered = entries.filter(([target]) => {
4393
4850
  return target !== key;
@@ -4427,16 +4884,16 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
4427
4884
  setShowNewEntries(true);
4428
4885
  setNewKey(undefined);
4429
4886
  setNewValue(undefined);
4430
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.fieldRequired`) }))] }));
4887
+ }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
4431
4888
  };
4432
4889
 
4433
4890
  const StringInputField = ({ column, schema, prefix, }) => {
4434
4891
  const { register, formState: { errors }, } = useFormContext();
4435
4892
  const { translate } = useSchemaContext();
4436
- const { required, gridColumn, gridRow } = schema;
4893
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4437
4894
  const isRequired = required?.some((columnId) => columnId === column);
4438
4895
  const colLabel = `${prefix}${column}`;
4439
- return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }) }));
4896
+ return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
4440
4897
  };
4441
4898
 
4442
4899
  const RadioCardItem = React.forwardRef(function RadioCardItem(props, ref) {
@@ -4534,9 +4991,574 @@ const TagPicker = ({ column, schema, prefix }) => {
4534
4991
  }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
4535
4992
  };
4536
4993
 
4994
+ const Textarea = 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) => {
4995
+ const contentEditableRef = useRef(null);
4996
+ const isControlled = value !== undefined;
4997
+ // Handle input changes
4998
+ const handleInput = (e) => {
4999
+ const text = e.currentTarget.textContent || "";
5000
+ // Check maxLength if specified
5001
+ if (maxLength && text.length > maxLength) {
5002
+ e.currentTarget.textContent = text.slice(0, maxLength);
5003
+ // Move cursor to end
5004
+ const selection = window.getSelection();
5005
+ if (selection) {
5006
+ selection.selectAllChildren(e.currentTarget);
5007
+ selection.collapseToEnd();
5008
+ }
5009
+ return;
5010
+ }
5011
+ onChange?.(text);
5012
+ };
5013
+ // Handle paste events to strip formatting and respect maxLength
5014
+ const handlePaste = (e) => {
5015
+ e.preventDefault();
5016
+ const text = e.clipboardData.getData('text/plain');
5017
+ const currentText = e.currentTarget.textContent || "";
5018
+ let pasteText = text;
5019
+ if (maxLength) {
5020
+ const remainingLength = maxLength - currentText.length;
5021
+ pasteText = text.slice(0, remainingLength);
5022
+ }
5023
+ document.execCommand('insertText', false, pasteText);
5024
+ };
5025
+ // Set initial content
5026
+ useEffect(() => {
5027
+ if (contentEditableRef.current && !isControlled) {
5028
+ const initialValue = defaultValue || "";
5029
+ if (contentEditableRef.current.textContent !== initialValue) {
5030
+ contentEditableRef.current.textContent = initialValue;
5031
+ }
5032
+ }
5033
+ }, [defaultValue, isControlled]);
5034
+ // Update content when value changes (controlled mode)
5035
+ useEffect(() => {
5036
+ if (contentEditableRef.current && isControlled && value !== undefined) {
5037
+ if (contentEditableRef.current.textContent !== value) {
5038
+ contentEditableRef.current.textContent = value;
5039
+ }
5040
+ }
5041
+ }, [value, isControlled]);
5042
+ // Auto focus
5043
+ useEffect(() => {
5044
+ if (autoFocus && contentEditableRef.current) {
5045
+ contentEditableRef.current.focus();
5046
+ }
5047
+ }, [autoFocus]);
5048
+ // Forward ref
5049
+ useEffect(() => {
5050
+ if (typeof ref === 'function') {
5051
+ ref(contentEditableRef.current);
5052
+ }
5053
+ else if (ref) {
5054
+ ref.current = contentEditableRef.current;
5055
+ }
5056
+ }, [ref]);
5057
+ const textareaElement = (jsx(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: {
5058
+ borderColor: invalid ? "red.500" : "blue.500",
5059
+ boxShadow: `0 0 0 1px ${invalid ? "red.500" : "blue.500"}`,
5060
+ }, _disabled: {
5061
+ opacity: 0.6,
5062
+ cursor: "not-allowed",
5063
+ bg: "gray.50",
5064
+ }, _empty: {
5065
+ _before: {
5066
+ content: placeholder ? `"${placeholder}"` : undefined,
5067
+ color: "gray.400",
5068
+ pointerEvents: "none",
5069
+ }
5070
+ }, whiteSpace: "pre-wrap", overflowWrap: "break-word", overflow: "auto", maxHeight: `${rows * 4}em`, suppressContentEditableWarning: true, ...props }));
5071
+ // If we have additional field props, wrap in Field component
5072
+ if (label || helperText || errorText || required) {
5073
+ return (jsxs(Field$1.Root, { invalid: invalid, required: required, children: [label && (jsxs(Field$1.Label, { children: [label, required && jsx(Field$1.RequiredIndicator, {})] })), textareaElement, helperText && jsx(Field$1.HelperText, { children: helperText }), errorText && jsx(Field$1.ErrorText, { children: errorText })] }));
5074
+ }
5075
+ return textareaElement;
5076
+ });
5077
+ Textarea.displayName = "Textarea";
5078
+
5079
+ const TextAreaInput = ({ column, schema, prefix, }) => {
5080
+ const { register, formState: { errors }, } = useFormContext();
5081
+ const { translate } = useSchemaContext();
5082
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5083
+ const isRequired = required?.some((columnId) => columnId === column);
5084
+ const colLabel = `${prefix}${column}`;
5085
+ const form = useFormContext();
5086
+ const { setValue, watch } = form;
5087
+ const watchValue = watch(colLabel);
5088
+ return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", display: "grid", children: [jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
5089
+ };
5090
+
5091
+ function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
5092
+ am: "am",
5093
+ pm: "pm",
5094
+ }, onChange = (_newValue) => { }, timezone = "Asia/Hong_Kong", }) {
5095
+ const handleClear = () => {
5096
+ setHour(null);
5097
+ setMinute(null);
5098
+ setMeridiem(null);
5099
+ setInputValue("");
5100
+ setShowInput(false);
5101
+ onChange({ hour: null, minute: null, meridiem: null });
5102
+ };
5103
+ const getTimeString = (hour, minute, meridiem) => {
5104
+ if (hour === null || minute === null || meridiem === null) {
5105
+ return "";
5106
+ }
5107
+ // if the hour is 24, set the hour to 0
5108
+ if (hour === 24) {
5109
+ return dayjs().tz(timezone).hour(0).minute(minute).format("HH:mmZ");
5110
+ }
5111
+ // use dayjs to format the time at current timezone
5112
+ // if meridiem is pm, add 12 hours
5113
+ let newHour = hour;
5114
+ if (meridiem === "pm" && hour !== 12) {
5115
+ newHour = hour + 12;
5116
+ }
5117
+ // if the hour is 12, set the meridiem to am, and set the hour to 0
5118
+ else if (meridiem === "am" && hour === 12) {
5119
+ newHour = 0;
5120
+ }
5121
+ return dayjs().tz(timezone).hour(newHour).minute(minute).format("HH:mmZ");
5122
+ };
5123
+ const stringTime = getTimeString(hour, minute, meridiem);
5124
+ const [inputValue, setInputValue] = useState("");
5125
+ const [showInput, setShowInput] = useState(false);
5126
+ const handleBlur = (text) => {
5127
+ // ignore all non-numeric characters
5128
+ if (!text) {
5129
+ return;
5130
+ }
5131
+ const value = text.replace(/[^0-9apm]/g, "");
5132
+ if (value === "") {
5133
+ handleClear();
5134
+ return;
5135
+ }
5136
+ // if the value is a valid time, parse it and set the hour, minute, and meridiem
5137
+ // if the value is not a valid time, set the stringTime to the value
5138
+ // first two characters are the hour
5139
+ // next two characters are the minute
5140
+ // final two characters are the meridiem
5141
+ const hour = parseInt(value.slice(0, 2));
5142
+ const minute = parseInt(value.slice(2, 4));
5143
+ const meridiem = value.slice(4, 6);
5144
+ // validate the hour and minute
5145
+ if (isNaN(hour) || isNaN(minute)) {
5146
+ setInputValue("");
5147
+ return;
5148
+ }
5149
+ // if the hour is larger than 24, set the hour to 24
5150
+ if (hour > 24) {
5151
+ setInputValue("");
5152
+ return;
5153
+ }
5154
+ let newHour = hour;
5155
+ let newMinute = minute;
5156
+ let newMeridiem = meridiem;
5157
+ // if the hour is 24, set the meridiem to am, and set the hour to 0
5158
+ if (hour === 24) {
5159
+ newMeridiem = "am";
5160
+ newHour = 0;
5161
+ }
5162
+ // if the hour is greater than 12, set the meridiem to pm, and subtract 12 from the hour
5163
+ else if (hour > 12) {
5164
+ newMeridiem = "pm";
5165
+ newHour = hour - 12;
5166
+ }
5167
+ // if the hour is 12, set the meridiem to pm, and set the hour to 12
5168
+ else if (hour === 12) {
5169
+ newMeridiem = "pm";
5170
+ newHour = 12;
5171
+ }
5172
+ // if the hour is 0, set the meridiem to am, and set the hour to 12
5173
+ else if (hour === 0) {
5174
+ newMeridiem = "am";
5175
+ newHour = 12;
5176
+ }
5177
+ else {
5178
+ newMeridiem = meridiem ?? "am";
5179
+ newHour = hour;
5180
+ }
5181
+ if (minute > 59) {
5182
+ newMinute = 0;
5183
+ }
5184
+ else {
5185
+ newMinute = minute;
5186
+ }
5187
+ onChange({
5188
+ hour: newHour,
5189
+ minute: newMinute,
5190
+ meridiem: newMeridiem,
5191
+ });
5192
+ setShowInput(false);
5193
+ };
5194
+ const handleKeyDown = (e) => {
5195
+ if (e.key === "Enter") {
5196
+ handleBlur(e.currentTarget.value);
5197
+ }
5198
+ };
5199
+ const inputRef = useRef(null);
5200
+ return (jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "200px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsx(Input, { onKeyDown: handleKeyDown, onChange: (e) => {
5201
+ setInputValue(e.currentTarget.value);
5202
+ }, onBlur: (e) => {
5203
+ handleBlur(e.currentTarget.value);
5204
+ }, onFocus: (e) => {
5205
+ e.currentTarget.select();
5206
+ }, value: inputValue, display: showInput ? undefined : "none", ref: inputRef }), jsxs(Button$1, { onClick: () => {
5207
+ setShowInput(true);
5208
+ setInputValue(dayjs(`1970-01-01T${getTimeString(hour, minute, meridiem)}`, "hh:mmZ").format("HH:mm"));
5209
+ inputRef.current?.focus();
5210
+ }, display: showInput ? "none" : "flex", alignItems: "center", justifyContent: "start", variant: "outline", gap: 2, children: [jsx(Icon, { size: "sm", children: jsx(BsClock, {}) }), jsx(Text, { fontSize: "sm", children: stringTime
5211
+ ? dayjs(`1970-01-01T${stringTime}`, "hh:mmZ").format("hh:mm a")
5212
+ : "" })] }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }));
5213
+ }
5214
+
5215
+ dayjs.extend(timezone);
5216
+ const TimePicker = ({ column, schema, prefix }) => {
5217
+ const { watch, formState: { errors }, setValue, } = useFormContext();
5218
+ const { translate, timezone } = useSchemaContext();
5219
+ const { required, gridColumn = "span 12", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
5220
+ const isRequired = required?.some((columnId) => columnId === column);
5221
+ const colLabel = `${prefix}${column}`;
5222
+ const [open, setOpen] = useState(false);
5223
+ const value = watch(colLabel);
5224
+ const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
5225
+ ? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
5226
+ : "";
5227
+ // Parse the initial time parts from the time string (HH:mm:ssZ)
5228
+ const parseTime = (time) => {
5229
+ if (!time)
5230
+ return { hour: 12, minute: 0, meridiem: "am" };
5231
+ const parsed = dayjs(`1970-01-01T${time}`).tz(timezone);
5232
+ if (!parsed.isValid()) {
5233
+ return { hour: 12, minute: 0, meridiem: "am" };
5234
+ }
5235
+ let hour = parsed.hour();
5236
+ const minute = parsed.minute();
5237
+ const meridiem = hour >= 12 ? "pm" : "am";
5238
+ if (hour === 0)
5239
+ hour = 12;
5240
+ else if (hour > 12)
5241
+ hour -= 12;
5242
+ return { hour, minute, meridiem };
5243
+ };
5244
+ const initialTime = parseTime(value);
5245
+ const [hour, setHour] = useState(initialTime.hour);
5246
+ const [minute, setMinute] = useState(initialTime.minute);
5247
+ const [meridiem, setMeridiem] = useState(initialTime.meridiem);
5248
+ useEffect(() => {
5249
+ const { hour, minute, meridiem } = parseTime(value);
5250
+ setHour(hour);
5251
+ setMinute(minute);
5252
+ setMeridiem(meridiem);
5253
+ }, [value]);
5254
+ const getTimeString = (hour, minute, meridiem) => {
5255
+ if (hour === null || minute === null || meridiem === null)
5256
+ return null;
5257
+ let newHour = hour;
5258
+ if (meridiem === "pm" && hour !== 12) {
5259
+ newHour = hour + 12;
5260
+ }
5261
+ return dayjs().tz(timezone).hour(newHour).minute(minute).second(0).format(timeFormat);
5262
+ };
5263
+ // Handle changes to time parts
5264
+ const handleTimeChange = ({ hour: newHour, minute: newMinute, meridiem: newMeridiem, }) => {
5265
+ setHour(newHour);
5266
+ setMinute(newMinute);
5267
+ setMeridiem(newMeridiem);
5268
+ const timeString = getTimeString(newHour, newMinute, newMeridiem);
5269
+ setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
5270
+ };
5271
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5272
+ gridRow, children: [jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5273
+ setOpen(true);
5274
+ }, justifyContent: "start", children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ""] }) }), jsx(Popover.Positioner, { children: jsx(Popover.Content, { children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
5275
+ am: translate.t(`common.am`, { defaultValue: "AM" }),
5276
+ pm: translate.t(`common.pm`, { defaultValue: "PM" }),
5277
+ } }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5278
+ };
5279
+
5280
+ function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
5281
+ // Refs for focus management
5282
+ const hourInputRef = useRef(null);
5283
+ const minuteInputRef = useRef(null);
5284
+ const secondInputRef = useRef(null);
5285
+ // Centralized handler for key events, value changes, and focus management
5286
+ const handleKeyDown = (e, field) => {
5287
+ const input = e.target;
5288
+ const value = input.value;
5289
+ // Handle navigation between fields
5290
+ if (e.key === "Tab") {
5291
+ return;
5292
+ }
5293
+ if (e.key === ":" && field === "hour") {
5294
+ e.preventDefault();
5295
+ minuteInputRef.current?.focus();
5296
+ return;
5297
+ }
5298
+ if (e.key === ":" && field === "minute") {
5299
+ e.preventDefault();
5300
+ secondInputRef.current?.focus();
5301
+ return;
5302
+ }
5303
+ if (e.key === "Backspace" && value === "") {
5304
+ e.preventDefault();
5305
+ if (field === "minute") {
5306
+ hourInputRef.current?.focus();
5307
+ }
5308
+ else if (field === "second") {
5309
+ minuteInputRef.current?.focus();
5310
+ }
5311
+ return;
5312
+ }
5313
+ // Handle number inputs
5314
+ if (field === "hour") {
5315
+ if (e.key.match(/^[0-9]$/)) {
5316
+ const newValue = value + e.key;
5317
+ const numValue = parseInt(newValue, 10);
5318
+ if (numValue > 23) {
5319
+ const digitValue = parseInt(e.key, 10);
5320
+ setHour(digitValue);
5321
+ onChange({ hour: digitValue, minute, second });
5322
+ return;
5323
+ }
5324
+ if (numValue >= 0 && numValue <= 23) {
5325
+ setHour(numValue);
5326
+ onChange({ hour: numValue, minute, second });
5327
+ e.preventDefault();
5328
+ minuteInputRef.current?.focus();
5329
+ }
5330
+ }
5331
+ }
5332
+ else if (field === "minute") {
5333
+ if (e.key.match(/^[0-9]$/)) {
5334
+ const newValue = value + e.key;
5335
+ const numValue = parseInt(newValue, 10);
5336
+ if (numValue > 59) {
5337
+ const digitValue = parseInt(e.key, 10);
5338
+ setMinute(digitValue);
5339
+ onChange({ hour, minute: digitValue, second });
5340
+ return;
5341
+ }
5342
+ if (numValue >= 0 && numValue <= 59) {
5343
+ setMinute(numValue);
5344
+ onChange({ hour, minute: numValue, second });
5345
+ e.preventDefault();
5346
+ secondInputRef.current?.focus();
5347
+ }
5348
+ }
5349
+ }
5350
+ else if (field === "second") {
5351
+ if (e.key.match(/^[0-9]$/)) {
5352
+ const newValue = value + e.key;
5353
+ const numValue = parseInt(newValue, 10);
5354
+ if (numValue > 59) {
5355
+ const digitValue = parseInt(e.key, 10);
5356
+ setSecond(digitValue);
5357
+ onChange({ hour, minute, second: digitValue });
5358
+ return;
5359
+ }
5360
+ if (numValue >= 0 && numValue <= 59) {
5361
+ setSecond(numValue);
5362
+ onChange({ hour, minute, second: numValue });
5363
+ }
5364
+ }
5365
+ }
5366
+ };
5367
+ const handleClear = () => {
5368
+ setHour(null);
5369
+ setMinute(null);
5370
+ setSecond(null);
5371
+ onChange({ hour: null, minute: null, second: null });
5372
+ hourInputRef.current?.focus();
5373
+ };
5374
+ return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 10px 60px auto", gap: "2", width: "auto", minWidth: "300px", children: [jsx(Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: secondInputRef, type: "text", value: second === null ? "" : second.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "second"), placeholder: "SS", maxLength: 2, textAlign: "center" }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }) }));
5375
+ }
5376
+
5377
+ function DateTimePicker$1({ value, onChange, format = "date-time", showSeconds = false, labels = {
5378
+ monthNamesShort: [
5379
+ "Jan",
5380
+ "Feb",
5381
+ "Mar",
5382
+ "Apr",
5383
+ "May",
5384
+ "Jun",
5385
+ "Jul",
5386
+ "Aug",
5387
+ "Sep",
5388
+ "Oct",
5389
+ "Nov",
5390
+ "Dec",
5391
+ ],
5392
+ weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
5393
+ backButtonLabel: "Back",
5394
+ forwardButtonLabel: "Next",
5395
+ }, timezone = "Asia/Hong_Kong", }) {
5396
+ const [selectedDate, setSelectedDate] = useState(value || "");
5397
+ // Time state for 12-hour format
5398
+ const [hour12, setHour12] = useState(value ? dayjs(value).hour() % 12 || 12 : null);
5399
+ const [minute, setMinute] = useState(value ? dayjs(value).minute() : null);
5400
+ const [meridiem, setMeridiem] = useState(value ? (dayjs(value).hour() >= 12 ? "pm" : "am") : null);
5401
+ // Time state for 24-hour format
5402
+ const [hour24, setHour24] = useState(value ? dayjs(value).hour() : null);
5403
+ const [second, setSecond] = useState(value ? dayjs(value).second() : null);
5404
+ const handleDateChange = (date) => {
5405
+ setSelectedDate(date);
5406
+ updateDateTime(dayjs(date).tz(timezone).toISOString());
5407
+ };
5408
+ const handleTimeChange = (timeData) => {
5409
+ if (format === "iso-date-time") {
5410
+ setHour24(timeData.hour);
5411
+ setMinute(timeData.minute);
5412
+ if (showSeconds)
5413
+ setSecond(timeData.second);
5414
+ }
5415
+ else {
5416
+ setHour12(timeData.hour);
5417
+ setMinute(timeData.minute);
5418
+ setMeridiem(timeData.meridiem);
5419
+ }
5420
+ updateDateTime(dayjs(selectedDate).tz(timezone).toISOString(), timeData);
5421
+ };
5422
+ const updateDateTime = (date, timeData) => {
5423
+ if (!date) {
5424
+ onChange?.(undefined);
5425
+ return;
5426
+ }
5427
+ // use dayjs to convert the date to the timezone
5428
+ const newDate = dayjs(date).tz(timezone).toDate();
5429
+ if (format === "iso-date-time") {
5430
+ const h = timeData?.hour ?? hour24;
5431
+ const m = timeData?.minute ?? minute;
5432
+ const s = showSeconds ? timeData?.second ?? second : 0;
5433
+ if (h !== null)
5434
+ newDate.setHours(h);
5435
+ if (m !== null)
5436
+ newDate.setMinutes(m);
5437
+ if (s !== null)
5438
+ newDate.setSeconds(s);
5439
+ }
5440
+ else {
5441
+ const h = timeData?.hour ?? hour12;
5442
+ const m = timeData?.minute ?? minute;
5443
+ const mer = timeData?.meridiem ?? meridiem;
5444
+ if (h !== null && mer !== null) {
5445
+ let hour24 = h;
5446
+ if (mer === "am" && h === 12)
5447
+ hour24 = 0;
5448
+ else if (mer === "pm" && h < 12)
5449
+ hour24 = h + 12;
5450
+ newDate.setHours(hour24);
5451
+ }
5452
+ if (m !== null)
5453
+ newDate.setMinutes(m);
5454
+ newDate.setSeconds(0);
5455
+ }
5456
+ onChange?.(dayjs(newDate).tz(timezone).toISOString());
5457
+ };
5458
+ const handleClear = () => {
5459
+ setSelectedDate("");
5460
+ setHour12(null);
5461
+ setHour24(null);
5462
+ setMinute(null);
5463
+ setSecond(null);
5464
+ setMeridiem(null);
5465
+ onChange?.(undefined);
5466
+ };
5467
+ const isISO = format === "iso-date-time";
5468
+ return (jsxs(Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsx(DatePicker$1, { selected: selectedDate
5469
+ ? dayjs(selectedDate).tz(timezone).toDate()
5470
+ : new Date(), onDateSelected: ({ date }) => handleDateChange(dayjs(date).tz(timezone).toISOString()), monthsToDisplay: 1, labels: labels }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: second, setSecond: setSecond, onChange: handleTimeChange })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), selectedDate && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).format(isISO
5471
+ ? showSeconds
5472
+ ? "YYYY-MM-DD HH:mm:ss"
5473
+ : "YYYY-MM-DD HH:mm"
5474
+ : "YYYY-MM-DD hh:mm A ") }), jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).tz(timezone).format("Z") }), jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: timezone })] }))] }));
5475
+ }
5476
+
5477
+ dayjs.extend(utc);
5478
+ dayjs.extend(timezone);
5479
+ const DateTimePicker = ({ column, schema, prefix, }) => {
5480
+ const { watch, formState: { errors }, setValue, } = useFormContext();
5481
+ const { timezone } = useSchemaContext();
5482
+ const formI18n = useFormI18n(column, prefix);
5483
+ const { required, gridColumn = "span 12", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
5484
+ // with timezone
5485
+ dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
5486
+ const isRequired = required?.some((columnId) => columnId === column);
5487
+ const colLabel = formI18n.colLabel;
5488
+ const [open, setOpen] = useState(false);
5489
+ const selectedDate = watch(colLabel);
5490
+ const displayDate = dayjs(selectedDate)
5491
+ .tz(timezone)
5492
+ .format(displayDateFormat);
5493
+ useEffect(() => {
5494
+ try {
5495
+ if (selectedDate) {
5496
+ // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
5497
+ // For example, parse as UTC:
5498
+ const parsedDate = dayjs(selectedDate).tz(timezone);
5499
+ if (!parsedDate.isValid())
5500
+ return;
5501
+ // Format according to dateFormat from schema
5502
+ const formatted = parsedDate.format(dateFormat);
5503
+ // Update the form value only if different to avoid loops
5504
+ if (formatted !== selectedDate) {
5505
+ setValue(colLabel, formatted, {
5506
+ shouldValidate: true,
5507
+ shouldDirty: true,
5508
+ });
5509
+ }
5510
+ }
5511
+ }
5512
+ catch (e) {
5513
+ console.error(e);
5514
+ }
5515
+ }, [selectedDate, dateFormat, colLabel, setValue]);
5516
+ return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
5517
+ gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
5518
+ setOpen(true);
5519
+ }, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { minW: "450px", children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
5520
+ setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
5521
+ }, timezone: timezone, labels: {
5522
+ monthNamesShort: [
5523
+ formI18n.translate.t(`common.month_1`, { defaultValue: "January" }),
5524
+ formI18n.translate.t(`common.month_2`, { defaultValue: "February" }),
5525
+ formI18n.translate.t(`common.month_3`, { defaultValue: "March" }),
5526
+ formI18n.translate.t(`common.month_4`, { defaultValue: "April" }),
5527
+ formI18n.translate.t(`common.month_5`, { defaultValue: "May" }),
5528
+ formI18n.translate.t(`common.month_6`, { defaultValue: "June" }),
5529
+ formI18n.translate.t(`common.month_7`, { defaultValue: "July" }),
5530
+ formI18n.translate.t(`common.month_8`, { defaultValue: "August" }),
5531
+ formI18n.translate.t(`common.month_9`, { defaultValue: "September" }),
5532
+ formI18n.translate.t(`common.month_10`, { defaultValue: "October" }),
5533
+ formI18n.translate.t(`common.month_11`, { defaultValue: "November" }),
5534
+ formI18n.translate.t(`common.month_12`, { defaultValue: "December" }),
5535
+ ],
5536
+ weekdayNamesShort: [
5537
+ formI18n.translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
5538
+ formI18n.translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
5539
+ formI18n.translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
5540
+ formI18n.translate.t(`common.weekday_4`, {
5541
+ defaultValue: "Wed",
5542
+ }),
5543
+ formI18n.translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
5544
+ formI18n.translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
5545
+ formI18n.translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
5546
+ ],
5547
+ backButtonLabel: formI18n.translate.t(`common.back_button`, {
5548
+ defaultValue: "Back",
5549
+ }),
5550
+ forwardButtonLabel: formI18n.translate.t(`common.forward_button`, {
5551
+ defaultValue: "Forward",
5552
+ }),
5553
+ } })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
5554
+ };
5555
+
4537
5556
  const SchemaRenderer = ({ schema, prefix, column, }) => {
4538
5557
  const colSchema = schema;
4539
- const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
5558
+ const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
5559
+ if (variant === "custom-input") {
5560
+ return jsx(CustomInput, { schema: colSchema, prefix, column });
5561
+ }
4540
5562
  if (type === "string") {
4541
5563
  if ((schema.enum ?? []).length > 0) {
4542
5564
  return jsx(EnumPicker, { schema: colSchema, prefix, column });
@@ -4545,9 +5567,18 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
4545
5567
  idPickerSanityCheck(column, foreign_key);
4546
5568
  return jsx(IdPicker, { schema: colSchema, prefix, column });
4547
5569
  }
4548
- if (variant === "date-picker") {
5570
+ if (format === "date") {
4549
5571
  return jsx(DatePicker, { schema: colSchema, prefix, column });
4550
5572
  }
5573
+ if (format === "time") {
5574
+ return jsx(TimePicker, { schema: colSchema, prefix, column });
5575
+ }
5576
+ if (format === "date-time") {
5577
+ return jsx(DateTimePicker, { schema: colSchema, prefix, column });
5578
+ }
5579
+ if (variant === "text-area") {
5580
+ return jsx(TextAreaInput, { schema: colSchema, prefix, column });
5581
+ }
4551
5582
  return jsx(StringInputField, { schema: colSchema, prefix, column });
4552
5583
  }
4553
5584
  if (type === "number" || type === "integer") {
@@ -4573,6 +5604,15 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
4573
5604
  if (variant === "file-picker") {
4574
5605
  return jsx(FilePicker, { schema: colSchema, prefix, column });
4575
5606
  }
5607
+ if (variant === "enum-picker") {
5608
+ const { items } = colSchema;
5609
+ const { enum: enumItems } = items;
5610
+ const enumSchema = {
5611
+ type: "string",
5612
+ enum: enumItems,
5613
+ };
5614
+ return (jsx(EnumPicker, { isMultiple: true, schema: enumSchema, prefix, column }));
5615
+ }
4576
5616
  if (items) {
4577
5617
  return jsx(ArrayRenderer, { schema: colSchema, prefix, column });
4578
5618
  }
@@ -4594,85 +5634,95 @@ const ColumnRenderer = ({ column, properties, prefix, }) => {
4594
5634
  };
4595
5635
 
4596
5636
  const ArrayViewer = ({ schema, column, prefix }) => {
4597
- const { gridRow, gridColumn = "1/span 12", required, items } = schema;
5637
+ const { gridColumn = "span 12", gridRow = "span 1", required, items, } = schema;
4598
5638
  const { translate } = useSchemaContext();
4599
5639
  const colLabel = `${prefix}${column}`;
4600
5640
  const isRequired = required?.some((columnId) => columnId === column);
4601
5641
  const { watch, formState: { errors }, } = useFormContext();
4602
5642
  const values = watch(colLabel) ?? [];
4603
- return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsx("span", { children: "*" })] }), values.map((field, index) => (jsx(Flex, { flexFlow: "column", children: jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: jsx(SchemaViewer, { column: `${index}`,
4604
- prefix: `${colLabel}.`,
4605
- schema: items }) }) }, `form-${prefix}${column}.${index}`))), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5643
+ return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Flex, { flexFlow: "column", gap: 1, children: values.map((field, index) => (jsx(Flex, { flexFlow: "column", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "2", borderRadius: "md", borderWidth: "thin", borderColor: {
5644
+ base: "colorPalette.200",
5645
+ _dark: "colorPalette.800",
5646
+ }, children: jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsx(SchemaViewer, { column: `${index}`,
5647
+ prefix: `${colLabel}.`,
5648
+ // @ts-expect-error find suitable types
5649
+ schema: { showLabel: false, ...(items ?? {}) } }) }) }, `form-${prefix}${column}.${index}`))) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4606
5650
  };
4607
5651
 
4608
5652
  const BooleanViewer = ({ schema, column, prefix, }) => {
4609
5653
  const { watch, formState: { errors }, } = useFormContext();
4610
5654
  const { translate } = useSchemaContext();
4611
- const { required, gridColumn, gridRow } = schema;
5655
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4612
5656
  const isRequired = required?.some((columnId) => columnId === column);
4613
5657
  const colLabel = `${prefix}${column}`;
4614
5658
  const value = watch(colLabel);
4615
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5659
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4616
5660
  gridRow, children: [jsx(Text, { children: value
4617
5661
  ? translate.t(removeIndex(`${colLabel}.true`))
4618
- : translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5662
+ : translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5663
+ };
5664
+
5665
+ const CustomViewer = ({ column, schema, prefix }) => {
5666
+ const formContext = useFormContext();
5667
+ const { inputViewerRender } = schema;
5668
+ return (inputViewerRender &&
5669
+ inputViewerRender({
5670
+ column,
5671
+ schema,
5672
+ prefix,
5673
+ formContext,
5674
+ }));
4619
5675
  };
4620
5676
 
4621
5677
  const DateViewer = ({ column, schema, prefix }) => {
4622
5678
  const { watch, formState: { errors }, } = useFormContext();
4623
- const { translate } = useSchemaContext();
4624
- const { required, gridColumn, gridRow } = schema;
5679
+ const { translate, timezone } = useSchemaContext();
5680
+ const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
4625
5681
  const isRequired = required?.some((columnId) => columnId === column);
4626
5682
  const colLabel = `${prefix}${column}`;
4627
5683
  const selectedDate = watch(colLabel);
4628
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4629
- gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? selectedDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.fieldRequired`) }))] }));
5684
+ const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
5685
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5686
+ gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
4630
5687
  };
4631
5688
 
4632
5689
  const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
4633
5690
  const { watch, formState: { errors }, } = useFormContext();
4634
- const { translate } = useSchemaContext();
5691
+ const formI18n = useFormI18n(column, prefix);
4635
5692
  const { required } = schema;
4636
5693
  const isRequired = required?.some((columnId) => columnId === column);
4637
- const { gridColumn, gridRow, renderDisplay } = schema;
4638
- const colLabel = `${prefix}${column}`;
5694
+ const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
5695
+ const colLabel = formI18n.colLabel;
4639
5696
  const watchEnum = watch(colLabel);
4640
5697
  const watchEnums = (watch(colLabel) ?? []);
4641
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5698
+ return (jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
4642
5699
  gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: "wrap", gap: 1, children: watchEnums.map((enumValue) => {
4643
5700
  const item = enumValue;
4644
5701
  if (item === undefined) {
4645
5702
  return jsx(Fragment, { children: "undefined" });
4646
5703
  }
4647
- return (jsx(Tag, { closable: true, children: !!renderDisplay === true
5704
+ return (jsx(Tag, { size: "lg", children: !!renderDisplay === true
4648
5705
  ? renderDisplay(item)
4649
- : translate.t(removeIndex(`${colLabel}.${item}`)) }));
4650
- }) })), !isMultiple && (jsx(Text, { children: translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5706
+ : formI18n.t(item) }, item));
5707
+ }) })), !isMultiple && jsx(Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: formI18n.required() }))] }));
4651
5708
  };
4652
5709
 
4653
5710
  const FileViewer = ({ column, schema, prefix }) => {
4654
- const { setValue, formState: { errors }, watch, } = useFormContext();
5711
+ const { watch } = useFormContext();
4655
5712
  const { translate } = useSchemaContext();
4656
- const { required, gridColumn, gridRow } = schema;
5713
+ const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
4657
5714
  const isRequired = required?.some((columnId) => columnId === column);
4658
5715
  const currentFiles = (watch(column) ?? []);
4659
5716
  const colLabel = `${prefix}${column}`;
4660
- return (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: [jsx(FileDropzone, { onDrop: ({ files }) => {
4661
- const newFiles = files.filter(({ name }) => !currentFiles.some((cur) => cur.name === name));
4662
- setValue(colLabel, [...currentFiles, ...newFiles]);
4663
- }, placeholder: translate.t(`${colLabel}.fileDropzone`) }), jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
4664
- return (jsx(Card.Root, { variant: "subtle", children: jsxs(Card.Body, { gap: "2", cursor: "pointer", onClick: () => {
4665
- setValue(column, currentFiles.filter(({ name }) => {
4666
- return name !== file.name;
4667
- }));
4668
- }, display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [jsx(Box, { children: file.name }), jsx(TiDeleteOutline, {})] }) }, file.name));
4669
- }) }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5717
+ return (jsx(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: jsx(Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
5718
+ return (jsx(Card.Root, { variant: "subtle", children: jsxs(Card.Body, { gap: "2", display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsx(Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsx(Box, { children: file.name })] }) }, file.name));
5719
+ }) }) }));
4670
5720
  };
4671
5721
 
4672
5722
  const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
4673
5723
  const { watch, formState: { errors }, } = useFormContext();
4674
5724
  const { idMap, translate } = useSchemaContext();
4675
- const { required, gridColumn, gridRow, renderDisplay, foreign_key } = schema;
5725
+ const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
4676
5726
  const isRequired = required?.some((columnId) => columnId === column);
4677
5727
  const { display_column } = foreign_key;
4678
5728
  const colLabel = `${prefix}${column}`;
@@ -4688,7 +5738,7 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
4688
5738
  }
4689
5739
  return record[display_column];
4690
5740
  };
4691
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.fieldLabel`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5741
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
4692
5742
  gridRow, children: [isMultiple && (jsx(Flex, { flexFlow: "wrap", gap: 1, children: watchIds.map((id) => {
4693
5743
  const item = idMap[id];
4694
5744
  if (item === undefined) {
@@ -4697,21 +5747,21 @@ const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
4697
5747
  return (jsx(Tag, { closable: true, children: !!renderDisplay === true
4698
5748
  ? renderDisplay(item)
4699
5749
  : item[display_column] }, id));
4700
- }) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5750
+ }) })), !isMultiple && jsx(Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4701
5751
  };
4702
5752
 
4703
5753
  const NumberViewer = ({ schema, column, prefix, }) => {
4704
5754
  const { watch, formState: { errors }, } = useFormContext();
4705
5755
  const { translate } = useSchemaContext();
4706
- const { required, gridColumn, gridRow } = schema;
5756
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4707
5757
  const isRequired = required?.some((columnId) => columnId === column);
4708
5758
  const colLabel = `${prefix}${column}`;
4709
5759
  const value = watch(colLabel);
4710
- return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: value }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5760
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsx(Text, { children: value }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4711
5761
  };
4712
5762
 
4713
5763
  const ObjectViewer = ({ schema, column, prefix }) => {
4714
- const { properties, gridRow, gridColumn = "1/span 12", required } = schema;
5764
+ const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
4715
5765
  const { translate } = useSchemaContext();
4716
5766
  const colLabel = `${prefix}${column}`;
4717
5767
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4719,25 +5769,28 @@ const ObjectViewer = ({ schema, column, prefix }) => {
4719
5769
  if (properties === undefined) {
4720
5770
  throw new Error(`properties is undefined when using ObjectInput`);
4721
5771
  }
4722
- return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: Object.keys(properties ?? {}).map((key) => {
5772
+ return (jsxs(Box, { gridRow, gridColumn, children: [showLabel && (jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] })), jsx(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: {
5773
+ base: "colorPalette.200",
5774
+ _dark: "colorPalette.800",
5775
+ }, children: Object.keys(properties ?? {}).map((key) => {
4723
5776
  return (
4724
5777
  // @ts-expect-error find suitable types
4725
5778
  jsx(ColumnViewer, { column: `${key}`,
4726
5779
  prefix: `${prefix}${column}.`,
4727
5780
  properties }, `form-objectviewer-${colLabel}-${key}`));
4728
- }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }));
5781
+ }) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4729
5782
  };
4730
5783
 
4731
5784
  const RecordInput = ({ column, schema, prefix }) => {
4732
5785
  const { formState: { errors }, setValue, getValues, } = useFormContext();
4733
5786
  const { translate } = useSchemaContext();
4734
- const { required, gridColumn, gridRow } = schema;
5787
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4735
5788
  const isRequired = required?.some((columnId) => columnId === column);
4736
5789
  const entries = Object.entries(getValues(column) ?? {});
4737
5790
  const [showNewEntries, setShowNewEntries] = useState(false);
4738
5791
  const [newKey, setNewKey] = useState();
4739
5792
  const [newValue, setNewValue] = useState();
4740
- return (jsxs(Field, { label: `${translate.t(`${column}.fieldLabel`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
5793
+ return (jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
4741
5794
  return (jsxs(Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsx(Input, { value: key, onChange: (e) => {
4742
5795
  const filtered = entries.filter(([target]) => {
4743
5796
  return target !== key;
@@ -4777,7 +5830,17 @@ const RecordInput = ({ column, schema, prefix }) => {
4777
5830
  setShowNewEntries(true);
4778
5831
  setNewKey(undefined);
4779
5832
  setNewValue(undefined);
4780
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.fieldRequired`) }))] }));
5833
+ }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
5834
+ };
5835
+
5836
+ const StringViewer = ({ column, schema, prefix, }) => {
5837
+ const { watch, formState: { errors }, } = useFormContext();
5838
+ const { translate } = useSchemaContext();
5839
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
5840
+ const isRequired = required?.some((columnId) => columnId === column);
5841
+ const colLabel = `${prefix}${column}`;
5842
+ const value = watch(colLabel);
5843
+ return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsx(Text, { children: value }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
4781
5844
  };
4782
5845
 
4783
5846
  const TagViewer = ({ column, schema, prefix }) => {
@@ -4865,19 +5928,50 @@ const TagViewer = ({ column, schema, prefix }) => {
4865
5928
  }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: (errors[`${column}`]?.message ?? "No error message") }))] }));
4866
5929
  };
4867
5930
 
4868
- const StringViewer = ({ column, schema, prefix, }) => {
5931
+ const TextAreaViewer = ({ column, schema, prefix, }) => {
4869
5932
  const { watch, formState: { errors }, } = useFormContext();
4870
5933
  const { translate } = useSchemaContext();
4871
- const { required, gridColumn, gridRow } = schema;
5934
+ const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
4872
5935
  const isRequired = required?.some((columnId) => columnId === column);
4873
5936
  const colLabel = `${prefix}${column}`;
4874
5937
  const value = watch(colLabel);
4875
- return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.fieldLabel`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsx(Text, { children: value }), errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.fieldRequired`)) }))] }) }));
5938
+ return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Text, { whiteSpace: "pre-wrap", children: value }), " ", errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
5939
+ };
5940
+
5941
+ const TimeViewer = ({ column, schema, prefix }) => {
5942
+ const { watch, formState: { errors }, } = useFormContext();
5943
+ const { translate, timezone } = useSchemaContext();
5944
+ const { required, gridColumn = "span 12", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
5945
+ const isRequired = required?.some((columnId) => columnId === column);
5946
+ const colLabel = `${prefix}${column}`;
5947
+ const selectedDate = watch(colLabel);
5948
+ const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
5949
+ .tz(timezone)
5950
+ .isValid()
5951
+ ? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
5952
+ : "";
5953
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5954
+ gridRow, children: [jsx(Text, { children: displayedTime }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
5955
+ };
5956
+
5957
+ const DateTimeViewer = ({ column, schema, prefix }) => {
5958
+ const { watch, formState: { errors }, } = useFormContext();
5959
+ const { translate, timezone } = useSchemaContext();
5960
+ const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
5961
+ const isRequired = required?.some((columnId) => columnId === column);
5962
+ const colLabel = `${prefix}${column}`;
5963
+ const selectedDate = watch(colLabel);
5964
+ const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
5965
+ return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
5966
+ gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
4876
5967
  };
4877
5968
 
4878
5969
  const SchemaViewer = ({ schema, prefix, column, }) => {
4879
5970
  const colSchema = schema;
4880
- const { type, variant, properties: innerProperties, foreign_key, items, } = schema;
5971
+ const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
5972
+ if (variant === "custom-input") {
5973
+ return jsx(CustomViewer, { schema: colSchema, prefix, column });
5974
+ }
4881
5975
  if (type === "string") {
4882
5976
  if ((schema.enum ?? []).length > 0) {
4883
5977
  return jsx(EnumViewer, { schema: colSchema, prefix, column });
@@ -4886,9 +5980,18 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
4886
5980
  idPickerSanityCheck(column, foreign_key);
4887
5981
  return jsx(IdViewer, { schema: colSchema, prefix, column });
4888
5982
  }
4889
- if (variant === "date-picker") {
5983
+ if (format === "time") {
5984
+ return jsx(TimeViewer, { schema: colSchema, prefix, column });
5985
+ }
5986
+ if (format === "date") {
4890
5987
  return jsx(DateViewer, { schema: colSchema, prefix, column });
4891
5988
  }
5989
+ if (format === "date-time") {
5990
+ return jsx(DateTimeViewer, { schema: colSchema, prefix, column });
5991
+ }
5992
+ if (variant === "text-area") {
5993
+ return jsx(TextAreaViewer, { schema: colSchema, prefix, column });
5994
+ }
4892
5995
  return jsx(StringViewer, { schema: colSchema, prefix, column });
4893
5996
  }
4894
5997
  if (type === "number" || type === "integer") {
@@ -4914,6 +6017,15 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
4914
6017
  if (variant === "file-picker") {
4915
6018
  return jsx(FileViewer, { schema: colSchema, prefix, column });
4916
6019
  }
6020
+ if (variant === "enum-picker") {
6021
+ const { items } = schema;
6022
+ const { enum: enumItems } = items;
6023
+ const enumSchema = {
6024
+ type: "string",
6025
+ enum: enumItems,
6026
+ };
6027
+ return (jsx(EnumViewer, { isMultiple: true, schema: enumSchema, prefix, column }));
6028
+ }
4917
6029
  if (items) {
4918
6030
  return jsx(ArrayViewer, { schema: colSchema, prefix, column });
4919
6031
  }
@@ -4937,10 +6049,20 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
4937
6049
  };
4938
6050
 
4939
6051
  const SubmitButton = () => {
4940
- const { translate, setValidatedData, setIsError, setIsConfirming } = useSchemaContext();
6052
+ const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, } = useSchemaContext();
4941
6053
  const methods = useFormContext();
4942
6054
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4943
6055
  const onValid = (data) => {
6056
+ const { isValid, errors } = validateData(data, schema);
6057
+ if (!isValid) {
6058
+ setError({
6059
+ type: "validation",
6060
+ errors,
6061
+ });
6062
+ setIsError(true);
6063
+ return;
6064
+ }
6065
+ // If validation passes, proceed to confirmation
4944
6066
  setValidatedData(data);
4945
6067
  setIsError(false);
4946
6068
  setIsConfirming(true);
@@ -4951,7 +6073,8 @@ const SubmitButton = () => {
4951
6073
  };
4952
6074
 
4953
6075
  const FormBody = () => {
4954
- const { schema, requestUrl, order, ignore, include, onSubmit, rowNumber, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, } = useSchemaContext();
6076
+ const { schema, requestUrl, order, ignore, include, onSubmit, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, displayConfig, } = useSchemaContext();
6077
+ const { showSubmitButton, showResetButton } = displayConfig;
4955
6078
  const methods = useFormContext();
4956
6079
  const { properties } = schema;
4957
6080
  const onBeforeSubmit = () => {
@@ -4967,6 +6090,26 @@ const FormBody = () => {
4967
6090
  const onSubmitSuccess = () => {
4968
6091
  setIsSuccess(true);
4969
6092
  };
6093
+ const validateFormData = (data) => {
6094
+ try {
6095
+ const { isValid, errors } = validateData(data, schema);
6096
+ return {
6097
+ isValid,
6098
+ errors,
6099
+ };
6100
+ }
6101
+ catch (error) {
6102
+ return {
6103
+ isValid: false,
6104
+ errors: [
6105
+ {
6106
+ field: "validation",
6107
+ message: error instanceof Error ? error.message : "Unknown error",
6108
+ },
6109
+ ],
6110
+ };
6111
+ }
6112
+ };
4970
6113
  const defaultOnSubmit = async (promise) => {
4971
6114
  try {
4972
6115
  onBeforeSubmit();
@@ -4991,12 +6134,28 @@ const FormBody = () => {
4991
6134
  };
4992
6135
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
4993
6136
  const onFormSubmit = async (data) => {
6137
+ // Validate data using AJV before submission
6138
+ const validationResult = validateFormData(data);
6139
+ if (!validationResult.isValid) {
6140
+ // Set validation errors
6141
+ const validationErrorMessage = {
6142
+ type: "validation",
6143
+ errors: validationResult.errors,
6144
+ message: translate.t("validation_error"),
6145
+ };
6146
+ onSubmitError(validationErrorMessage);
6147
+ return;
6148
+ }
4994
6149
  if (onSubmit === undefined) {
4995
6150
  await defaultOnSubmit(defaultSubmitPromise(data));
4996
6151
  return;
4997
6152
  }
4998
6153
  await defaultOnSubmit(onSubmit(data));
4999
6154
  };
6155
+ // Custom error renderer for validation errors with i18n support
6156
+ const renderValidationErrors = (validationErrors) => {
6157
+ return (jsx(Flex, { flexFlow: "column", gap: "2", children: validationErrors.map((err, index) => (jsxs(Alert.Root, { status: "error", display: "flex", alignItems: "center", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Description, { children: err.message }) })] }, index))) }));
6158
+ };
5000
6159
  const renderColumns = ({ order, keys, ignore, include, }) => {
5001
6160
  const included = include.length > 0 ? include : keys;
5002
6161
  const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
@@ -5011,7 +6170,7 @@ const FormBody = () => {
5011
6170
  include,
5012
6171
  });
5013
6172
  if (isSuccess) {
5014
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Title, { children: translate.t("submitSuccess") })] }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { onClick: async () => {
6173
+ return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsxs(Alert.Root, { status: "success", children: [jsx(Alert.Indicator, {}), jsx(Alert.Content, { children: jsx(Alert.Title, { children: translate.t("submit_success") }) })] }), jsx(Flex, { justifyContent: "end", children: jsx(Button$1, { onClick: async () => {
5015
6174
  setIsError(false);
5016
6175
  setIsSubmiting(false);
5017
6176
  setIsSuccess(false);
@@ -5019,10 +6178,10 @@ const FormBody = () => {
5019
6178
  setValidatedData(undefined);
5020
6179
  const data = await getUpdatedData();
5021
6180
  methods.reset(data);
5022
- }, formNoValidate: true, children: translate.t("submitAgain") }) })] }));
6181
+ }, formNoValidate: true, children: translate.t("submit_again") }) })] }));
5023
6182
  }
5024
6183
  if (isConfirming) {
5025
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat(${rowNumber ?? "auto-fit"}, auto)`, children: ordered.map((column) => {
6184
+ return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: 4, gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: "repeat(12, max-content)", autoFlow: "row", children: ordered.map((column) => {
5026
6185
  return (jsx(ColumnViewer
5027
6186
  // @ts-expect-error find suitable types
5028
6187
  , {
@@ -5032,17 +6191,19 @@ const FormBody = () => {
5032
6191
  setIsConfirming(false);
5033
6192
  }, variant: "subtle", children: translate.t("cancel") }), jsx(Button$1, { onClick: () => {
5034
6193
  onFormSubmit(validatedData);
5035
- }, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: jsx(Alert.Root, { status: "error", children: jsx(Alert.Title, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsxs(AccordionItemTrigger, { children: [jsx(Alert.Indicator, {}), `${error}`] }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) }) }) }))] }));
6194
+ }, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
6195
+ error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
5036
6196
  }
5037
- return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat(${rowNumber ?? "auto-fit"}, auto)`, children: ordered.map((column) => {
6197
+ return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: ordered.map((column) => {
5038
6198
  return (jsx(ColumnRenderer
5039
6199
  // @ts-expect-error find suitable types
5040
6200
  , {
5041
6201
  // @ts-expect-error find suitable types
5042
6202
  properties: properties, prefix: ``, column }, `form-input-${column}`));
5043
- }) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [jsx(Button$1, { onClick: () => {
6203
+ }) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [showResetButton && (jsx(Button$1, { onClick: () => {
5044
6204
  methods.reset();
5045
- }, variant: "subtle", children: translate.t("reset") }), jsx(SubmitButton, {})] })] }));
6205
+ }, variant: "subtle", children: translate.t("reset") })), showSubmitButton && jsx(SubmitButton, {})] }), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === "validation" &&
6206
+ error?.errors ? (renderValidationErrors(error.errors)) : (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsxs(Alert.Content, { children: [jsx(Alert.Title, { children: "Error" }), jsx(Alert.Description, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsx(AccordionItemTrigger, { children: `${error}` }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) })] })] })) })) }))] }));
5046
6207
  };
5047
6208
 
5048
6209
  const FormTitle = () => {
@@ -5051,7 +6212,8 @@ const FormTitle = () => {
5051
6212
  };
5052
6213
 
5053
6214
  const DefaultForm = ({ formConfig, }) => {
5054
- return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
6215
+ const { showTitle } = formConfig.displayConfig ?? {};
6216
+ return (jsx(FormRoot, { ...formConfig, children: jsxs(Grid, { gap: "2", children: [showTitle && jsx(FormTitle, {}), jsx(FormBody, {})] }) }));
5055
6217
  };
5056
6218
 
5057
6219
  const useForm = ({ preLoadedValues, keyPrefix }) => {
@@ -5084,4 +6246,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
5084
6246
  }
5085
6247
  };
5086
6248
 
5087
- export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FilterOptions, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
6249
+ export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };