@bsol-oss/react-datatable5 12.0.0-beta.90 → 12.0.0-beta.92

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 (31) hide show
  1. package/dist/index.d.ts +38 -7
  2. package/dist/index.js +1242 -521
  3. package/dist/index.mjs +1244 -525
  4. package/dist/types/components/DataTable/display/RecordDisplay.d.ts +2 -2
  5. package/dist/types/components/DataTable/display/TextCell.d.ts +11 -4
  6. package/dist/types/components/DataTable/display/TextWithCopy.d.ts +8 -0
  7. package/dist/types/components/DatePicker/DatePickerInput.d.ts +18 -0
  8. package/dist/types/components/DatePicker/DateTimePicker.d.ts +4 -1
  9. package/dist/types/components/DatePicker/IsoTimePicker.d.ts +2 -1
  10. package/dist/types/components/DatePicker/index.d.ts +2 -1
  11. package/dist/types/components/Form/SchemaFormContext.d.ts +2 -1
  12. package/dist/types/components/Form/components/core/FormRoot.d.ts +3 -4
  13. package/dist/types/components/Form/components/fields/ArrayRenderer.d.ts +1 -1
  14. package/dist/types/components/Form/components/fields/StringInputField.d.ts +0 -1
  15. package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +0 -5
  16. package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +8 -0
  17. package/dist/types/components/Form/components/viewers/ArrayViewer.d.ts +1 -1
  18. package/dist/types/components/Form/components/viewers/BooleanViewer.d.ts +1 -1
  19. package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +1 -1
  20. package/dist/types/components/Form/components/viewers/DateViewer.d.ts +1 -1
  21. package/dist/types/components/Form/components/viewers/IdViewer.d.ts +1 -1
  22. package/dist/types/components/Form/components/viewers/ObjectViewer.d.ts +1 -1
  23. package/dist/types/components/Form/components/viewers/RecordViewer.d.ts +2 -2
  24. package/dist/types/components/Form/components/viewers/StringViewer.d.ts +1 -6
  25. package/dist/types/components/Form/components/viewers/TextAreaViewer.d.ts +1 -6
  26. package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +1 -1
  27. package/dist/types/components/Form/utils/useFormI18n.d.ts +5 -3
  28. package/dist/types/components/TimePicker/TimePicker.d.ts +2 -1
  29. package/dist/types/components/ui/pagination.d.ts +10 -7
  30. package/dist/types/index.d.ts +1 -0
  31. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ var dayjs = require('dayjs');
34
34
  var utc = require('dayjs/plugin/utc');
35
35
  var timezone = require('dayjs/plugin/timezone');
36
36
  var ti = require('react-icons/ti');
37
+ var customParseFormat = require('dayjs/plugin/customParseFormat');
37
38
  var matchSorterUtils = require('@tanstack/match-sorter-utils');
38
39
 
39
40
  function _interopNamespaceDefault(e) {
@@ -561,16 +562,111 @@ const { withContext } = react.createRecipeContext({ key: "button" });
561
562
  const LinkButton = withContext("a");
562
563
 
563
564
  const [RootPropsProvider, useRootProps] = react.createContext({
564
- name: "RootPropsProvider",
565
+ name: 'RootPropsProvider',
565
566
  });
566
567
  const variantMap = {
567
- outline: { default: "ghost", ellipsis: "plain", current: "outline" },
568
- solid: { default: "outline", ellipsis: "outline", current: "solid" },
569
- subtle: { default: "ghost", ellipsis: "plain", current: "subtle" },
568
+ outline: { default: 'ghost', ellipsis: 'plain', current: 'outline' },
569
+ solid: { default: 'outline', ellipsis: 'outline', current: 'solid' },
570
+ subtle: { default: 'ghost', ellipsis: 'plain', current: 'subtle' },
570
571
  };
571
572
  const PaginationRoot = React__namespace.forwardRef(function PaginationRoot(props, ref) {
572
- const { size = "sm", variant = "outline", getHref, ...rest } = props;
573
- return (jsxRuntime.jsx(RootPropsProvider, { value: { size, variantMap: variantMap[variant], getHref }, children: jsxRuntime.jsx(react.Pagination.Root, { ref: ref, type: getHref ? "link" : "button", ...rest }) }));
573
+ const { size = 'sm', variant = 'outline', getHref, siblingCount, minSiblingCount = 1, maxSiblingCount, ...rest } = props;
574
+ const containerRef = React__namespace.useRef(null);
575
+ const [calculatedSiblingCount, setCalculatedSiblingCount] = React__namespace.useState(siblingCount);
576
+ React__namespace.useEffect(() => {
577
+ if (siblingCount !== undefined || !containerRef.current) {
578
+ setCalculatedSiblingCount(siblingCount);
579
+ return;
580
+ }
581
+ const container = containerRef.current;
582
+ let rafId = null;
583
+ const calculateSiblingCount = () => {
584
+ if (!container)
585
+ return;
586
+ const width = container.offsetWidth;
587
+ if (width === 0)
588
+ return;
589
+ // Estimate button width based on size
590
+ // These are approximate widths including padding for different button sizes
591
+ const buttonWidthMap = {
592
+ xs: 28,
593
+ sm: 36,
594
+ md: 40,
595
+ lg: 44,
596
+ };
597
+ let buttonWidth = buttonWidthMap[size] || 36;
598
+ // Try to measure actual button if available (for more accuracy)
599
+ const buttons = container.querySelectorAll('button');
600
+ if (buttons.length > 0) {
601
+ const firstButton = buttons[0];
602
+ if (firstButton.offsetWidth > 0) {
603
+ // Use measured width, but account for text content variation
604
+ const measuredWidth = firstButton.offsetWidth;
605
+ // Page number buttons might be slightly wider due to text, use measured width
606
+ buttonWidth = Math.max(buttonWidth, measuredWidth);
607
+ }
608
+ }
609
+ // Account for prev/next buttons and gaps
610
+ // HStack gap is typically 8px in Chakra UI
611
+ const gap = 8;
612
+ const prevNextWidth = buttonWidth * 2 + gap;
613
+ const availableWidth = Math.max(0, width - prevNextWidth);
614
+ // Each page button takes buttonWidth + gap
615
+ const buttonWithGap = buttonWidth + gap;
616
+ const maxButtons = Math.floor(availableWidth / buttonWithGap);
617
+ // Calculate sibling count
618
+ // Minimum structure: [prev] [1] [current] [last] [next] = 5 buttons
619
+ // With siblings: [prev] [1] [...] [current-N] ... [current] ... [current+N] [...] [last] [next]
620
+ // We need: prev(1) + first(1) + ellipsis(1) + siblings*2 + current(1) + ellipsis(1) + last(1) + next(1)
621
+ // Minimum: 5 buttons (prev, first, current, last, next)
622
+ // With siblings: 5 + siblings*2 + ellipsis*2 (if needed)
623
+ const minRequired = 5;
624
+ const extraButtons = Math.max(0, maxButtons - minRequired);
625
+ // Calculate sibling count
626
+ // If we have enough space for ellipsis (2 buttons), account for that
627
+ let calculated = minSiblingCount;
628
+ if (extraButtons >= 4) {
629
+ // Space for ellipsis (2) + siblings
630
+ calculated = Math.floor((extraButtons - 2) / 2);
631
+ }
632
+ else if (extraButtons >= 2) {
633
+ // Space for some siblings but not ellipsis
634
+ calculated = Math.floor(extraButtons / 2);
635
+ }
636
+ // Apply max limit if provided
637
+ if (maxSiblingCount !== undefined) {
638
+ calculated = Math.min(calculated, maxSiblingCount);
639
+ }
640
+ setCalculatedSiblingCount(Math.max(minSiblingCount, calculated));
641
+ };
642
+ const resizeObserver = new ResizeObserver(() => {
643
+ // Use requestAnimationFrame to debounce and ensure DOM is updated
644
+ if (rafId !== null) {
645
+ cancelAnimationFrame(rafId);
646
+ }
647
+ rafId = requestAnimationFrame(calculateSiblingCount);
648
+ });
649
+ resizeObserver.observe(container);
650
+ // Initial calculation after a short delay to ensure buttons are rendered
651
+ const timeoutId = setTimeout(calculateSiblingCount, 100);
652
+ return () => {
653
+ resizeObserver.disconnect();
654
+ if (rafId !== null) {
655
+ cancelAnimationFrame(rafId);
656
+ }
657
+ clearTimeout(timeoutId);
658
+ };
659
+ }, [size, siblingCount, minSiblingCount, maxSiblingCount]);
660
+ const mergedRef = React__namespace.useCallback((node) => {
661
+ if (typeof ref === 'function') {
662
+ ref(node);
663
+ }
664
+ else if (ref) {
665
+ ref.current = node;
666
+ }
667
+ containerRef.current = node;
668
+ }, [ref]);
669
+ return (jsxRuntime.jsx(RootPropsProvider, { value: { size, variantMap: variantMap[variant], getHref }, children: jsxRuntime.jsx(react.Pagination.Root, { ref: mergedRef, type: getHref ? 'link' : 'button', siblingCount: calculatedSiblingCount, ...rest }) }));
574
670
  });
575
671
  const PaginationEllipsis = React__namespace.forwardRef(function PaginationEllipsis(props, ref) {
576
672
  const { size, variantMap } = useRootProps();
@@ -604,16 +700,16 @@ const PaginationNextTrigger = React__namespace.forwardRef(function PaginationNex
604
700
  });
605
701
  const PaginationItems = (props) => {
606
702
  return (jsxRuntime.jsx(react.Pagination.Context, { children: ({ pages }) => pages.map((page, index) => {
607
- return page.type === "ellipsis" ? (jsxRuntime.jsx(PaginationEllipsis, { index: index, ...props }, index)) : (jsxRuntime.jsx(PaginationItem, { type: "page", value: page.value, ...props }, index));
703
+ return page.type === 'ellipsis' ? (jsxRuntime.jsx(PaginationEllipsis, { index: index, ...props }, index)) : (jsxRuntime.jsx(PaginationItem, { type: "page", value: page.value, ...props }, index));
608
704
  }) }));
609
705
  };
610
706
  React__namespace.forwardRef(function PaginationPageText(props, ref) {
611
- const { format = "compact", ...rest } = props;
707
+ const { format = 'compact', ...rest } = props;
612
708
  const { page, totalPages, pageRange, count } = react.usePaginationContext();
613
709
  const content = React__namespace.useMemo(() => {
614
- if (format === "short")
710
+ if (format === 'short')
615
711
  return `${page} / ${totalPages}`;
616
- if (format === "compact")
712
+ if (format === 'compact')
617
713
  return `${page} / ${totalPages}`;
618
714
  return `${pageRange.start + 1} - ${Math.min(pageRange.end, count)} / ${count}`;
619
715
  }, [format, page, totalPages, pageRange, count]);
@@ -3101,14 +3197,14 @@ const DefaultCardTitle = () => {
3101
3197
  const TableCards = ({ isSelectable = false, showDisplayNameOnly = false, renderTitle = DefaultCardTitle, cardBodyProps = {}, }) => {
3102
3198
  const { table, rowSelection, setRowSelection } = useDataTableContext();
3103
3199
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: table.getRowModel().rows.map((row) => {
3104
- return (jsxRuntime.jsx(react.Card.Root, { flex: '1 0 20rem', children: jsxRuntime.jsxs(react.Card.Body, { display: 'flex', flexFlow: 'column', gap: '0.5rem', ...cardBodyProps, children: [isSelectable && (jsxRuntime.jsx(Checkbox, { isChecked: isRowSelected(row.id, rowSelection),
3200
+ return (jsxRuntime.jsx(react.Card.Root, { flex: '1 0 20rem', children: jsxRuntime.jsxs(react.Card.Body, { display: 'flex', flexFlow: 'column', gap: '0.5rem', ...cardBodyProps, children: [isSelectable && (jsxRuntime.jsx(Checkbox, { checked: isRowSelected(row.id, rowSelection),
3105
3201
  disabled: !canRowSelect(row),
3106
3202
  // indeterminate: row.getIsSomeSelected(),
3107
3203
  onChange: createRowToggleHandler(row, rowSelection, setRowSelection) })), renderTitle(row), jsxRuntime.jsx(react.Grid, { templateColumns: 'auto 1fr', gap: '1rem', children: row.getVisibleCells().map((cell) => {
3108
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(react.Box, { children: [showDisplayNameOnly && (jsxRuntime.jsx(react.Text, { fontWeight: 'bold', children: cell.column.columnDef.meta?.displayName ??
3204
+ return (jsxRuntime.jsxs(react.Box, { display: "contents", children: [jsxRuntime.jsxs(react.Box, { children: [showDisplayNameOnly && (jsxRuntime.jsx(react.Text, { fontWeight: 'bold', children: cell.column.columnDef.meta?.displayName ??
3109
3205
  cell.column.id })), !showDisplayNameOnly && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: reactTable.flexRender(cell.column.columnDef.header,
3110
3206
  // @ts-expect-error Assuming the CellContext interface is the same as HeaderContext
3111
- cell.getContext()) }))] }, `chakra-table-cardcolumnid-${row.id}`), jsxRuntime.jsx(react.Box, { justifySelf: 'end', children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) }, `chakra-table-cardcolumn-${row.id}`)] }));
3207
+ cell.getContext()) }))] }), jsxRuntime.jsx(react.Box, { justifySelf: 'end', children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext()) })] }, `chakra-table-cardcell-${cell.id}`));
3112
3208
  }) })] }) }, `chakra-table-card-${row.id}`));
3113
3209
  }) }));
3114
3210
  };
@@ -3139,9 +3235,13 @@ const TableFooter = ({ showSelector = false, alwaysShowSelector = true, }) => {
3139
3235
  }
3140
3236
  return false;
3141
3237
  };
3142
- return (jsxRuntime.jsx(react.Table.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: 'flex', children: [showSelector && (jsxRuntime.jsxs(react.Table.Header, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: 'grid', children: [isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { margin: '0rem', display: 'grid', justifyItems: 'center', alignItems: 'center', children: jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, isChecked: areAllRowsSelected(table, rowSelection),
3143
- // indeterminate: areSomeRowsSelected(table, rowSelection),
3144
- onChange: createToggleAllRowsHandler(table, rowSelection, setRowSelection) }) })), !isCheckBoxVisible() && (jsxRuntime.jsx(react.Box, { as: "span", margin: '0rem', display: 'grid', justifyItems: 'center', alignItems: 'center', width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` }))] })), footerGroup.headers.map((header) => (jsxRuntime.jsx(react.Table.Cell, { padding: '0', columnSpan: `${header.colSpan}`,
3238
+ return (jsxRuntime.jsx(react.Table.Footer, { children: table.getFooterGroups().map((footerGroup) => (jsxRuntime.jsxs(react.Table.Row, { display: 'flex', children: [showSelector && (jsxRuntime.jsx(react.Table.Cell, { padding: `${table.getDensityValue()}px`, onMouseEnter: () => handleRowHover(true), onMouseLeave: () => handleRowHover(false), display: 'grid', justifyItems: 'center', alignItems: 'center', color: {
3239
+ base: 'colorPalette.900',
3240
+ _dark: 'colorPalette.100',
3241
+ },
3242
+ bg: { base: 'colorPalette.50', _dark: 'colorPalette.950' }, children: isCheckBoxVisible() ? (jsxRuntime.jsx(Checkbox, { width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px`, checked: areAllRowsSelected(table, rowSelection),
3243
+ // indeterminate: areSomeRowsSelected(table, rowSelection),
3244
+ onChange: createToggleAllRowsHandler(table, rowSelection, setRowSelection) })) : (jsxRuntime.jsx(react.Box, { as: "span", width: `${SELECTION_BOX_WIDTH}px`, height: `${SELECTION_BOX_WIDTH}px` })) })), footerGroup.headers.map((header) => (jsxRuntime.jsx(react.Table.Cell, { padding: '0', columnSpan: `${header.colSpan}`,
3145
3245
  // styling resize and pinning start
3146
3246
  maxWidth: `${header.getSize()}px`, width: `${header.getSize()}px`, display: 'grid', children: jsxRuntime.jsx(react.MenuRoot, { children: jsxRuntime.jsx(react.MenuTrigger, { asChild: true, children: jsxRuntime.jsx(react.Box, { padding: `${table.getDensityValue()}px`, display: 'flex', alignItems: 'center', justifyContent: 'start', borderRadius: '0rem', children: jsxRuntime.jsxs(react.Flex, { gap: "0.5rem", alignItems: 'center', children: [header.isPlaceholder
3147
3247
  ? null
@@ -3335,11 +3435,136 @@ const TableLoadingComponent = ({ render, }) => {
3335
3435
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: render(query.isLoading) });
3336
3436
  };
3337
3437
 
3338
- const TextCell = ({ label, containerProps = {}, textProps = {}, children, }) => {
3339
- if (label) {
3340
- return (jsxRuntime.jsx(react.Flex, { alignItems: "center", height: "100%", ...containerProps, children: jsxRuntime.jsx(Tooltip, { content: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", children: label }), children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", wordBreak: "break-all", ...textProps, children: children }) }) }));
3438
+ // Helper function to highlight matching text
3439
+ const highlightText$1 = (text, searchTerm) => {
3440
+ if (!searchTerm || searchTerm.trim() === '') {
3441
+ return String(text);
3442
+ }
3443
+ const textStr = String(text);
3444
+ const searchLower = searchTerm.toLowerCase();
3445
+ const textLower = textStr.toLowerCase();
3446
+ const parts = [];
3447
+ let lastIndex = 0;
3448
+ let index = textLower.indexOf(searchLower, lastIndex);
3449
+ while (index !== -1) {
3450
+ // Add text before match
3451
+ if (index > lastIndex) {
3452
+ parts.push(textStr.substring(lastIndex, index));
3453
+ }
3454
+ // Add highlighted match
3455
+ parts.push(jsxRuntime.jsx(react.Text, { as: "mark", bg: {
3456
+ base: 'yellow.200',
3457
+ _dark: 'yellow.800',
3458
+ }, color: {
3459
+ base: 'gray.900',
3460
+ _dark: 'gray.100',
3461
+ }, px: 0.5, borderRadius: "sm", children: textStr.substring(index, index + searchTerm.length) }, index));
3462
+ lastIndex = index + searchTerm.length;
3463
+ index = textLower.indexOf(searchLower, lastIndex);
3464
+ }
3465
+ // Add remaining text
3466
+ if (lastIndex < textStr.length) {
3467
+ parts.push(textStr.substring(lastIndex));
3468
+ }
3469
+ return parts.length > 0 ? jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts }) : textStr;
3470
+ };
3471
+ const TextWithCopy = ({ text, globalFilter, highlightedText, }) => {
3472
+ const textValue = String(text ?? '');
3473
+ const displayText = highlightedText !== undefined
3474
+ ? highlightedText
3475
+ : highlightText$1(textValue, globalFilter);
3476
+ return (jsxRuntime.jsxs(react.HStack, { gap: 2, alignItems: "center", children: [jsxRuntime.jsx(react.Text, { as: "span", children: displayText }), jsxRuntime.jsx(react.Clipboard.Root, { value: textValue, children: jsxRuntime.jsx(react.Clipboard.Trigger, { asChild: true, children: jsxRuntime.jsx(react.IconButton, { size: "xs", variant: "ghost", "aria-label": "Copy", fontSize: "1em", children: jsxRuntime.jsx(react.Clipboard.Indicator, { copied: jsxRuntime.jsx(lu.LuCheck, {}), children: jsxRuntime.jsx(lu.LuCopy, {}) }) }) }) })] }));
3477
+ };
3478
+
3479
+ // Helper function to highlight matching text
3480
+ const highlightText = (text, searchTerm) => {
3481
+ if (!searchTerm || searchTerm.trim() === '') {
3482
+ return String(text);
3483
+ }
3484
+ const textStr = String(text);
3485
+ const searchLower = searchTerm.toLowerCase();
3486
+ const textLower = textStr.toLowerCase();
3487
+ const parts = [];
3488
+ let lastIndex = 0;
3489
+ let index = textLower.indexOf(searchLower, lastIndex);
3490
+ while (index !== -1) {
3491
+ // Add text before match
3492
+ if (index > lastIndex) {
3493
+ parts.push(textStr.substring(lastIndex, index));
3494
+ }
3495
+ // Add highlighted match
3496
+ parts.push(jsxRuntime.jsx(react.Text, { as: "mark", bg: {
3497
+ base: 'yellow.200',
3498
+ _dark: 'yellow.800',
3499
+ }, color: {
3500
+ base: 'gray.900',
3501
+ _dark: 'gray.100',
3502
+ }, px: 0.5, borderRadius: "sm", children: textStr.substring(index, index + searchTerm.length) }, index));
3503
+ lastIndex = index + searchTerm.length;
3504
+ index = textLower.indexOf(searchLower, lastIndex);
3505
+ }
3506
+ // Add remaining text
3507
+ if (lastIndex < textStr.length) {
3508
+ parts.push(textStr.substring(lastIndex));
3509
+ }
3510
+ return parts.length > 0 ? jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts }) : textStr;
3511
+ };
3512
+ const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, globalFilter, }) => {
3513
+ const highlightedText = React.useMemo(() => highlightText(text ?? '', globalFilter), [text, globalFilter]);
3514
+ if (isBadge) {
3515
+ return (jsxRuntime.jsx(react.Badge, { colorPalette: colorPalette || badgeColor, children: highlightedText }));
3516
+ }
3517
+ // onClick takes precedence over href
3518
+ if (onClick) {
3519
+ return (jsxRuntime.jsx(react.Box, { as: "button", onClick: onClick, cursor: "pointer", textAlign: "left", _hover: {
3520
+ textDecoration: 'underline',
3521
+ color: {
3522
+ base: 'blue.500',
3523
+ _dark: 'blue.400',
3524
+ },
3525
+ }, transition: "all 0.2s", children: highlightedText }));
3341
3526
  }
3342
- return (jsxRuntime.jsx(react.Flex, { alignItems: "center", height: "100%", ...containerProps, children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", wordBreak: "break-all", ...textProps, children: children }) }));
3527
+ if (href) {
3528
+ return (jsxRuntime.jsxs(react.Link, { href: href, target: "_blank", rel: "noopener noreferrer", _hover: {
3529
+ textDecoration: 'underline',
3530
+ }, children: [highlightedText, " ", jsxRuntime.jsx(react.Icon, { as: lu.LuExternalLink })] }));
3531
+ }
3532
+ if (isCopyable) {
3533
+ return (jsxRuntime.jsx(TextWithCopy, { text: text, globalFilter: globalFilter, highlightedText: highlightedText }));
3534
+ }
3535
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: highlightedText });
3536
+ };
3537
+ const TextCell = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette,
3538
+ // Legacy props
3539
+ label, containerProps = {}, textProps = {}, children, }) => {
3540
+ // Get globalFilter from context
3541
+ // If not in DataTable context, will use default empty string from context
3542
+ const { globalFilter } = useDataTableContext();
3543
+ // Legacy API: if children is provided, use old behavior
3544
+ if (children !== undefined) {
3545
+ const displayText = typeof children === 'string' || typeof children === 'number'
3546
+ ? String(children)
3547
+ : children;
3548
+ const highlightedDisplayText = typeof displayText === 'string' || typeof displayText === 'number'
3549
+ ? highlightText(displayText, globalFilter)
3550
+ : displayText;
3551
+ if (label) {
3552
+ return (jsxRuntime.jsx(react.Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsxRuntime.jsx(Tooltip, { content: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', children: label }), children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }) }));
3553
+ }
3554
+ return (jsxRuntime.jsx(react.Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsxRuntime.jsx(react.Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }));
3555
+ }
3556
+ // New API: use text prop
3557
+ const displayValue = text ?? children;
3558
+ if (Array.isArray(displayValue)) {
3559
+ return (jsxRuntime.jsx(react.Flex, { gap: 2, flexWrap: "wrap", children: displayValue.map((item, index) => {
3560
+ const highlightedItem = highlightText(item, globalFilter);
3561
+ return (jsxRuntime.jsx(react.Badge, { colorPalette: colorPalette || badgeColor, children: highlightedItem }, index));
3562
+ }) }));
3563
+ }
3564
+ if (!!displayValue === false) {
3565
+ return (jsxRuntime.jsx(react.Text, { textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", wordBreak: "break-all", display: "flex", alignItems: "center", height: "100%", children: "-" }));
3566
+ }
3567
+ return (jsxRuntime.jsx(react.Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", height: "100%", children: jsxRuntime.jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter }) }));
3343
3568
  };
3344
3569
 
3345
3570
  const Tag = React__namespace.forwardRef(function Tag(props, ref) {
@@ -3502,7 +3727,7 @@ const snakeToLabel = (str) => {
3502
3727
  .join(" "); // Join with space
3503
3728
  };
3504
3729
 
3505
- const RecordDisplay = ({ object, boxProps, translate, prefix = "", }) => {
3730
+ const RecordDisplay = ({ object, boxProps, translate, prefix = '', }) => {
3506
3731
  const getColumn = ({ field }) => {
3507
3732
  if (translate !== undefined) {
3508
3733
  return translate.t(`${prefix}${field}`);
@@ -3512,8 +3737,9 @@ const RecordDisplay = ({ object, boxProps, translate, prefix = "", }) => {
3512
3737
  if (object === null) {
3513
3738
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "null" });
3514
3739
  }
3515
- return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: "auto", ...boxProps, children: Object.entries(object).map(([field, value]) => {
3516
- return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: "auto 1fr", children: [jsxRuntime.jsx(react.Text, { color: "colorPalette.400", children: getColumn({ field }) }), typeof value === "object" ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, field));
3740
+ return (jsxRuntime.jsx(react.Grid, { rowGap: 1, padding: 1, overflow: 'auto', ...boxProps, children: Object.entries(object).map(([field, value], index) => {
3741
+ const uniqueKey = `${prefix}${field}-${index}`;
3742
+ return (jsxRuntime.jsxs(react.Grid, { columnGap: 2, gridTemplateColumns: 'auto 1fr', children: [jsxRuntime.jsx(react.Text, { color: 'colorPalette.400', children: getColumn({ field }) }), typeof value === 'object' && value !== null ? (jsxRuntime.jsx(RecordDisplay, { object: value, prefix: `${prefix}${field}.`, translate: translate })) : (jsxRuntime.jsx(react.Text, { children: JSON.stringify(value) }))] }, uniqueKey));
3517
3743
  }) }));
3518
3744
  };
3519
3745
 
@@ -3804,13 +4030,10 @@ const idPickerSanityCheck = (column, foreign_key) => {
3804
4030
  if (!!foreign_key == false) {
3805
4031
  throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
3806
4032
  }
3807
- const { table, column: foreignKeyColumn, display_column } = foreign_key;
4033
+ const { table, column: foreignKeyColumn } = foreign_key;
3808
4034
  if (!!table == false) {
3809
4035
  throw new Error(`The key table does not exist in properties of column ${table} when using id-picker.`);
3810
4036
  }
3811
- if (!!display_column == false) {
3812
- throw new Error(`The key display_column does not exist in properties of column ${column} when using id-picker.`);
3813
- }
3814
4037
  if (!!foreignKeyColumn == false) {
3815
4038
  throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
3816
4039
  }
@@ -3819,7 +4042,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3819
4042
  showSubmitButton: true,
3820
4043
  showResetButton: true,
3821
4044
  showTitle: true,
3822
- }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, insideDialog = false, }) => {
4045
+ }, requireConfirmation = false, dateTimePickerLabels, idPickerLabels, enumPickerLabels, filePickerLabels, formButtonLabels, insideDialog = false, }) => {
3823
4046
  const [isSuccess, setIsSuccess] = React.useState(false);
3824
4047
  const [isError, setIsError] = React.useState(false);
3825
4048
  const [isSubmiting, setIsSubmiting] = React.useState(false);
@@ -3909,6 +4132,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
3909
4132
  idPickerLabels,
3910
4133
  enumPickerLabels,
3911
4134
  filePickerLabels,
4135
+ formButtonLabels,
3912
4136
  ajvResolver: ajvResolver(schema),
3913
4137
  insideDialog,
3914
4138
  }, children: jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: children }) }));
@@ -3918,40 +4142,107 @@ function removeIndex(str) {
3918
4142
  return str.replace(/\.\d+\./g, ".");
3919
4143
  }
3920
4144
 
4145
+ /**
4146
+ * Custom hook to simplify i18n translation for form fields.
4147
+ * Automatically handles colLabel construction and removeIndex logic.
4148
+ *
4149
+ * @param column - The column name
4150
+ * @param prefix - The prefix for the field (usually empty string or parent path)
4151
+ * @returns Object with translation helper functions
4152
+ *
4153
+ * @example
4154
+ * ```tsx
4155
+ * const formI18n = useFormI18n(column, prefix);
4156
+ *
4157
+ * // Get field label
4158
+ * <Field label={formI18n.label()} />
4159
+ *
4160
+ * // Get error message
4161
+ * <Text>{formI18n.required()}</Text>
4162
+ *
4163
+ * // Get custom translation key
4164
+ * <Text>{formI18n.t('add_more')}</Text>
4165
+ *
4166
+ * // Access the raw colLabel
4167
+ * const colLabel = formI18n.colLabel;
4168
+ * ```
4169
+ */
4170
+ const useFormI18n$1 = (column, prefix = '', schema) => {
4171
+ const { translate } = useSchemaContext();
4172
+ const colLabel = `${prefix}${column}`;
4173
+ return {
4174
+ /**
4175
+ * The constructed column label (prefix + column)
4176
+ */
4177
+ colLabel,
4178
+ /**
4179
+ * Get the field label from schema title prop, or fall back to translation
4180
+ * Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
4181
+ */
4182
+ label: (options) => {
4183
+ if (schema?.title) {
4184
+ return schema.title;
4185
+ }
4186
+ return translate.t(removeIndex(`${colLabel}.field_label`), options);
4187
+ },
4188
+ /**
4189
+ * Get the required error message translation
4190
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
4191
+ */
4192
+ required: (options) => {
4193
+ return translate.t(removeIndex(`${colLabel}.field_required`), options);
4194
+ },
4195
+ /**
4196
+ * Get a translation for any custom key relative to the field
4197
+ * Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
4198
+ *
4199
+ * @param key - The translation key suffix (e.g., 'add_more', 'total', etc.)
4200
+ * @param options - Optional translation options (e.g., defaultValue, interpolation variables)
4201
+ */
4202
+ t: (key, options) => {
4203
+ return translate.t(removeIndex(`${colLabel}.${key}`), options);
4204
+ },
4205
+ /**
4206
+ * Access to the original translate object for edge cases
4207
+ */
4208
+ translate,
4209
+ };
4210
+ };
4211
+
3921
4212
  const ArrayRenderer = ({ schema, column, prefix, }) => {
3922
- const { gridRow, gridColumn = "1/span 12", required, items } = schema;
4213
+ const { gridRow, gridColumn = '1/span 12', required, items } = schema;
3923
4214
  // @ts-expect-error TODO: find suitable types
3924
4215
  const { type } = items;
3925
- const { translate } = useSchemaContext();
3926
4216
  const colLabel = `${prefix}${column}`;
3927
4217
  const isRequired = required?.some((columnId) => columnId === column);
4218
+ const formI18n = useFormI18n$1(column, prefix, schema);
3928
4219
  const { formState: { errors }, setValue, watch, } = reactHookForm.useFormContext();
3929
4220
  const fields = (watch(colLabel) ?? []);
3930
- return (jsxRuntime.jsxs(react.Flex, { gridRow, gridColumn, flexFlow: "column", gap: 2, children: [jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 2, children: fields.map((field, index) => (jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
3931
- base: "colorPalette.200",
3932
- _dark: "colorPalette.800",
3933
- }, children: [jsxRuntime.jsx(react.Grid, { gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsxRuntime.jsx(SchemaRenderer, { column: `${index}`,
4221
+ return (jsxRuntime.jsxs(react.Flex, { gridRow, gridColumn, flexFlow: 'column', gap: 2, children: [jsxRuntime.jsxs(react.Box, { as: "label", children: [formI18n.label(), isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 2, children: fields.map((field, index) => (jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: '1fr auto', gap: 2, bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
4222
+ base: 'colorPalette.200',
4223
+ _dark: 'colorPalette.800',
4224
+ }, children: [jsxRuntime.jsx(react.Grid, { gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: jsxRuntime.jsx(SchemaRenderer, { column: `${index}`,
3934
4225
  prefix: `${colLabel}.`,
3935
4226
  // @ts-expect-error find suitable types
3936
- schema: { showLabel: false, ...(items ?? {}) } }) }), jsxRuntime.jsx(react.Flex, { justifyContent: "end", children: jsxRuntime.jsx(react.Button, { variant: "ghost", onClick: () => {
4227
+ schema: { showLabel: false, ...(items ?? {}) } }) }), jsxRuntime.jsx(react.Flex, { justifyContent: 'end', children: jsxRuntime.jsx(react.Button, { variant: 'ghost', onClick: () => {
3937
4228
  setValue(colLabel, fields.filter((_, curIndex) => {
3938
4229
  return curIndex !== index;
3939
4230
  }));
3940
4231
  }, children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(cg.CgTrash, {}) }) }) })] }, `${colLabel}.${index}`))) }), jsxRuntime.jsx(react.Flex, { children: jsxRuntime.jsx(react.Button, { onClick: () => {
3941
- if (type === "number") {
4232
+ if (type === 'number') {
3942
4233
  setValue(colLabel, [...fields, 0]);
3943
4234
  return;
3944
4235
  }
3945
- if (type === "string") {
3946
- setValue(colLabel, [...fields, ""]);
4236
+ if (type === 'string') {
4237
+ setValue(colLabel, [...fields, '']);
3947
4238
  return;
3948
4239
  }
3949
- if (type === "boolean") {
4240
+ if (type === 'boolean') {
3950
4241
  setValue(colLabel, [...fields, false]);
3951
4242
  return;
3952
4243
  }
3953
4244
  setValue(colLabel, [...fields, {}]);
3954
- }, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4245
+ }, children: translate.t(removeIndex(`${colLabel}.add`)) }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
3955
4246
  };
3956
4247
 
3957
4248
  const Field = React__namespace.forwardRef(function Field(props, ref) {
@@ -3961,15 +4252,13 @@ const Field = React__namespace.forwardRef(function Field(props, ref) {
3961
4252
 
3962
4253
  const BooleanPicker = ({ schema, column, prefix }) => {
3963
4254
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
3964
- const { translate } = useSchemaContext();
3965
4255
  const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
3966
4256
  const isRequired = required?.some((columnId) => columnId === column);
3967
4257
  const colLabel = `${prefix}${column}`;
3968
4258
  const value = watch(colLabel);
3969
- return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
3970
- gridRow, errorText: errors[`${colLabel}`]
3971
- ? translate.t(removeIndex(`${colLabel}.field_required`))
3972
- : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
4259
+ const formI18n = useFormI18n$1(column, prefix, schema);
4260
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4261
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsx(CheckboxCard, { checked: value, variant: 'surface', onChange: () => {
3973
4262
  setValue(colLabel, !value);
3974
4263
  } }) }));
3975
4264
  };
@@ -4085,76 +4374,12 @@ let DatePicker$1 = class DatePicker extends React.Component {
4085
4374
  }
4086
4375
  };
4087
4376
 
4088
- /**
4089
- * Custom hook to simplify i18n translation for form fields.
4090
- * Automatically handles colLabel construction and removeIndex logic.
4091
- *
4092
- * @param column - The column name
4093
- * @param prefix - The prefix for the field (usually empty string or parent path)
4094
- * @returns Object with translation helper functions
4095
- *
4096
- * @example
4097
- * ```tsx
4098
- * const formI18n = useFormI18n(column, prefix);
4099
- *
4100
- * // Get field label
4101
- * <Field label={formI18n.label()} />
4102
- *
4103
- * // Get error message
4104
- * <Text>{formI18n.required()}</Text>
4105
- *
4106
- * // Get custom translation key
4107
- * <Text>{formI18n.t('add_more')}</Text>
4108
- *
4109
- * // Access the raw colLabel
4110
- * const colLabel = formI18n.colLabel;
4111
- * ```
4112
- */
4113
- const useFormI18n = (column, prefix = "") => {
4114
- const { translate } = useSchemaContext();
4115
- const colLabel = `${prefix}${column}`;
4116
- return {
4117
- /**
4118
- * The constructed column label (prefix + column)
4119
- */
4120
- colLabel,
4121
- /**
4122
- * Get the field label translation
4123
- * Equivalent to: translate.t(removeIndex(`${colLabel}.field_label`))
4124
- */
4125
- label: (options) => {
4126
- return translate.t(removeIndex(`${colLabel}.field_label`), options);
4127
- },
4128
- /**
4129
- * Get the required error message translation
4130
- * Equivalent to: translate.t(removeIndex(`${colLabel}.field_required`))
4131
- */
4132
- required: (options) => {
4133
- return translate.t(removeIndex(`${colLabel}.field_required`), options);
4134
- },
4135
- /**
4136
- * Get a translation for any custom key relative to the field
4137
- * Equivalent to: translate.t(removeIndex(`${colLabel}.${key}`))
4138
- *
4139
- * @param key - The translation key suffix (e.g., 'add_more', 'total', etc.)
4140
- * @param options - Optional translation options (e.g., defaultValue, interpolation variables)
4141
- */
4142
- t: (key, options) => {
4143
- return translate.t(removeIndex(`${colLabel}.${key}`), options);
4144
- },
4145
- /**
4146
- * Access to the original translate object for edge cases
4147
- */
4148
- translate,
4149
- };
4150
- };
4151
-
4152
4377
  dayjs.extend(utc);
4153
4378
  dayjs.extend(timezone);
4154
4379
  const DatePicker = ({ column, schema, prefix }) => {
4155
4380
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4156
4381
  const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
4157
- const formI18n = useFormI18n(column, prefix);
4382
+ const formI18n = useFormI18n$1(column, prefix, schema);
4158
4383
  const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4159
4384
  const isRequired = required?.some((columnId) => columnId === column);
4160
4385
  const colLabel = formI18n.colLabel;
@@ -4272,7 +4497,7 @@ dayjs.extend(timezone);
4272
4497
  const DateRangePicker = ({ column, schema, prefix, }) => {
4273
4498
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4274
4499
  const { timezone, insideDialog } = useSchemaContext();
4275
- const formI18n = useFormI18n(column, prefix);
4500
+ const formI18n = useFormI18n$1(column, prefix);
4276
4501
  const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4277
4502
  const isRequired = required?.some((columnId) => columnId === column);
4278
4503
  const colLabel = formI18n.colLabel;
@@ -4370,7 +4595,7 @@ const DateRangePicker = ({ column, schema, prefix, }) => {
4370
4595
  const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLimit = false, }) => {
4371
4596
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4372
4597
  const { enumPickerLabels, insideDialog } = useSchemaContext();
4373
- const formI18n = useFormI18n(column, prefix);
4598
+ const formI18n = useFormI18n$1(column, prefix, schema);
4374
4599
  const { required, variant } = schema;
4375
4600
  const isRequired = required?.some((columnId) => columnId === column);
4376
4601
  const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
@@ -5014,7 +5239,7 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
5014
5239
  const FilePicker = ({ column, schema, prefix }) => {
5015
5240
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
5016
5241
  const { filePickerLabels } = useSchemaContext();
5017
- const formI18n = useFormI18n(column, prefix);
5242
+ const formI18n = useFormI18n$1(column, prefix);
5018
5243
  const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
5019
5244
  const isRequired = required?.some((columnId) => columnId === column);
5020
5245
  const isSingleSelect = type === 'string';
@@ -5090,7 +5315,7 @@ const FilePicker = ({ column, schema, prefix }) => {
5090
5315
  const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5091
5316
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
5092
5317
  const { filePickerLabels } = useSchemaContext();
5093
- const formI18n = useFormI18n(column, prefix);
5318
+ const formI18n = useFormI18n$1(column, prefix);
5094
5319
  const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
5095
5320
  const isRequired = required?.some((columnId) => columnId === column);
5096
5321
  const isSingleSelect = type === 'string';
@@ -5231,13 +5456,18 @@ const getTableData = async ({ serverUrl, in_table, searching = "", where = [], l
5231
5456
  }
5232
5457
  };
5233
5458
 
5459
+ // Default renderDisplay function that stringifies JSON
5460
+ const defaultRenderDisplay = (item) => {
5461
+ return JSON.stringify(item);
5462
+ };
5463
+
5234
5464
  const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
5235
5465
  const { watch, getValues, formState: { errors }, setValue, } = reactHookForm.useFormContext();
5236
5466
  const { serverUrl, idMap, setIdMap, idPickerLabels, insideDialog } = useSchemaContext();
5237
- const formI18n = useFormI18n(column, prefix);
5467
+ const formI18n = useFormI18n$1(column, prefix, schema);
5238
5468
  const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
5239
5469
  const isRequired = required?.some((columnId) => columnId === column);
5240
- const { table, column: column_ref, display_column, customQueryFn, } = foreign_key;
5470
+ const { table, column: column_ref, customQueryFn, } = foreign_key;
5241
5471
  const [searchText, setSearchText] = React.useState('');
5242
5472
  const [debouncedSearchText, setDebouncedSearchText] = React.useState('');
5243
5473
  const [limit] = React.useState(50); // Increased limit for combobox
@@ -5315,15 +5545,19 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
5315
5545
  // Check if we're currently searching (user typed but debounce hasn't fired yet)
5316
5546
  const isSearching = searchText !== debouncedSearchText;
5317
5547
  // Transform data for combobox collection
5548
+ // label is used for filtering/searching (must be a string)
5549
+ // raw item is stored for custom rendering
5318
5550
  const comboboxItems = React.useMemo(() => {
5319
- return dataList.map((item) => ({
5320
- label: !!renderDisplay === true
5321
- ? String(renderDisplay(item))
5322
- : String(item[display_column] ?? ''),
5323
- value: String(item[column_ref]),
5324
- raw: item,
5325
- }));
5326
- }, [dataList, display_column, column_ref, renderDisplay]);
5551
+ const renderFn = renderDisplay || defaultRenderDisplay;
5552
+ return dataList.map((item) => {
5553
+ const rendered = renderFn(item);
5554
+ return {
5555
+ label: typeof rendered === 'string' ? rendered : JSON.stringify(item), // Use string for filtering
5556
+ value: String(item[column_ref]),
5557
+ raw: item,
5558
+ };
5559
+ });
5560
+ }, [dataList, column_ref, renderDisplay]);
5327
5561
  // Use filter hook for combobox
5328
5562
  const { contains } = react.useFilter({ sensitivity: 'base' });
5329
5563
  // Create collection for combobox
@@ -5369,9 +5603,9 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
5369
5603
  return (jsxRuntime.jsx(Tag, { closable: true, onClick: () => {
5370
5604
  const newValue = currentValue.filter((itemId) => itemId !== id);
5371
5605
  setValue(colLabel, newValue);
5372
- }, children: !!renderDisplay === true
5606
+ }, children: renderDisplay
5373
5607
  ? renderDisplay(item)
5374
- : item[display_column] }, id));
5608
+ : defaultRenderDisplay(item) }, id));
5375
5609
  }) })), jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue, onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, multiple: isMultiple, closeOnSelect: !isMultiple, openOnClick: true, invalid: !!errors[colLabel], width: "100%", positioning: insideDialog
5376
5610
  ? { strategy: 'fixed', hideWhenDetached: true }
5377
5611
  : undefined, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.Combobox.Input, { placeholder: idPickerLabels?.typeToSearch ?? formI18n.t('type_to_search') }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, { size: "xs" }), isError && (jsxRuntime.jsx(react.Icon, { color: "fg.error", children: jsxRuntime.jsx(bi.BiError, {}) })), !isMultiple && currentValue.length > 0 && (jsxRuntime.jsx(react.Combobox.ClearTrigger, { onClick: () => {
@@ -5382,13 +5616,17 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
5382
5616
  ? idPickerLabels?.emptySearchResult ??
5383
5617
  formI18n.t('empty_search_result')
5384
5618
  : idPickerLabels?.initialResults ??
5385
- formI18n.t('initial_results') })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: formI18n.t('loading_failed') })) : isFetching || isLoading || isPending || isSearching ? (
5619
+ formI18n.t('initial_results') })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplay === true
5620
+ ? renderDisplay(item.raw)
5621
+ : item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsx(react.Combobox.Content, { children: isError ? (jsxRuntime.jsx(react.Text, { p: 2, color: "fg.error", fontSize: "sm", children: formI18n.t('loading_failed') })) : isFetching || isLoading || isPending || isSearching ? (
5386
5622
  // Show skeleton items to prevent UI shift
5387
5623
  jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsxRuntime.jsx(react.Flex, { p: 2, align: "center", gap: 2, children: jsxRuntime.jsx(react.Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsxRuntime.jsx(react.Combobox.Empty, { children: searchText
5388
5624
  ? idPickerLabels?.emptySearchResult ??
5389
5625
  formI18n.t('empty_search_result')
5390
5626
  : idPickerLabels?.initialResults ??
5391
- formI18n.t('initial_results') })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
5627
+ formI18n.t('initial_results') })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: collection.items.map((item, index) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsx(react.Combobox.ItemText, { children: !!renderDisplay === true
5628
+ ? renderDisplay(item.raw)
5629
+ : item.label }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
5392
5630
  };
5393
5631
 
5394
5632
  const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
@@ -5456,15 +5694,15 @@ const extractErrorMessage = (error) => {
5456
5694
 
5457
5695
  const NumberInputField = ({ schema, column, prefix, }) => {
5458
5696
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
5459
- const { translate } = useSchemaContext();
5460
5697
  const { required, gridColumn = 'span 12', gridRow = 'span 1', numberStorageType = 'number', } = schema;
5461
5698
  const isRequired = required?.some((columnId) => columnId === column);
5462
5699
  const colLabel = `${prefix}${column}`;
5463
5700
  const value = watch(`${colLabel}`);
5464
5701
  const fieldError = getFieldError(errors, colLabel);
5465
- return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, errorText: fieldError
5702
+ const formI18n = useFormI18n$1(column, prefix, schema);
5703
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, errorText: fieldError
5466
5704
  ? fieldError.includes('required')
5467
- ? translate.t(removeIndex(`${colLabel}.field_required`))
5705
+ ? formI18n.required()
5468
5706
  : fieldError
5469
5707
  : undefined, invalid: !!fieldError, children: jsxRuntime.jsx(NumberInputRoot, { value: value, onValueChange: (details) => {
5470
5708
  // Store as string or number based on configuration, default to number
@@ -5477,14 +5715,14 @@ const NumberInputField = ({ schema, column, prefix, }) => {
5477
5715
 
5478
5716
  const ObjectInput = ({ schema, column, prefix }) => {
5479
5717
  const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
5480
- const { translate } = useSchemaContext();
5481
5718
  const colLabel = `${prefix}${column}`;
5482
5719
  const isRequired = required?.some((columnId) => columnId === column);
5720
+ const formI18n = useFormI18n$1(column, prefix, schema);
5483
5721
  const { formState: { errors }, } = reactHookForm.useFormContext();
5484
5722
  if (properties === undefined) {
5485
5723
  throw new Error(`properties is undefined when using ObjectInput`);
5486
5724
  }
5487
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
5725
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [formI18n.label(), isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: 2, borderRadius: 4, borderWidth: 1, borderColor: {
5488
5726
  base: 'colorPalette.200',
5489
5727
  _dark: 'colorPalette.800',
5490
5728
  }, gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: Object.keys(properties ?? {}).map((key) => {
@@ -5494,10 +5732,10 @@ const ObjectInput = ({ schema, column, prefix }) => {
5494
5732
  prefix: `${prefix}${column}.`,
5495
5733
  properties,
5496
5734
  parentRequired: required }, `form-${colLabel}-${key}`));
5497
- }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
5735
+ }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
5498
5736
  };
5499
5737
 
5500
- const RecordInput$1 = ({ column, schema, prefix }) => {
5738
+ const RecordInput = ({ column, schema, prefix }) => {
5501
5739
  const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
5502
5740
  const { translate } = useSchemaContext();
5503
5741
  const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
@@ -5506,9 +5744,8 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
5506
5744
  const [showNewEntries, setShowNewEntries] = React.useState(false);
5507
5745
  const [newKey, setNewKey] = React.useState();
5508
5746
  const [newValue, setNewValue] = React.useState();
5509
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`]
5510
- ? translate.t(`${column}.field_required`)
5511
- : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
5747
+ const formI18n = useFormI18n$1(column, prefix, schema);
5748
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, errorText: errors[`${column}`] ? formI18n.required() : undefined, invalid: !!errors[column], children: [entries.map(([key, value]) => {
5512
5749
  return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr auto', gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
5513
5750
  const filtered = entries.filter(([target]) => {
5514
5751
  return target !== key;
@@ -5553,12 +5790,12 @@ const RecordInput$1 = ({ column, schema, prefix }) => {
5553
5790
 
5554
5791
  const StringInputField = ({ column, schema, prefix, }) => {
5555
5792
  const { register, formState: { errors }, } = reactHookForm.useFormContext();
5556
- const { translate } = useSchemaContext();
5557
5793
  const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5558
5794
  const isRequired = required?.some((columnId) => columnId === column);
5559
5795
  const colLabel = `${prefix}${column}`;
5560
5796
  const fieldError = getFieldError(errors, colLabel);
5561
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
5797
+ const formI18n = useFormI18n$1(column, prefix, schema);
5798
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, errorText: fieldError, invalid: !!fieldError, children: jsxRuntime.jsx(react.Input, { ...register(`${colLabel}`, { required: isRequired }), autoComplete: "off" }) }) }));
5562
5799
  };
5563
5800
 
5564
5801
  const RadioCardItem = React__namespace.forwardRef(function RadioCardItem(props, ref) {
@@ -5743,17 +5980,17 @@ Textarea.displayName = "Textarea";
5743
5980
 
5744
5981
  const TextAreaInput = ({ column, schema, prefix, }) => {
5745
5982
  const { register, formState: { errors }, } = reactHookForm.useFormContext();
5746
- const { translate } = useSchemaContext();
5747
5983
  const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
5748
5984
  const isRequired = required?.some((columnId) => columnId === column);
5749
5985
  const colLabel = `${prefix}${column}`;
5750
5986
  const form = reactHookForm.useFormContext();
5751
5987
  const { setValue, watch } = form;
5752
5988
  const fieldError = getFieldError(errors, colLabel);
5989
+ const formI18n = useFormI18n$1(column, prefix, schema);
5753
5990
  const watchValue = watch(colLabel);
5754
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
5991
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', display: "grid", errorText: fieldError
5755
5992
  ? fieldError.includes('required')
5756
- ? translate.t(removeIndex(`${colLabel}.field_required`))
5993
+ ? formI18n.required()
5757
5994
  : fieldError
5758
5995
  : undefined, invalid: !!fieldError, children: jsxRuntime.jsx(Textarea, { value: watchValue, onChange: (value) => setValue(colLabel, value) }) }) }));
5759
5996
  };
@@ -5767,7 +6004,7 @@ meridiemLabel: _meridiemLabel = {
5767
6004
  pm: 'pm',
5768
6005
  },
5769
6006
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5770
- onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, }) {
6007
+ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
5771
6008
  // Generate time options (every 15 minutes)
5772
6009
  const timeOptions = React.useMemo(() => {
5773
6010
  const options = [];
@@ -5790,12 +6027,10 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5790
6027
  for (let h = 1; h <= 12; h++) {
5791
6028
  for (let m = 0; m < 60; m += 15) {
5792
6029
  const hour24 = mer === 'am' ? (h === 12 ? 0 : h) : h === 12 ? 12 : h + 12;
5793
- const timeStr = dayjs()
5794
- .tz(timezone)
5795
- .hour(hour24)
5796
- .minute(m)
5797
- .format('HH:mmZ');
5798
- const displayTime = dayjs(`1970-01-01T${timeStr}`, 'HH:mmZ').format('hh:mm a');
6030
+ // Format time directly without using dayjs with dummy dates
6031
+ const formattedHour = h.toString().padStart(2, '0');
6032
+ const formattedMinute = m.toString().padStart(2, '0');
6033
+ const displayTime = `${formattedHour}:${formattedMinute} ${mer}`;
5799
6034
  // Filter out times that would result in negative duration (only when dates are the same)
5800
6035
  if (startDateTime && selectedDate && shouldFilterByDate) {
5801
6036
  const selectedDateObj = dayjs(selectedDate).tz(timezone);
@@ -5808,8 +6043,8 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5808
6043
  continue; // Skip this option as it would result in negative duration
5809
6044
  }
5810
6045
  }
5811
- // Calculate and append duration if startTime is provided
5812
- let label = displayTime;
6046
+ // Calculate duration if startTime is provided
6047
+ let durationText;
5813
6048
  if (startDateTime && selectedDate) {
5814
6049
  const selectedDateObj = dayjs(selectedDate).tz(timezone);
5815
6050
  const optionDateTime = selectedDateObj
@@ -5822,21 +6057,30 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5822
6057
  const diffMs = optionDateTime.diff(startDateTime);
5823
6058
  const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
5824
6059
  const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
5825
- if (diffHours > 0 || diffMinutes > 0) {
5826
- const diffText = diffHours > 0
5827
- ? `${diffHours}h ${diffMinutes}m`
5828
- : `${diffMinutes}m`;
5829
- label = `${displayTime} (+${diffText})`;
6060
+ const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
6061
+ if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
6062
+ let diffText = '';
6063
+ if (diffHours > 0) {
6064
+ diffText = `${diffHours}h ${diffMinutes}m`;
6065
+ }
6066
+ else if (diffMinutes > 0) {
6067
+ diffText = `${diffMinutes}m ${diffSeconds}s`;
6068
+ }
6069
+ else {
6070
+ diffText = `${diffSeconds}s`;
6071
+ }
6072
+ durationText = `+${diffText}`;
5830
6073
  }
5831
6074
  }
5832
6075
  }
5833
6076
  options.push({
5834
- label,
6077
+ label: displayTime,
5835
6078
  value: `${h}:${m.toString().padStart(2, '0')}:${mer}`,
5836
6079
  hour: h,
5837
6080
  minute: m,
5838
6081
  meridiem: mer,
5839
6082
  searchText: displayTime, // Use base time without duration for searching
6083
+ durationText,
5840
6084
  });
5841
6085
  }
5842
6086
  }
@@ -5850,22 +6094,6 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5850
6094
  itemToValue: (item) => item.value,
5851
6095
  filter: contains,
5852
6096
  });
5853
- // Track input mode vs display mode
5854
- const [isInputMode, setIsInputMode] = React.useState(false);
5855
- const [inputValue, setInputValue] = React.useState('');
5856
- const inputRef = React.useRef(null);
5857
- // Switch to display mode when value is selected
5858
- React.useEffect(() => {
5859
- if (hour !== null && minute !== null && meridiem !== null) {
5860
- setIsInputMode(false);
5861
- }
5862
- }, [hour, minute, meridiem]);
5863
- // Focus input when switching to input mode
5864
- React.useEffect(() => {
5865
- if (isInputMode && inputRef.current) {
5866
- inputRef.current.focus();
5867
- }
5868
- }, [isInputMode]);
5869
6097
  // Get current value string for combobox
5870
6098
  const currentValue = React.useMemo(() => {
5871
6099
  if (hour === null || minute === null || meridiem === null) {
@@ -5873,14 +6101,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5873
6101
  }
5874
6102
  return `${hour}:${minute.toString().padStart(2, '0')}:${meridiem}`;
5875
6103
  }, [hour, minute, meridiem]);
5876
- // INPUT MODE: Show raw input text (no duration)
5877
- const inputModeText = React.useMemo(() => {
5878
- return inputValue;
5879
- }, [inputValue]);
5880
- // DISPLAY MODE: Show selected value with duration
5881
- const displayModeText = React.useMemo(() => {
5882
- if (hour === null || minute === null || meridiem === null) {
5883
- return '';
6104
+ // Calculate duration difference
6105
+ const durationDiff = React.useMemo(() => {
6106
+ if (!startTime ||
6107
+ !selectedDate ||
6108
+ hour === null ||
6109
+ minute === null ||
6110
+ meridiem === null) {
6111
+ return null;
5884
6112
  }
5885
6113
  const hour24 = meridiem === 'am'
5886
6114
  ? hour === 12
@@ -5889,45 +6117,42 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5889
6117
  : hour === 12
5890
6118
  ? 12
5891
6119
  : hour + 12;
5892
- const timeStr = dayjs()
5893
- .tz(timezone)
6120
+ const startDateObj = dayjs(startTime).tz(timezone);
6121
+ const selectedDateObj = dayjs(selectedDate).tz(timezone);
6122
+ const currentDateTime = selectedDateObj
5894
6123
  .hour(hour24)
5895
6124
  .minute(minute)
5896
- .format('HH:mmZ');
5897
- const timeDisplay = dayjs(`1970-01-01T${timeStr}`, 'HH:mmZ').format('hh:mm a');
5898
- // Add duration if startTime is provided
5899
- if (startTime && selectedDate) {
5900
- const startDateObj = dayjs(startTime).tz(timezone);
5901
- const selectedDateObj = dayjs(selectedDate).tz(timezone);
5902
- const currentDateTime = selectedDateObj
5903
- .hour(hour24)
5904
- .minute(minute)
5905
- .second(0)
5906
- .millisecond(0);
5907
- if (startDateObj.isValid() && currentDateTime.isValid()) {
5908
- const diffMs = currentDateTime.diff(startDateObj);
5909
- if (diffMs >= 0) {
5910
- const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
5911
- const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
5912
- if (diffHours > 0 || diffMinutes > 0) {
5913
- const diffText = diffHours > 0
5914
- ? `${diffHours}h ${diffMinutes}m`
5915
- : `${diffMinutes}m`;
5916
- return `${timeDisplay} (+${diffText})`;
5917
- }
5918
- }
6125
+ .second(0)
6126
+ .millisecond(0);
6127
+ if (!startDateObj.isValid() || !currentDateTime.isValid()) {
6128
+ return null;
6129
+ }
6130
+ const diffMs = currentDateTime.diff(startDateObj);
6131
+ if (diffMs < 0) {
6132
+ return null;
6133
+ }
6134
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
6135
+ const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
6136
+ const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
6137
+ if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
6138
+ let diffText = '';
6139
+ if (diffHours > 0) {
6140
+ diffText = `${diffHours}h ${diffMinutes}m`;
6141
+ }
6142
+ else if (diffMinutes > 0) {
6143
+ diffText = `${diffMinutes}m ${diffSeconds}s`;
5919
6144
  }
6145
+ else {
6146
+ diffText = `${diffSeconds}s`;
6147
+ }
6148
+ return `+${diffText}`;
5920
6149
  }
5921
- return timeDisplay;
5922
- }, [hour, minute, meridiem, timezone, startTime, selectedDate]);
5923
- // Choose text based on mode
5924
- const displayText = isInputMode ? inputModeText : displayModeText;
6150
+ return null;
6151
+ }, [hour, minute, meridiem, startTime, selectedDate, timezone]);
5925
6152
  const handleClear = () => {
5926
6153
  setHour(null);
5927
6154
  setMinute(null);
5928
6155
  setMeridiem(null);
5929
- setIsInputMode(false);
5930
- setInputValue('');
5931
6156
  filter(''); // Reset filter to show all options
5932
6157
  onChange({ hour: null, minute: null, meridiem: null });
5933
6158
  };
@@ -5942,8 +6167,6 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5942
6167
  setHour(selectedOption.hour);
5943
6168
  setMinute(selectedOption.minute);
5944
6169
  setMeridiem(selectedOption.meridiem);
5945
- setIsInputMode(false); // Switch to display mode
5946
- setInputValue('');
5947
6170
  filter(''); // Reset filter after selection
5948
6171
  onChange({
5949
6172
  hour: selectedOption.hour,
@@ -5952,41 +6175,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5952
6175
  });
5953
6176
  }
5954
6177
  };
5955
- // Handle Enter key to select first filtered option
5956
- const handleKeyDown = (e) => {
5957
- if (e.key === 'Enter' && collection.items.length > 0) {
5958
- e.preventDefault();
5959
- const firstOption = collection.items[0];
5960
- if (firstOption) {
5961
- const selectedOption = timeOptions.find((opt) => opt.value === firstOption.value);
5962
- if (selectedOption) {
5963
- setHour(selectedOption.hour);
5964
- setMinute(selectedOption.minute);
5965
- setMeridiem(selectedOption.meridiem);
5966
- setIsInputMode(false); // Switch to display mode
5967
- setInputValue('');
5968
- filter('');
5969
- onChange({
5970
- hour: selectedOption.hour,
5971
- minute: selectedOption.minute,
5972
- meridiem: selectedOption.meridiem,
5973
- });
5974
- }
5975
- }
5976
- }
5977
- };
5978
- const handleInputValueChange = (details) => {
5979
- const inputValue = details.inputValue.trim();
5980
- setInputValue(inputValue);
5981
- setIsInputMode(true); // Switch to input mode
6178
+ // Parse input value and update state
6179
+ const parseAndCommitInput = (value) => {
6180
+ const trimmedValue = value.trim();
5982
6181
  // Filter the collection based on input
5983
- filter(inputValue);
5984
- if (!inputValue) {
5985
- setIsInputMode(false);
6182
+ filter(trimmedValue);
6183
+ if (!trimmedValue) {
5986
6184
  return;
5987
6185
  }
5988
6186
  // Try to parse custom input using explicit regex patterns
5989
- const normalized = inputValue.toLowerCase().replace(/\s+/g, '');
6187
+ const normalized = trimmedValue.toLowerCase().replace(/\s+/g, '');
5990
6188
  // Pattern 1: 12-hour format with meridiem (e.g., "930pm", "1230am", "9:30pm", "12:30am")
5991
6189
  // Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
5992
6190
  const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
@@ -5997,29 +6195,43 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
5997
6195
  const parsedMeridiem = match12Hour[3];
5998
6196
  // Validate hour (1-12)
5999
6197
  if (parsedHour < 1 || parsedHour > 12) {
6198
+ // Parse failed, select first result
6199
+ selectFirstResult();
6000
6200
  return;
6001
6201
  }
6002
6202
  // Validate minute (0-59)
6003
- const validMinute = parsedMinute > 59 ? 0 : parsedMinute;
6203
+ if (parsedMinute < 0 || parsedMinute > 59) {
6204
+ // Parse failed, select first result
6205
+ selectFirstResult();
6206
+ return;
6207
+ }
6004
6208
  setHour(parsedHour);
6005
- setMinute(validMinute);
6209
+ setMinute(parsedMinute);
6006
6210
  setMeridiem(parsedMeridiem);
6007
6211
  onChange({
6008
6212
  hour: parsedHour,
6009
- minute: validMinute,
6213
+ minute: parsedMinute,
6010
6214
  meridiem: parsedMeridiem,
6011
6215
  });
6012
6216
  return;
6013
6217
  }
6014
6218
  // Pattern 2: 24-hour format (e.g., "2130", "09:30", "21:30")
6015
6219
  // Matches: 1-2 digits hour, optional colon, 2 digits minute
6016
- const pattern24Hour = /^(\d{2}):?(\d{2})$/;
6220
+ const pattern24Hour = /^(\d{1,2}):?(\d{2})$/;
6017
6221
  const match24Hour = normalized.match(pattern24Hour);
6018
6222
  if (match24Hour) {
6019
6223
  let parsedHour = parseInt(match24Hour[1], 10);
6020
6224
  const parsedMinute = parseInt(match24Hour[2], 10);
6021
6225
  // Validate hour (0-23)
6022
- if (parsedHour > 23) {
6226
+ if (parsedHour < 0 || parsedHour > 23) {
6227
+ // Parse failed, select first result
6228
+ selectFirstResult();
6229
+ return;
6230
+ }
6231
+ // Validate minute (0-59)
6232
+ if (parsedMinute < 0 || parsedMinute > 59) {
6233
+ // Parse failed, select first result
6234
+ selectFirstResult();
6023
6235
  return;
6024
6236
  }
6025
6237
  // Convert 24-hour to 12-hour format
@@ -6039,32 +6251,72 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
6039
6251
  else {
6040
6252
  parsedMeridiem = 'am';
6041
6253
  }
6042
- // Validate minute (0-59)
6043
- const validMinute = parsedMinute > 59 ? 0 : parsedMinute;
6044
6254
  setHour(parsedHour);
6045
- setMinute(validMinute);
6255
+ setMinute(parsedMinute);
6046
6256
  setMeridiem(parsedMeridiem);
6047
6257
  onChange({
6048
6258
  hour: parsedHour,
6049
- minute: validMinute,
6259
+ minute: parsedMinute,
6050
6260
  meridiem: parsedMeridiem,
6051
6261
  });
6052
6262
  return;
6053
6263
  }
6264
+ // Parse failed, select first result
6265
+ selectFirstResult();
6266
+ };
6267
+ // Select first result from filtered collection
6268
+ const selectFirstResult = () => {
6269
+ if (collection.items.length > 0) {
6270
+ const firstItem = collection.items[0];
6271
+ setHour(firstItem.hour);
6272
+ setMinute(firstItem.minute);
6273
+ setMeridiem(firstItem.meridiem);
6274
+ filter(''); // Reset filter after selection
6275
+ onChange({
6276
+ hour: firstItem.hour,
6277
+ minute: firstItem.minute,
6278
+ meridiem: firstItem.meridiem,
6279
+ });
6280
+ }
6281
+ };
6282
+ const handleInputValueChange = (details) => {
6283
+ // Filter the collection based on input, but don't parse yet
6284
+ filter(details.inputValue);
6285
+ };
6286
+ const handleFocus = (e) => {
6287
+ // Select all text when focusing
6288
+ e.target.select();
6289
+ };
6290
+ const handleBlur = (e) => {
6291
+ // Parse and commit the input value when losing focus
6292
+ const inputValue = e.target.value;
6293
+ if (inputValue) {
6294
+ parseAndCommitInput(inputValue);
6295
+ }
6296
+ };
6297
+ const handleKeyDown = (e) => {
6298
+ // Commit input on Enter key
6299
+ if (e.key === 'Enter') {
6300
+ e.preventDefault();
6301
+ const inputValue = e.currentTarget.value;
6302
+ if (inputValue) {
6303
+ parseAndCommitInput(inputValue);
6304
+ }
6305
+ // Blur the input
6306
+ e.currentTarget?.blur();
6307
+ }
6054
6308
  };
6055
- return (jsxRuntime.jsxs(react.Grid, { justifyContent: 'center', alignItems: 'center', templateColumns: '200px auto', gap: "2", width: "auto", minWidth: "250px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, width: "100%", children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [isInputMode ? (jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { ref: inputRef, placeholder: "Select time", value: displayText, onKeyDown: handleKeyDown }) })) : (jsxRuntime.jsxs(react.Grid, { templateColumns: "auto 1fr auto", alignItems: "center", gap: 2, width: "100%", minHeight: "40px", px: 3, border: "1px solid", borderColor: "gray.200", borderRadius: "md", cursor: "pointer", onClick: () => setIsInputMode(true), children: [jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(bs.BsClock, {}) }), jsxRuntime.jsx(react.Text, { fontSize: "sm", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", children: displayText || 'Select time' }), jsxRuntime.jsx(react.Combobox.Trigger, { onClick: (e) => {
6056
- e.stopPropagation();
6057
- setIsInputMode(true);
6058
- } })] })), isInputMode && (jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [jsxRuntime.jsx(react.Combobox.ClearTrigger, {}), jsxRuntime.jsx(react.Combobox.Trigger, {})] }))] }), jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [jsxRuntime.jsx(react.Combobox.Empty, { children: "No time found" }), collection.items.map((item) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [item.label, jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdCancel, {}) }) })] }));
6309
+ return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder: "hh:mm a", onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsxRuntime.jsx(react.Combobox.IndicatorGroup, { children: jsxRuntime.jsx(react.Combobox.Trigger, {}) })] }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [jsxRuntime.jsx(react.Combobox.Empty, { children: "No time found" }), collection.items.map((item) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsxRuntime.jsx(react.Text, { flex: 1, children: item.label }), item.durationText && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", colorPalette: "blue", children: jsxRuntime.jsx(react.Tag.Label, { children: item.durationText }) }))] }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: durationDiff }) })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdCancel, {}) }) })] }) }));
6059
6310
  }
6060
6311
 
6061
6312
  dayjs.extend(timezone);
6062
6313
  const TimePicker = ({ column, schema, prefix }) => {
6063
6314
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
6064
- const { translate, timezone, insideDialog } = useSchemaContext();
6315
+ const { timezone, insideDialog } = useSchemaContext();
6065
6316
  const { required, gridColumn = 'span 12', gridRow = 'span 1', timeFormat = 'HH:mm:ssZ', displayTimeFormat = 'hh:mm A', } = schema;
6066
6317
  const isRequired = required?.some((columnId) => columnId === column);
6067
6318
  const colLabel = `${prefix}${column}`;
6319
+ const formI18n = useFormI18n$1(column, prefix, schema);
6068
6320
  const [open, setOpen] = React.useState(false);
6069
6321
  const value = watch(colLabel);
6070
6322
  const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
@@ -6119,10 +6371,8 @@ const TimePicker = ({ column, schema, prefix }) => {
6119
6371
  const timeString = getTimeString(newHour, newMinute, newMeridiem);
6120
6372
  setValue(colLabel, timeString, { shouldValidate: true, shouldDirty: true });
6121
6373
  };
6122
- return (jsxRuntime.jsx(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: 'stretch', gridColumn,
6123
- gridRow, errorText: errors[`${colLabel}`]
6124
- ? translate.t(removeIndex(`${colLabel}.field_required`))
6125
- : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
6374
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6375
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
6126
6376
  setOpen(true);
6127
6377
  }, justifyContent: 'start', children: [jsxRuntime.jsx(io.IoMdClock, {}), !!value ? `${displayedTime}` : ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { maxH: "70vh", overflowY: "auto", children: jsxRuntime.jsx(react.Popover.Body, { overflow: "visible", children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
6128
6378
  am: translate.t(`common.am`, { defaultValue: 'AM' }),
@@ -6135,21 +6385,148 @@ const TimePicker = ({ column, schema, prefix }) => {
6135
6385
 
6136
6386
  dayjs.extend(utc);
6137
6387
  dayjs.extend(timezone);
6138
- function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
6139
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6140
- onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', }) {
6141
- // Generate time options (every 15 minutes, seconds always 0)
6142
- const timeOptions = React.useMemo(() => {
6143
- const options = [];
6144
- // Get start time for comparison if provided
6145
- let startDateTime = null;
6146
- let shouldFilterByDate = false;
6147
- if (startTime && selectedDate) {
6148
- const startDateObj = dayjs(startTime).tz(timezone);
6149
- const selectedDateObj = dayjs(selectedDate).tz(timezone);
6150
- if (startDateObj.isValid() && selectedDateObj.isValid()) {
6151
- startDateTime = startDateObj;
6152
- // Only filter if dates are the same
6388
+ dayjs.extend(customParseFormat);
6389
+ function DatePickerInput({ value, onChange, placeholder = 'Select a date', dateFormat = 'YYYY-MM-DD', displayFormat = 'YYYY-MM-DD', labels = {
6390
+ monthNamesShort: [
6391
+ 'Jan',
6392
+ 'Feb',
6393
+ 'Mar',
6394
+ 'Apr',
6395
+ 'May',
6396
+ 'Jun',
6397
+ 'Jul',
6398
+ 'Aug',
6399
+ 'Sep',
6400
+ 'Oct',
6401
+ 'Nov',
6402
+ 'Dec',
6403
+ ],
6404
+ weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
6405
+ backButtonLabel: 'Back',
6406
+ forwardButtonLabel: 'Next',
6407
+ }, timezone = 'Asia/Hong_Kong', minDate, maxDate, firstDayOfWeek, showOutsideDays, monthsToDisplay = 1, insideDialog = false, readOnly = false, }) {
6408
+ const [open, setOpen] = React.useState(false);
6409
+ const [inputValue, setInputValue] = React.useState('');
6410
+ // Update input value when prop value changes
6411
+ React.useEffect(() => {
6412
+ if (value) {
6413
+ const formatted = typeof value === 'string'
6414
+ ? dayjs(value).tz(timezone).isValid()
6415
+ ? dayjs(value).tz(timezone).format(displayFormat)
6416
+ : ''
6417
+ : dayjs(value).tz(timezone).format(displayFormat);
6418
+ setInputValue(formatted);
6419
+ }
6420
+ else {
6421
+ setInputValue('');
6422
+ }
6423
+ }, [value, displayFormat, timezone]);
6424
+ // Convert value to Date object for DatePicker
6425
+ const selectedDate = value
6426
+ ? typeof value === 'string'
6427
+ ? dayjs(value).tz(timezone).isValid()
6428
+ ? dayjs(value).tz(timezone).toDate()
6429
+ : new Date()
6430
+ : value
6431
+ : new Date();
6432
+ // Shared function to parse and validate input value
6433
+ const parseAndValidateInput = (inputVal) => {
6434
+ // If empty, clear the value
6435
+ if (!inputVal.trim()) {
6436
+ onChange?.(undefined);
6437
+ setInputValue('');
6438
+ return;
6439
+ }
6440
+ // Try parsing with displayFormat first
6441
+ let parsedDate = dayjs(inputVal, displayFormat, true);
6442
+ // If that fails, try common date formats
6443
+ if (!parsedDate.isValid()) {
6444
+ parsedDate = dayjs(inputVal);
6445
+ }
6446
+ // If still invalid, try parsing with dateFormat
6447
+ if (!parsedDate.isValid()) {
6448
+ parsedDate = dayjs(inputVal, dateFormat, true);
6449
+ }
6450
+ // If valid, check constraints and update
6451
+ if (parsedDate.isValid()) {
6452
+ const dateObj = parsedDate.tz(timezone).toDate();
6453
+ // Check min/max constraints
6454
+ if (minDate && dateObj < minDate) {
6455
+ // Invalid: before minDate, reset to prop value
6456
+ resetToPropValue();
6457
+ return;
6458
+ }
6459
+ if (maxDate && dateObj > maxDate) {
6460
+ // Invalid: after maxDate, reset to prop value
6461
+ resetToPropValue();
6462
+ return;
6463
+ }
6464
+ // Valid date - format and update
6465
+ const formattedDate = parsedDate.tz(timezone).format(dateFormat);
6466
+ const formattedDisplay = parsedDate.tz(timezone).format(displayFormat);
6467
+ onChange?.(formattedDate);
6468
+ setInputValue(formattedDisplay);
6469
+ }
6470
+ else {
6471
+ // Invalid date - reset to prop value
6472
+ resetToPropValue();
6473
+ }
6474
+ };
6475
+ // Helper function to reset input to prop value
6476
+ const resetToPropValue = () => {
6477
+ if (value) {
6478
+ const formatted = typeof value === 'string'
6479
+ ? dayjs(value).tz(timezone).isValid()
6480
+ ? dayjs(value).tz(timezone).format(displayFormat)
6481
+ : ''
6482
+ : dayjs(value).tz(timezone).format(displayFormat);
6483
+ setInputValue(formatted);
6484
+ }
6485
+ else {
6486
+ setInputValue('');
6487
+ }
6488
+ };
6489
+ const handleInputChange = (e) => {
6490
+ // Only update the input value, don't parse yet
6491
+ setInputValue(e.target.value);
6492
+ };
6493
+ const handleInputBlur = () => {
6494
+ // Parse and validate when input loses focus
6495
+ parseAndValidateInput(inputValue);
6496
+ };
6497
+ const handleKeyDown = (e) => {
6498
+ // Parse and validate when Enter is pressed
6499
+ if (e.key === 'Enter') {
6500
+ e.preventDefault();
6501
+ parseAndValidateInput(inputValue);
6502
+ }
6503
+ };
6504
+ const handleDateSelected = ({ date }) => {
6505
+ const formattedDate = dayjs(date).tz(timezone).format(dateFormat);
6506
+ onChange?.(formattedDate);
6507
+ setOpen(false);
6508
+ };
6509
+ const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: selectedDate, onDateSelected: handleDateSelected, labels: labels, minDate: minDate, maxDate: maxDate, firstDayOfWeek: firstDayOfWeek, showOutsideDays: showOutsideDays, monthsToDisplay: monthsToDisplay }));
6510
+ return (jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsxRuntime.jsx(InputGroup, { endElement: jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsx(react.IconButton, { variant: "ghost", size: "2xs", "aria-label": "Open calendar", onClick: () => setOpen(true), children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdDateRange, {}) }) }) }), children: jsxRuntime.jsx(react.Input, { value: inputValue, onChange: handleInputChange, onBlur: handleInputBlur, onKeyDown: handleKeyDown, placeholder: placeholder, readOnly: readOnly }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minH: "25rem", children: jsxRuntime.jsx(react.Popover.Body, { children: datePickerContent }) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minH: "25rem", children: jsxRuntime.jsx(react.Popover.Body, { children: datePickerContent }) }) }) }))] }));
6511
+ }
6512
+
6513
+ dayjs.extend(utc);
6514
+ dayjs.extend(timezone);
6515
+ function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
6516
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
6517
+ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, }) {
6518
+ // Generate time options (every 15 minutes, seconds always 0)
6519
+ const timeOptions = React.useMemo(() => {
6520
+ const options = [];
6521
+ // Get start time for comparison if provided
6522
+ let startDateTime = null;
6523
+ let shouldFilterByDate = false;
6524
+ if (startTime && selectedDate) {
6525
+ const startDateObj = dayjs(startTime).tz(timezone);
6526
+ const selectedDateObj = dayjs(selectedDate).tz(timezone);
6527
+ if (startDateObj.isValid() && selectedDateObj.isValid()) {
6528
+ startDateTime = startDateObj;
6529
+ // Only filter if dates are the same
6153
6530
  shouldFilterByDate =
6154
6531
  startDateObj.format('YYYY-MM-DD') ===
6155
6532
  selectedDateObj.format('YYYY-MM-DD');
@@ -6172,8 +6549,8 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
6172
6549
  continue; // Skip this option as it would result in negative duration
6173
6550
  }
6174
6551
  }
6175
- // Calculate and append duration if startTime is provided
6176
- let label = timeDisplay;
6552
+ // Calculate duration if startTime is provided
6553
+ let durationText;
6177
6554
  if (startDateTime && selectedDate) {
6178
6555
  const selectedDateObj = dayjs(selectedDate).tz(timezone);
6179
6556
  const optionDateTime = selectedDateObj
@@ -6198,17 +6575,18 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
6198
6575
  else {
6199
6576
  diffText = `${diffSeconds}s`;
6200
6577
  }
6201
- label = `${timeDisplay} (+${diffText})`;
6578
+ durationText = `+${diffText}`;
6202
6579
  }
6203
6580
  }
6204
6581
  }
6205
6582
  options.push({
6206
- label,
6583
+ label: timeDisplay,
6207
6584
  value: `${h}:${m}:0`,
6208
6585
  hour: h,
6209
6586
  minute: m,
6210
6587
  second: 0,
6211
6588
  searchText: timeDisplay, // Use base time without duration for searching
6589
+ durationText,
6212
6590
  });
6213
6591
  }
6214
6592
  }
@@ -6228,46 +6606,46 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
6228
6606
  }
6229
6607
  return `${hour}:${minute}:${second}`;
6230
6608
  }, [hour, minute, second]);
6231
- // Get display text for combobox
6232
- const displayText = React.useMemo(() => {
6233
- if (hour === null || minute === null || second === null) {
6234
- return '';
6609
+ // Calculate duration difference
6610
+ const durationDiff = React.useMemo(() => {
6611
+ if (!startTime ||
6612
+ !selectedDate ||
6613
+ hour === null ||
6614
+ minute === null ||
6615
+ second === null) {
6616
+ return null;
6235
6617
  }
6236
- const timeDisplay = `${hour.toString().padStart(2, '0')}:${minute
6237
- .toString()
6238
- .padStart(2, '0')}:${second.toString().padStart(2, '0')}`;
6239
- // Show duration difference if startTime is provided
6240
- if (startTime && selectedDate) {
6241
- const startDateObj = dayjs(startTime).tz(timezone);
6242
- const selectedDateObj = dayjs(selectedDate).tz(timezone);
6243
- const currentDateTime = selectedDateObj
6244
- .hour(hour)
6245
- .minute(minute)
6246
- .second(second ?? 0)
6247
- .millisecond(0);
6248
- if (startDateObj.isValid() && currentDateTime.isValid()) {
6249
- const diffMs = currentDateTime.diff(startDateObj);
6250
- if (diffMs >= 0) {
6251
- const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
6252
- const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
6253
- const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
6254
- if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
6255
- let diffText = '';
6256
- if (diffHours > 0) {
6257
- diffText = `${diffHours}h ${diffMinutes}m`;
6258
- }
6259
- else if (diffMinutes > 0) {
6260
- diffText = `${diffMinutes}m ${diffSeconds}s`;
6261
- }
6262
- else {
6263
- diffText = `${diffSeconds}s`;
6264
- }
6265
- return `${timeDisplay} (+${diffText})`;
6266
- }
6267
- }
6618
+ const startDateObj = dayjs(startTime).tz(timezone);
6619
+ const selectedDateObj = dayjs(selectedDate).tz(timezone);
6620
+ const currentDateTime = selectedDateObj
6621
+ .hour(hour)
6622
+ .minute(minute)
6623
+ .second(second ?? 0)
6624
+ .millisecond(0);
6625
+ if (!startDateObj.isValid() || !currentDateTime.isValid()) {
6626
+ return null;
6627
+ }
6628
+ const diffMs = currentDateTime.diff(startDateObj);
6629
+ if (diffMs < 0) {
6630
+ return null;
6631
+ }
6632
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
6633
+ const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
6634
+ const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
6635
+ if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
6636
+ let diffText = '';
6637
+ if (diffHours > 0) {
6638
+ diffText = `${diffHours}h ${diffMinutes}m`;
6639
+ }
6640
+ else if (diffMinutes > 0) {
6641
+ diffText = `${diffMinutes}m ${diffSeconds}s`;
6268
6642
  }
6643
+ else {
6644
+ diffText = `${diffSeconds}s`;
6645
+ }
6646
+ return `+${diffText}`;
6269
6647
  }
6270
- return timeDisplay;
6648
+ return null;
6271
6649
  }, [hour, minute, second, startTime, selectedDate, timezone]);
6272
6650
  const handleClear = () => {
6273
6651
  setHour(null);
@@ -6295,16 +6673,17 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
6295
6673
  });
6296
6674
  }
6297
6675
  };
6298
- const handleInputValueChange = (details) => {
6299
- const inputValue = details.inputValue.trim();
6676
+ // Parse input value and update state
6677
+ const parseAndCommitInput = (value) => {
6678
+ const trimmedValue = value.trim();
6300
6679
  // Filter the collection based on input
6301
- filter(inputValue);
6302
- if (!inputValue) {
6680
+ filter(trimmedValue);
6681
+ if (!trimmedValue) {
6303
6682
  return;
6304
6683
  }
6305
6684
  // Parse HH:mm:ss or HH:mm format
6306
6685
  const timePattern = /^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/;
6307
- const match = inputValue.match(timePattern);
6686
+ const match = trimmedValue.match(timePattern);
6308
6687
  if (match) {
6309
6688
  const parsedHour = parseInt(match[1], 10);
6310
6689
  const parsedMinute = parseInt(match[2], 10);
@@ -6324,11 +6703,12 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
6324
6703
  minute: parsedMinute,
6325
6704
  second: parsedSecond,
6326
6705
  });
6706
+ return;
6327
6707
  }
6328
6708
  }
6329
6709
  else {
6330
6710
  // Try to parse formats like "123045" (HHmmss) or "1230" (HHmm)
6331
- const numbersOnly = inputValue.replace(/[^0-9]/g, '');
6711
+ const numbersOnly = trimmedValue.replace(/[^0-9]/g, '');
6332
6712
  if (numbersOnly.length >= 4) {
6333
6713
  const parsedHour = parseInt(numbersOnly.slice(0, 2), 10);
6334
6714
  const parsedMinute = parseInt(numbersOnly.slice(2, 4), 10);
@@ -6348,11 +6728,56 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
6348
6728
  minute: parsedMinute,
6349
6729
  second: parsedSecond,
6350
6730
  });
6731
+ return;
6351
6732
  }
6352
6733
  }
6353
6734
  }
6735
+ // Parse failed, select first result
6736
+ selectFirstResult();
6737
+ };
6738
+ // Select first result from filtered collection
6739
+ const selectFirstResult = () => {
6740
+ if (collection.items.length > 0) {
6741
+ const firstItem = collection.items[0];
6742
+ setHour(firstItem.hour);
6743
+ setMinute(firstItem.minute);
6744
+ setSecond(firstItem.second);
6745
+ filter(''); // Reset filter after selection
6746
+ onChange({
6747
+ hour: firstItem.hour,
6748
+ minute: firstItem.minute,
6749
+ second: firstItem.second,
6750
+ });
6751
+ }
6752
+ };
6753
+ const handleInputValueChange = (details) => {
6754
+ // Filter the collection based on input, but don't parse yet
6755
+ filter(details.inputValue);
6756
+ };
6757
+ const handleFocus = (e) => {
6758
+ // Select all text when focusing
6759
+ e.target.select();
6760
+ };
6761
+ const handleBlur = (e) => {
6762
+ // Parse and commit the input value when losing focus
6763
+ const inputValue = e.target.value;
6764
+ if (inputValue) {
6765
+ parseAndCommitInput(inputValue);
6766
+ }
6767
+ };
6768
+ const handleKeyDown = (e) => {
6769
+ // Commit input on Enter key
6770
+ if (e.key === 'Enter') {
6771
+ e.preventDefault();
6772
+ const inputValue = e.currentTarget.value;
6773
+ if (inputValue) {
6774
+ parseAndCommitInput(inputValue);
6775
+ }
6776
+ // Blur the input
6777
+ e.currentTarget?.blur();
6778
+ }
6354
6779
  };
6355
- return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Grid, { justifyContent: 'center', alignItems: 'center', templateColumns: '1fr auto', gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, width: "100%", children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder: "HH:mm:ss", value: displayText }) }), jsxRuntime.jsxs(react.Combobox.IndicatorGroup, { children: [jsxRuntime.jsx(react.Combobox.ClearTrigger, {}), jsxRuntime.jsx(react.Combobox.Trigger, {})] })] }), jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [jsxRuntime.jsx(react.Combobox.Empty, { children: "No time found" }), collection.items.map((item) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [item.label, jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdCancel, {}) }) })] }) }));
6780
+ return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxRuntime.jsxs(react.Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxRuntime.jsxs(react.Combobox.Control, { children: [jsxRuntime.jsx(react.InputGroup, { startElement: jsxRuntime.jsx(bs.BsClock, {}), children: jsxRuntime.jsx(react.Combobox.Input, { placeholder: "HH:mm:ss", onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsxRuntime.jsx(react.Combobox.IndicatorGroup, { children: jsxRuntime.jsx(react.Combobox.Trigger, {}) })] }), jsxRuntime.jsx(react.Portal, { disabled: !portalled, children: jsxRuntime.jsx(react.Combobox.Positioner, { children: jsxRuntime.jsxs(react.Combobox.Content, { children: [jsxRuntime.jsx(react.Combobox.Empty, { children: "No time found" }), collection.items.map((item) => (jsxRuntime.jsxs(react.Combobox.Item, { item: item, children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsxRuntime.jsx(react.Text, { flex: 1, children: item.label }), item.durationText && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: item.durationText }) }))] }), jsxRuntime.jsx(react.Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsxRuntime.jsx(react.Tag.Root, { size: "sm", children: jsxRuntime.jsx(react.Tag.Label, { children: durationDiff }) })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(react.Icon, { children: jsxRuntime.jsx(md.MdCancel, {}) }) })] }) }));
6356
6781
  }
6357
6782
 
6358
6783
  dayjs.extend(utc);
@@ -6375,30 +6800,193 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
6375
6800
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
6376
6801
  backButtonLabel: 'Back',
6377
6802
  forwardButtonLabel: 'Next',
6378
- }, timezone = 'Asia/Hong_Kong', startTime, }) {
6379
- const [selectedDate, setSelectedDate] = React.useState(value || '');
6803
+ }, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
6804
+ console.log('[DateTimePicker] Component initialized with props:', {
6805
+ value,
6806
+ format,
6807
+ showSeconds,
6808
+ timezone,
6809
+ startTime,
6810
+ minDate,
6811
+ maxDate,
6812
+ });
6813
+ // Initialize selectedDate from value prop, converting ISO to YYYY-MM-DD format
6814
+ const getDateString = React.useCallback((val) => {
6815
+ if (!val)
6816
+ return '';
6817
+ const dateObj = dayjs(val).tz(timezone);
6818
+ return dateObj.isValid() ? dateObj.format('YYYY-MM-DD') : '';
6819
+ }, [timezone]);
6820
+ const [selectedDate, setSelectedDate] = React.useState(getDateString(value));
6821
+ // Helper to get time values from value prop with timezone
6822
+ const getTimeFromValue = React.useCallback((val) => {
6823
+ console.log('[DateTimePicker] getTimeFromValue called:', {
6824
+ val,
6825
+ timezone,
6826
+ showSeconds,
6827
+ });
6828
+ if (!val) {
6829
+ console.log('[DateTimePicker] No value provided, returning nulls');
6830
+ return {
6831
+ hour12: null,
6832
+ minute: null,
6833
+ meridiem: null,
6834
+ hour24: null,
6835
+ second: null,
6836
+ };
6837
+ }
6838
+ const dateObj = dayjs(val).tz(timezone);
6839
+ console.log('[DateTimePicker] Parsed date object:', {
6840
+ original: val,
6841
+ timezone,
6842
+ isValid: dateObj.isValid(),
6843
+ formatted: dateObj.format('YYYY-MM-DD HH:mm:ss Z'),
6844
+ hour24: dateObj.hour(),
6845
+ minute: dateObj.minute(),
6846
+ second: dateObj.second(),
6847
+ });
6848
+ if (!dateObj.isValid()) {
6849
+ console.log('[DateTimePicker] Invalid date object, returning nulls');
6850
+ return {
6851
+ hour12: null,
6852
+ minute: null,
6853
+ meridiem: null,
6854
+ hour24: null,
6855
+ second: null,
6856
+ };
6857
+ }
6858
+ const hour24Value = dateObj.hour();
6859
+ const hour12Value = hour24Value % 12 || 12;
6860
+ const minuteValue = dateObj.minute();
6861
+ const meridiemValue = hour24Value >= 12 ? 'pm' : 'am';
6862
+ const secondValue = showSeconds ? dateObj.second() : null;
6863
+ const result = {
6864
+ hour12: hour12Value,
6865
+ minute: minuteValue,
6866
+ meridiem: meridiemValue,
6867
+ hour24: hour24Value,
6868
+ second: secondValue,
6869
+ };
6870
+ console.log('[DateTimePicker] Extracted time values:', result);
6871
+ return result;
6872
+ }, [timezone, showSeconds]);
6873
+ const initialTime = getTimeFromValue(value);
6874
+ console.log('[DateTimePicker] Initial time from value:', {
6875
+ value,
6876
+ initialTime,
6877
+ });
6380
6878
  // Time state for 12-hour format
6381
- const [hour12, setHour12] = React.useState(value ? dayjs(value).hour() % 12 || 12 : null);
6382
- const [minute, setMinute] = React.useState(value ? dayjs(value).minute() : null);
6383
- const [meridiem, setMeridiem] = React.useState(value ? (dayjs(value).hour() >= 12 ? 'pm' : 'am') : null);
6879
+ const [hour12, setHour12] = React.useState(initialTime.hour12);
6880
+ const [minute, setMinute] = React.useState(initialTime.minute);
6881
+ const [meridiem, setMeridiem] = React.useState(initialTime.meridiem);
6384
6882
  // Time state for 24-hour format
6385
- const [hour24, setHour24] = React.useState(value ? dayjs(value).hour() : null);
6386
- const [second, setSecond] = React.useState(showSeconds && value ? dayjs(value).second() : null);
6883
+ const [hour24, setHour24] = React.useState(initialTime.hour24);
6884
+ const [second, setSecond] = React.useState(initialTime.second);
6885
+ // Sync selectedDate and time states when value prop changes
6886
+ React.useEffect(() => {
6887
+ console.log('[DateTimePicker] useEffect triggered - value changed:', {
6888
+ value,
6889
+ timezone,
6890
+ format,
6891
+ });
6892
+ // If value is null, undefined, or invalid, clear all fields
6893
+ if (!value || value === null || value === undefined) {
6894
+ console.log('[DateTimePicker] Value is null/undefined, clearing all fields');
6895
+ setSelectedDate('');
6896
+ setHour12(null);
6897
+ setMinute(null);
6898
+ setMeridiem(null);
6899
+ setHour24(null);
6900
+ setSecond(null);
6901
+ return;
6902
+ }
6903
+ // Check if value is valid
6904
+ const dateObj = dayjs(value).tz(timezone);
6905
+ if (!dateObj.isValid()) {
6906
+ console.log('[DateTimePicker] Invalid value, clearing all fields');
6907
+ setSelectedDate('');
6908
+ setHour12(null);
6909
+ setMinute(null);
6910
+ setMeridiem(null);
6911
+ setHour24(null);
6912
+ setSecond(null);
6913
+ return;
6914
+ }
6915
+ const dateString = getDateString(value);
6916
+ console.log('[DateTimePicker] Setting selectedDate:', dateString);
6917
+ setSelectedDate(dateString);
6918
+ const timeData = getTimeFromValue(value);
6919
+ console.log('[DateTimePicker] Updating time states:', {
6920
+ timeData,
6921
+ });
6922
+ setHour12(timeData.hour12);
6923
+ setMinute(timeData.minute);
6924
+ setMeridiem(timeData.meridiem);
6925
+ setHour24(timeData.hour24);
6926
+ setSecond(timeData.second);
6927
+ }, [value, getTimeFromValue, getDateString, timezone]);
6387
6928
  const handleDateChange = (date) => {
6929
+ console.log('[DateTimePicker] handleDateChange called:', {
6930
+ date,
6931
+ timezone,
6932
+ showSeconds,
6933
+ currentTimeStates: { hour12, minute, meridiem, hour24, second },
6934
+ });
6935
+ // If date is empty or invalid, clear all fields
6936
+ if (!date || date === '') {
6937
+ console.log('[DateTimePicker] Empty date, clearing all fields');
6938
+ setSelectedDate('');
6939
+ setHour12(null);
6940
+ setMinute(null);
6941
+ setMeridiem(null);
6942
+ setHour24(null);
6943
+ setSecond(null);
6944
+ onChange?.(undefined);
6945
+ return;
6946
+ }
6388
6947
  setSelectedDate(date);
6948
+ // Parse the date string (YYYY-MM-DD) in the specified timezone
6949
+ const dateObj = dayjs.tz(date, timezone);
6950
+ console.log('[DateTimePicker] Parsed date object:', {
6951
+ date,
6952
+ timezone,
6953
+ isValid: dateObj.isValid(),
6954
+ isoString: dateObj.toISOString(),
6955
+ formatted: dateObj.format('YYYY-MM-DD HH:mm:ss Z'),
6956
+ });
6957
+ if (!dateObj.isValid()) {
6958
+ console.warn('[DateTimePicker] Invalid date object in handleDateChange, clearing fields');
6959
+ setSelectedDate('');
6960
+ setHour12(null);
6961
+ setMinute(null);
6962
+ setMeridiem(null);
6963
+ setHour24(null);
6964
+ setSecond(null);
6965
+ onChange?.(undefined);
6966
+ return;
6967
+ }
6389
6968
  // When showSeconds is false, ignore seconds from the date
6390
- const dateObj = dayjs(date).tz(timezone);
6391
- if (!showSeconds && dateObj.isValid()) {
6969
+ if (!showSeconds) {
6392
6970
  const dateWithoutSeconds = dateObj.second(0).millisecond(0).toISOString();
6971
+ console.log('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
6393
6972
  updateDateTime(dateWithoutSeconds);
6394
6973
  }
6395
6974
  else {
6396
- updateDateTime(dateObj.toISOString());
6975
+ const dateWithSeconds = dateObj.toISOString();
6976
+ console.log('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
6977
+ updateDateTime(dateWithSeconds);
6397
6978
  }
6398
6979
  };
6399
6980
  const handleTimeChange = (timeData) => {
6981
+ console.log('[DateTimePicker] handleTimeChange called:', {
6982
+ timeData,
6983
+ format,
6984
+ selectedDate,
6985
+ timezone,
6986
+ });
6400
6987
  if (format === 'iso-date-time') {
6401
6988
  const data = timeData;
6989
+ console.log('[DateTimePicker] ISO format - setting 24-hour time:', data);
6402
6990
  setHour24(data.hour);
6403
6991
  setMinute(data.minute);
6404
6992
  if (showSeconds) {
@@ -6411,60 +6999,161 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
6411
6999
  }
6412
7000
  else {
6413
7001
  const data = timeData;
7002
+ console.log('[DateTimePicker] 12-hour format - setting time:', data);
6414
7003
  setHour12(data.hour);
6415
7004
  setMinute(data.minute);
6416
7005
  setMeridiem(data.meridiem);
6417
7006
  }
6418
- // Use selectedDate if valid, otherwise use today's date as fallback
6419
- const dateToUse = selectedDate && dayjs(selectedDate).isValid()
6420
- ? selectedDate
6421
- : dayjs().tz(timezone).toISOString();
6422
- const dateObj = dayjs(dateToUse).tz(timezone);
7007
+ // Use selectedDate if valid, otherwise clear all fields
7008
+ if (!selectedDate || !dayjs(selectedDate).isValid()) {
7009
+ console.log('[DateTimePicker] No valid selectedDate, clearing all fields');
7010
+ setSelectedDate('');
7011
+ setHour12(null);
7012
+ setMinute(null);
7013
+ setMeridiem(null);
7014
+ setHour24(null);
7015
+ setSecond(null);
7016
+ onChange?.(undefined);
7017
+ return;
7018
+ }
7019
+ const dateObj = dayjs(selectedDate).tz(timezone);
6423
7020
  if (dateObj.isValid()) {
6424
7021
  updateDateTime(dateObj.toISOString(), timeData);
6425
7022
  }
7023
+ else {
7024
+ console.warn('[DateTimePicker] Invalid date object in handleTimeChange, clearing fields');
7025
+ setSelectedDate('');
7026
+ setHour12(null);
7027
+ setMinute(null);
7028
+ setMeridiem(null);
7029
+ setHour24(null);
7030
+ setSecond(null);
7031
+ onChange?.(undefined);
7032
+ }
6426
7033
  };
6427
7034
  const updateDateTime = (date, timeData) => {
6428
- if (!date) {
7035
+ console.log('[DateTimePicker] updateDateTime called:', {
7036
+ date,
7037
+ timeData,
7038
+ format,
7039
+ currentStates: { hour12, minute, meridiem, hour24, second },
7040
+ });
7041
+ if (!date || date === null || date === undefined) {
7042
+ console.log('[DateTimePicker] No date provided, clearing all fields and calling onChange(undefined)');
7043
+ setSelectedDate('');
7044
+ setHour12(null);
7045
+ setMinute(null);
7046
+ setMeridiem(null);
7047
+ setHour24(null);
7048
+ setSecond(null);
6429
7049
  onChange?.(undefined);
6430
7050
  return;
6431
7051
  }
6432
7052
  // use dayjs to convert the date to the timezone
6433
7053
  const dateObj = dayjs(date).tz(timezone);
6434
7054
  if (!dateObj.isValid()) {
7055
+ console.warn('[DateTimePicker] Invalid date object in updateDateTime, clearing fields:', date);
7056
+ setSelectedDate('');
7057
+ setHour12(null);
7058
+ setMinute(null);
7059
+ setMeridiem(null);
7060
+ setHour24(null);
7061
+ setSecond(null);
7062
+ onChange?.(undefined);
6435
7063
  return;
6436
7064
  }
6437
7065
  const newDate = dateObj.toDate();
6438
7066
  if (format === 'iso-date-time') {
6439
7067
  const data = timeData;
6440
- const h = data?.hour ?? hour24;
6441
- const m = data?.minute ?? minute;
7068
+ // Use timeData values if provided, otherwise fall back to current state
7069
+ // But if timeData is explicitly provided with nulls, we need to check if all are null
7070
+ const h = data !== undefined ? data.hour : hour24;
7071
+ const m = data !== undefined ? data.minute : minute;
6442
7072
  // Always ignore seconds when showSeconds is false - set to 0
6443
- const s = showSeconds ? data?.second ?? second ?? 0 : 0;
7073
+ const s = showSeconds
7074
+ ? data !== undefined
7075
+ ? data.second ?? null
7076
+ : second ?? 0
7077
+ : 0;
7078
+ // If all time values are null, clear the value
7079
+ if (h === null && m === null && (showSeconds ? s === null : true)) {
7080
+ console.log('[DateTimePicker] All time values are null, clearing value');
7081
+ onChange?.(undefined);
7082
+ return;
7083
+ }
7084
+ console.log('[DateTimePicker] ISO format - setting time on date:', {
7085
+ h,
7086
+ m,
7087
+ s,
7088
+ showSeconds,
7089
+ });
6444
7090
  if (h !== null)
6445
7091
  newDate.setHours(h);
6446
7092
  if (m !== null)
6447
7093
  newDate.setMinutes(m);
6448
- newDate.setSeconds(s);
7094
+ newDate.setSeconds(s ?? 0);
6449
7095
  }
6450
7096
  else {
6451
7097
  const data = timeData;
6452
- const h = data?.hour ?? hour12;
6453
- const m = data?.minute ?? minute;
6454
- const mer = data?.meridiem ?? meridiem;
7098
+ console.log('[DateTimePicker] Processing 12-hour format:', {
7099
+ 'data !== undefined': data !== undefined,
7100
+ 'data?.hour': data?.hour,
7101
+ 'data?.minute': data?.minute,
7102
+ 'data?.meridiem': data?.meridiem,
7103
+ 'current hour12': hour12,
7104
+ 'current minute': minute,
7105
+ 'current meridiem': meridiem,
7106
+ });
7107
+ // Use timeData values if provided, otherwise fall back to current state
7108
+ const h = data !== undefined ? data.hour : hour12;
7109
+ const m = data !== undefined ? data.minute : minute;
7110
+ const mer = data !== undefined ? data.meridiem : meridiem;
7111
+ console.log('[DateTimePicker] Resolved time values:', { h, m, mer });
7112
+ // If all time values are null, clear the value
7113
+ if (h === null && m === null && mer === null) {
7114
+ console.log('[DateTimePicker] All time values are null, clearing value');
7115
+ onChange?.(undefined);
7116
+ return;
7117
+ }
7118
+ console.log('[DateTimePicker] 12-hour format - converting time:', {
7119
+ h,
7120
+ m,
7121
+ mer,
7122
+ });
6455
7123
  if (h !== null && mer !== null) {
6456
7124
  let hour24 = h;
6457
7125
  if (mer === 'am' && h === 12)
6458
7126
  hour24 = 0;
6459
7127
  else if (mer === 'pm' && h < 12)
6460
7128
  hour24 = h + 12;
7129
+ console.log('[DateTimePicker] Converted to 24-hour:', {
7130
+ h,
7131
+ mer,
7132
+ hour24,
7133
+ });
6461
7134
  newDate.setHours(hour24);
6462
7135
  }
6463
- if (m !== null)
7136
+ else {
7137
+ console.log('[DateTimePicker] Skipping hour update - h or mer is null:', {
7138
+ h,
7139
+ mer,
7140
+ });
7141
+ }
7142
+ if (m !== null) {
6464
7143
  newDate.setMinutes(m);
7144
+ }
7145
+ else {
7146
+ console.log('[DateTimePicker] Skipping minute update - m is null');
7147
+ }
6465
7148
  newDate.setSeconds(0);
6466
7149
  }
6467
- onChange?.(dayjs(newDate).tz(timezone).toISOString());
7150
+ const finalISO = dayjs(newDate).tz(timezone).toISOString();
7151
+ console.log('[DateTimePicker] Final ISO string to emit:', {
7152
+ newDate: newDate.toISOString(),
7153
+ timezone,
7154
+ finalISO,
7155
+ });
7156
+ onChange?.(finalISO);
6468
7157
  };
6469
7158
  const handleClear = () => {
6470
7159
  setSelectedDate('');
@@ -6480,14 +7169,92 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
6480
7169
  const normalizedStartTime = startTime
6481
7170
  ? dayjs(startTime).tz(timezone).millisecond(0).toISOString()
6482
7171
  : undefined;
6483
- return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsxRuntime.jsx(DatePicker$1, { selected: selectedDate ? dayjs(selectedDate).tz(timezone).toDate() : new Date(), onDateSelected: ({ date }) => handleDateChange(dayjs(date).tz(timezone).toISOString()), monthsToDisplay: 1, labels: labels, minDate: normalizedStartTime &&
6484
- dayjs(normalizedStartTime).tz(timezone).isValid()
6485
- ? dayjs(normalizedStartTime).tz(timezone).startOf('day').toDate()
6486
- : undefined }), jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsxRuntime.jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: showSeconds ? second : null, setSecond: showSeconds ? setSecond : () => { }, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone })) : (jsxRuntime.jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsxRuntime.jsx(react.Icon, { as: fa6.FaTrash }) })] }), selectedDate && (jsxRuntime.jsxs(react.Flex, { gap: 2, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: dayjs(value).format(isISO
6487
- ? showSeconds
6488
- ? 'YYYY-MM-DD HH:mm:ss'
6489
- : 'YYYY-MM-DD HH:mm'
6490
- : 'YYYY-MM-DD hh:mm A ') }), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: dayjs(value).tz(timezone).format('Z') }), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
7172
+ // Determine minDate: prioritize explicit minDate prop, then fall back to startTime
7173
+ const effectiveMinDate = minDate
7174
+ ? minDate
7175
+ : normalizedStartTime && dayjs(normalizedStartTime).tz(timezone).isValid()
7176
+ ? dayjs(normalizedStartTime).tz(timezone).startOf('day').toDate()
7177
+ : undefined;
7178
+ // Log current state before render
7179
+ React.useEffect(() => {
7180
+ console.log('[DateTimePicker] Current state before render:', {
7181
+ isISO,
7182
+ hour12,
7183
+ minute,
7184
+ meridiem,
7185
+ hour24,
7186
+ second,
7187
+ selectedDate,
7188
+ normalizedStartTime,
7189
+ timezone,
7190
+ });
7191
+ }, [
7192
+ isISO,
7193
+ hour12,
7194
+ minute,
7195
+ meridiem,
7196
+ hour24,
7197
+ second,
7198
+ selectedDate,
7199
+ normalizedStartTime,
7200
+ timezone,
7201
+ ]);
7202
+ // Compute display text from current state
7203
+ const displayText = React.useMemo(() => {
7204
+ if (!selectedDate)
7205
+ return null;
7206
+ const dateObj = dayjs.tz(selectedDate, timezone);
7207
+ if (!dateObj.isValid())
7208
+ return null;
7209
+ if (isISO) {
7210
+ // For ISO format, use hour24, minute, second
7211
+ if (hour24 === null || minute === null)
7212
+ return null;
7213
+ const dateTimeObj = dateObj
7214
+ .hour(hour24)
7215
+ .minute(minute)
7216
+ .second(second ?? 0);
7217
+ return dateTimeObj.format(showSeconds ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD HH:mm');
7218
+ }
7219
+ else {
7220
+ // For 12-hour format, use hour12, minute, meridiem
7221
+ if (hour12 === null || minute === null || meridiem === null)
7222
+ return null;
7223
+ // Convert to 24-hour format for dayjs
7224
+ let hour24Value = hour12;
7225
+ if (meridiem === 'am' && hour12 === 12)
7226
+ hour24Value = 0;
7227
+ else if (meridiem === 'pm' && hour12 < 12)
7228
+ hour24Value = hour12 + 12;
7229
+ const dateTimeObj = dateObj.hour(hour24Value).minute(minute).second(0);
7230
+ return dateTimeObj.format('YYYY-MM-DD hh:mm A');
7231
+ }
7232
+ }, [
7233
+ selectedDate,
7234
+ isISO,
7235
+ hour12,
7236
+ minute,
7237
+ meridiem,
7238
+ hour24,
7239
+ second,
7240
+ showSeconds,
7241
+ timezone,
7242
+ ]);
7243
+ const timezoneOffset = React.useMemo(() => {
7244
+ if (!selectedDate)
7245
+ return null;
7246
+ const dateObj = dayjs.tz(selectedDate, timezone);
7247
+ return dateObj.isValid() ? dateObj.format('Z') : null;
7248
+ }, [selectedDate, timezone]);
7249
+ return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsxRuntime.jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
7250
+ if (date) {
7251
+ handleDateChange(date);
7252
+ }
7253
+ else {
7254
+ setSelectedDate('');
7255
+ onChange?.(undefined);
7256
+ }
7257
+ }, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsxRuntime.jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: showSeconds ? second : null, setSecond: showSeconds ? setSecond : () => { }, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled })) : (jsxRuntime.jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, startTime: normalizedStartTime, selectedDate: selectedDate, timezone: timezone, portalled: portalled })), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsxRuntime.jsx(react.Icon, { as: fa6.FaTrash }) })] }), displayText && (jsxRuntime.jsxs(react.Flex, { gap: 2, children: [jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsxRuntime.jsx(react.Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
6491
7258
  }
6492
7259
 
6493
7260
  dayjs.extend(utc);
@@ -6495,7 +7262,7 @@ dayjs.extend(timezone);
6495
7262
  const DateTimePicker = ({ column, schema, prefix, }) => {
6496
7263
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
6497
7264
  const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
6498
- const formI18n = useFormI18n(column, prefix);
7265
+ const formI18n = useFormI18n$1(column, prefix, schema);
6499
7266
  const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss',
6500
7267
  // with timezone
6501
7268
  dateFormat = 'YYYY-MM-DD[T]HH:mm:ssZ', } = schema;
@@ -6503,32 +7270,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
6503
7270
  const colLabel = formI18n.colLabel;
6504
7271
  const [open, setOpen] = React.useState(false);
6505
7272
  const selectedDate = watch(colLabel);
6506
- const displayDate = dayjs(selectedDate)
6507
- .tz(timezone)
6508
- .format(displayDateFormat);
6509
- React.useEffect(() => {
6510
- try {
6511
- if (selectedDate) {
6512
- // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
6513
- // For example, parse as UTC:
6514
- const parsedDate = dayjs(selectedDate).tz(timezone);
6515
- if (!parsedDate.isValid())
6516
- return;
6517
- // Format according to dateFormat from schema
6518
- const formatted = parsedDate.format(dateFormat);
6519
- // Update the form value only if different to avoid loops
6520
- if (formatted !== selectedDate) {
6521
- setValue(colLabel, formatted, {
6522
- shouldValidate: true,
6523
- shouldDirty: true,
6524
- });
6525
- }
6526
- }
6527
- }
6528
- catch (e) {
6529
- console.error(e);
6530
- }
6531
- }, [selectedDate, dateFormat, colLabel, setValue]);
7273
+ const displayDate = selectedDate && dayjs(selectedDate).tz(timezone).isValid()
7274
+ ? dayjs(selectedDate).tz(timezone).format(displayDateFormat)
7275
+ : '';
6532
7276
  const dateTimePickerLabelsConfig = {
6533
7277
  monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
6534
7278
  formI18n.translate.t(`common.month_1`, {
@@ -6601,12 +7345,22 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
6601
7345
  }),
6602
7346
  };
6603
7347
  const dateTimePickerContent = (jsxRuntime.jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
6604
- setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
7348
+ if (!date || date === null || date === undefined) {
7349
+ setValue(colLabel, undefined);
7350
+ return;
7351
+ }
7352
+ const dateObj = dayjs(date).tz(timezone);
7353
+ if (dateObj.isValid()) {
7354
+ setValue(colLabel, dateObj.format(dateFormat));
7355
+ }
7356
+ else {
7357
+ setValue(colLabel, undefined);
7358
+ }
6605
7359
  }, timezone: timezone, labels: dateTimePickerLabelsConfig }));
6606
7360
  return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
6607
- gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
7361
+ gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxRuntime.jsxs(react.Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsxRuntime.jsx(react.Popover.Trigger, { asChild: true, children: jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
6608
7362
  setOpen(true);
6609
- }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minW: "450px", minH: "25rem", children: jsxRuntime.jsx(react.Popover.Body, { children: dateTimePickerContent }) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minW: "450px", minH: "25rem", children: jsxRuntime.jsx(react.Popover.Body, { children: dateTimePickerContent }) }) }) }))] }) }));
7363
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), displayDate || ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minW: "450px", minH: "25rem", children: jsxRuntime.jsx(react.Popover.Body, { children: dateTimePickerContent }) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minW: "450px", minH: "25rem", children: jsxRuntime.jsx(react.Popover.Body, { children: dateTimePickerContent }) }) }) }))] }) }));
6610
7364
  };
6611
7365
 
6612
7366
  const SchemaRenderer = ({ schema, prefix, column, }) => {
@@ -6650,7 +7404,7 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
6650
7404
  if (innerProperties) {
6651
7405
  return jsxRuntime.jsx(ObjectInput, { schema: colSchema, prefix, column });
6652
7406
  }
6653
- return jsxRuntime.jsx(RecordInput$1, { schema: colSchema, prefix, column });
7407
+ return jsxRuntime.jsx(RecordInput, { schema: colSchema, prefix, column });
6654
7408
  }
6655
7409
  if (type === 'array') {
6656
7410
  if (variant === 'id-picker') {
@@ -6704,32 +7458,30 @@ const ColumnRenderer = ({ column, properties, prefix, parentRequired, }) => {
6704
7458
  };
6705
7459
 
6706
7460
  const ArrayViewer = ({ schema, column, prefix }) => {
6707
- const { gridColumn = "span 12", gridRow = "span 1", required, items, } = schema;
6708
- const { translate } = useSchemaContext();
7461
+ const { gridColumn = 'span 12', gridRow = 'span 1', required, items, } = schema;
6709
7462
  const colLabel = `${prefix}${column}`;
6710
7463
  const isRequired = required?.some((columnId) => columnId === column);
7464
+ const formI18n = useFormI18n$1(column, prefix, schema);
6711
7465
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6712
7466
  const values = watch(colLabel) ?? [];
6713
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: values.map((field, index) => (jsxRuntime.jsx(react.Flex, { flexFlow: "column", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "2", borderRadius: "md", borderWidth: "thin", borderColor: {
6714
- base: "colorPalette.200",
6715
- _dark: "colorPalette.800",
6716
- }, children: jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: jsxRuntime.jsx(SchemaViewer, { column: `${index}`,
7467
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: '1/span12', children: [formI18n.label(), isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: values.map((field, index) => (jsxRuntime.jsx(react.Flex, { flexFlow: 'column', bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: '2', borderRadius: 'md', borderWidth: 'thin', borderColor: {
7468
+ base: 'colorPalette.200',
7469
+ _dark: 'colorPalette.800',
7470
+ }, children: jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: jsxRuntime.jsx(SchemaViewer, { column: `${index}`,
6717
7471
  prefix: `${colLabel}.`,
6718
7472
  // @ts-expect-error find suitable types
6719
- schema: { showLabel: false, ...(items ?? {}) } }) }) }, `form-${prefix}${column}.${index}`))) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
7473
+ schema: { showLabel: false, ...(items ?? {}) } }) }) }, `form-${prefix}${column}.${index}`))) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
6720
7474
  };
6721
7475
 
6722
7476
  const BooleanViewer = ({ schema, column, prefix, }) => {
6723
7477
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6724
- const { translate } = useSchemaContext();
6725
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
7478
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
6726
7479
  const isRequired = required?.some((columnId) => columnId === column);
6727
7480
  const colLabel = `${prefix}${column}`;
6728
7481
  const value = watch(colLabel);
6729
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6730
- gridRow, children: [jsxRuntime.jsx(react.Text, { children: value
6731
- ? translate.t(removeIndex(`${colLabel}.true`))
6732
- : translate.t(removeIndex(`${colLabel}.false`)) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
7482
+ const formI18n = useFormI18n$1(column, prefix, schema);
7483
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7484
+ gridRow, children: [jsxRuntime.jsx(react.Text, { children: value ? formI18n.t('true') : formI18n.t('false') }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
6733
7485
  };
6734
7486
 
6735
7487
  const CustomViewer = ({ column, schema, prefix }) => {
@@ -6746,19 +7498,22 @@ const CustomViewer = ({ column, schema, prefix }) => {
6746
7498
 
6747
7499
  const DateViewer = ({ column, schema, prefix }) => {
6748
7500
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6749
- const { translate, timezone } = useSchemaContext();
6750
- const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
7501
+ const { timezone } = useSchemaContext();
7502
+ const { required, gridColumn = 'span 4', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', } = schema;
6751
7503
  const isRequired = required?.some((columnId) => columnId === column);
6752
7504
  const colLabel = `${prefix}${column}`;
6753
7505
  const selectedDate = watch(colLabel);
6754
- const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
6755
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6756
- gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
7506
+ const formI18n = useFormI18n$1(column, prefix, schema);
7507
+ const displayDate = dayjs(selectedDate)
7508
+ .tz(timezone)
7509
+ .format(displayDateFormat);
7510
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7511
+ gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ''] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
6757
7512
  };
6758
7513
 
6759
7514
  const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
6760
7515
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6761
- const formI18n = useFormI18n(column, prefix);
7516
+ const formI18n = useFormI18n$1(column, prefix);
6762
7517
  const { required } = schema;
6763
7518
  const isRequired = required?.some((columnId) => columnId === column);
6764
7519
  const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
@@ -6779,54 +7534,56 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
6779
7534
 
6780
7535
  const FileViewer = ({ column, schema, prefix }) => {
6781
7536
  const { watch } = reactHookForm.useFormContext();
6782
- const { translate } = useSchemaContext();
6783
- const { required, gridColumn = "span 12", gridRow = "span 1", } = schema;
7537
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', } = schema;
6784
7538
  const isRequired = required?.some((columnId) => columnId === column);
6785
7539
  const currentFiles = (watch(column) ?? []);
6786
- const colLabel = `${prefix}${column}`;
6787
- return (jsxRuntime.jsx(Field, { label: `${translate.t(`${colLabel}.field_label`)}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: "grid", gridTemplateRows: "auto 1fr auto", alignItems: "stretch", children: jsxRuntime.jsx(react.Flex, { flexFlow: "column", gap: 1, children: currentFiles.map((file) => {
6788
- return (jsxRuntime.jsx(react.Card.Root, { variant: "subtle", children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", display: "flex", flexFlow: "row", alignItems: "center", padding: "2", children: [file.type.startsWith("image/") && (jsxRuntime.jsx(react.Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsxRuntime.jsx(react.Box, { children: file.name })] }) }, file.name));
7540
+ const formI18n = useFormI18n$1(column, prefix, schema);
7541
+ return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, display: 'grid', gridTemplateRows: 'auto 1fr auto', alignItems: 'stretch', children: jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFiles.map((file) => {
7542
+ return (jsxRuntime.jsx(react.Card.Root, { variant: 'subtle', children: jsxRuntime.jsxs(react.Card.Body, { gap: "2", display: 'flex', flexFlow: 'row', alignItems: 'center', padding: '2', children: [file.type.startsWith('image/') && (jsxRuntime.jsx(react.Image, { src: URL.createObjectURL(file), alt: file.name, boxSize: "50px", objectFit: "cover", borderRadius: "md", marginRight: "2" })), jsxRuntime.jsx(react.Box, { children: file.name })] }) }, file.name));
6789
7543
  }) }) }));
6790
7544
  };
6791
7545
 
6792
7546
  const IdViewer = ({ column, schema, prefix, isMultiple = false, }) => {
6793
7547
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6794
7548
  const { idMap, translate } = useSchemaContext();
6795
- const { required, gridColumn = "span 12", gridRow = "span 1", renderDisplay, foreign_key, } = schema;
7549
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
6796
7550
  const isRequired = required?.some((columnId) => columnId === column);
6797
- const { display_column } = foreign_key;
7551
+ const formI18n = useFormI18n(column, prefix, schema);
6798
7552
  const colLabel = `${prefix}${column}`;
6799
7553
  const watchId = watch(colLabel);
6800
7554
  const watchIds = (watch(colLabel) ?? []);
6801
7555
  const getPickedValue = () => {
6802
7556
  if (Object.keys(idMap).length <= 0) {
6803
- return "";
7557
+ return '';
6804
7558
  }
6805
7559
  const record = idMap[watchId];
6806
7560
  if (record === undefined) {
6807
- return "";
7561
+ return '';
6808
7562
  }
6809
- return record[display_column];
7563
+ const rendered = renderDisplay
7564
+ ? renderDisplay(record)
7565
+ : defaultRenderDisplay(record);
7566
+ return typeof rendered === 'string' ? rendered : JSON.stringify(record);
6810
7567
  };
6811
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
6812
- gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 1, children: watchIds.map((id) => {
7568
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7569
+ gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchIds.map((id) => {
6813
7570
  const item = idMap[id];
6814
7571
  if (item === undefined) {
6815
7572
  return (jsxRuntime.jsx(react.Text, { children: translate.t(removeIndex(`${colLabel}.undefined`)) }, id));
6816
7573
  }
6817
- return (jsxRuntime.jsx(Tag, { closable: true, children: !!renderDisplay === true
7574
+ return (jsxRuntime.jsx(Tag, { closable: true, children: renderDisplay
6818
7575
  ? renderDisplay(item)
6819
- : item[display_column] }, id));
6820
- }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
7576
+ : defaultRenderDisplay(item) }, id));
7577
+ }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
6821
7578
  };
6822
7579
 
6823
7580
  const NumberViewer = ({ schema, column, prefix, }) => {
6824
7581
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6825
- const { translate } = useSchemaContext();
6826
7582
  const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
6827
7583
  const isRequired = required?.some((columnId) => columnId === column);
6828
7584
  const colLabel = `${prefix}${column}`;
6829
7585
  const value = watch(colLabel);
7586
+ const formI18n = useFormI18n$1(column, prefix, schema);
6830
7587
  // Format the value for display if formatOptions are provided
6831
7588
  const formatValue = (val) => {
6832
7589
  if (val === undefined || val === null || val === '')
@@ -6845,90 +7602,49 @@ const NumberViewer = ({ schema, column, prefix, }) => {
6845
7602
  }
6846
7603
  return String(val);
6847
7604
  };
6848
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn, gridRow, children: [jsxRuntime.jsx(react.Text, { children: formatValue(value) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
7605
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn, gridRow, children: [jsxRuntime.jsx(react.Text, { children: formatValue(value) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
6849
7606
  };
6850
7607
 
6851
7608
  const ObjectViewer = ({ schema, column, prefix }) => {
6852
- const { properties, gridColumn = "span 12", gridRow = "span 1", required, showLabel = true, } = schema;
6853
- const { translate } = useSchemaContext();
7609
+ const { properties, gridColumn = 'span 12', gridRow = 'span 1', required, showLabel = true, } = schema;
6854
7610
  const colLabel = `${prefix}${column}`;
6855
7611
  const isRequired = required?.some((columnId) => columnId === column);
7612
+ const formI18n = useFormI18n$1(column, prefix, schema);
6856
7613
  const { formState: { errors }, } = reactHookForm.useFormContext();
6857
7614
  if (properties === undefined) {
6858
7615
  throw new Error(`properties is undefined when using ObjectInput`);
6859
7616
  }
6860
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", bgColor: { base: "colorPalette.100", _dark: "colorPalette.900" }, p: "1", borderRadius: "md", borderWidth: "thin", borderColor: {
6861
- base: "colorPalette.200",
6862
- _dark: "colorPalette.800",
7617
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [showLabel && (jsxRuntime.jsxs(react.Box, { as: "label", children: [formI18n.label(), isRequired && jsxRuntime.jsx("span", { children: "*" })] })), jsxRuntime.jsx(react.Grid, { gap: "4", padding: '4', gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', bgColor: { base: 'colorPalette.100', _dark: 'colorPalette.900' }, p: '1', borderRadius: 'md', borderWidth: 'thin', borderColor: {
7618
+ base: 'colorPalette.200',
7619
+ _dark: 'colorPalette.800',
6863
7620
  }, children: Object.keys(properties ?? {}).map((key) => {
6864
7621
  return (
6865
7622
  // @ts-expect-error find suitable types
6866
7623
  jsxRuntime.jsx(ColumnViewer, { column: `${key}`,
6867
7624
  prefix: `${prefix}${column}.`,
6868
7625
  properties }, `form-objectviewer-${colLabel}-${key}`));
6869
- }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
7626
+ }) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
6870
7627
  };
6871
7628
 
6872
- const RecordInput = ({ column, schema, prefix }) => {
6873
- const { formState: { errors }, setValue, getValues, } = reactHookForm.useFormContext();
6874
- const { translate } = useSchemaContext();
6875
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
7629
+ const RecordViewer = ({ column, schema, prefix }) => {
7630
+ const { formState: { errors }, getValues, } = reactHookForm.useFormContext();
7631
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
6876
7632
  const isRequired = required?.some((columnId) => columnId === column);
6877
7633
  const entries = Object.entries(getValues(column) ?? {});
6878
- const [showNewEntries, setShowNewEntries] = React.useState(false);
6879
- const [newKey, setNewKey] = React.useState();
6880
- const [newValue, setNewValue] = React.useState();
6881
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(`${column}.field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn, gridRow, children: [entries.map(([key, value]) => {
6882
- return (jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: key, onChange: (e) => {
6883
- const filtered = entries.filter(([target]) => {
6884
- return target !== key;
6885
- });
6886
- setValue(column, Object.fromEntries([...filtered, [e.target.value, value]]));
6887
- }, autoComplete: "off" }), jsxRuntime.jsx(react.Input, { value: value, onChange: (e) => {
6888
- setValue(column, {
6889
- ...getValues(column),
6890
- [key]: e.target.value,
6891
- });
6892
- }, autoComplete: "off" }), jsxRuntime.jsx(react.IconButton, { variant: "ghost", onClick: () => {
6893
- const filtered = entries.filter(([target]) => {
6894
- return target !== key;
6895
- });
6896
- setValue(column, Object.fromEntries([...filtered]));
6897
- }, children: jsxRuntime.jsx(cg.CgClose, {}) })] }));
6898
- }), jsxRuntime.jsx(react.Show, { when: showNewEntries, children: jsxRuntime.jsxs(react.Card.Root, { children: [jsxRuntime.jsx(react.Card.Body, { gap: "2", children: jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr 1fr auto", gap: 1, children: [jsxRuntime.jsx(react.Input, { value: newKey, onChange: (e) => {
6899
- setNewKey(e.target.value);
6900
- }, autoComplete: "off" }), jsxRuntime.jsx(react.Input, { value: newValue, onChange: (e) => {
6901
- setNewValue(e.target.value);
6902
- }, autoComplete: "off" })] }) }), jsxRuntime.jsxs(react.Card.Footer, { justifyContent: "flex-end", children: [jsxRuntime.jsx(react.IconButton, { variant: "subtle", onClick: () => {
6903
- setShowNewEntries(false);
6904
- setNewKey(undefined);
6905
- setNewValue(undefined);
6906
- }, children: jsxRuntime.jsx(cg.CgClose, {}) }), jsxRuntime.jsx(Button, { onClick: () => {
6907
- if (!!newKey === false) {
6908
- setShowNewEntries(false);
6909
- setNewKey(undefined);
6910
- setNewValue(undefined);
6911
- return;
6912
- }
6913
- setValue(column, Object.fromEntries([...entries, [newKey, newValue]]));
6914
- setShowNewEntries(false);
6915
- setNewKey(undefined);
6916
- setNewValue(undefined);
6917
- }, children: translate.t(`${column}.save`) })] })] }) }), jsxRuntime.jsx(Button, { onClick: () => {
6918
- setShowNewEntries(true);
6919
- setNewKey(undefined);
6920
- setNewValue(undefined);
6921
- }, children: translate.t(`${column}.addNew`) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
7634
+ const formI18n = useFormI18n$1(column, prefix, schema);
7635
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn, gridRow, children: [entries.length === 0 ? (jsxRuntime.jsx(react.Text, { color: "gray.500", children: "No entries" })) : (jsxRuntime.jsx(react.Grid, { templateColumns: '1fr 1fr', gap: 2, children: entries.map(([key, value]) => {
7636
+ return (jsxRuntime.jsxs(react.Grid, { templateColumns: '1fr 1fr', gap: 2, children: [jsxRuntime.jsxs(react.Text, { fontWeight: "medium", children: [key, ":"] }), jsxRuntime.jsx(react.Text, { children: String(value ?? '') })] }, key));
7637
+ }) })), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
6922
7638
  };
6923
7639
 
6924
7640
  const StringViewer = ({ column, schema, prefix, }) => {
6925
7641
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
6926
- const { translate } = useSchemaContext();
6927
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
7642
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
6928
7643
  const isRequired = required?.some((columnId) => columnId === column);
6929
7644
  const colLabel = `${prefix}${column}`;
6930
7645
  const value = watch(colLabel);
6931
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn ?? "span 4", gridRow: gridRow ?? "span 1", children: [jsxRuntime.jsx(react.Text, { children: value }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
7646
+ const formI18n = useFormI18n$1(column, prefix, schema);
7647
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn ?? 'span 4', gridRow: gridRow ?? 'span 1', children: [jsxRuntime.jsx(react.Text, { children: value }), errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }) }));
6932
7648
  };
6933
7649
 
6934
7650
  const TagViewer = ({ column, schema, prefix }) => {
@@ -7018,40 +7734,44 @@ const TagViewer = ({ column, schema, prefix }) => {
7018
7734
 
7019
7735
  const TextAreaViewer = ({ column, schema, prefix, }) => {
7020
7736
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
7021
- const { translate } = useSchemaContext();
7022
- const { required, gridColumn = "span 12", gridRow = "span 1" } = schema;
7737
+ const { required, gridColumn = 'span 12', gridRow = 'span 1' } = schema;
7023
7738
  const isRequired = required?.some((columnId) => columnId === column);
7024
7739
  const colLabel = `${prefix}${column}`;
7025
7740
  const value = watch(colLabel);
7026
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsxRuntime.jsx(react.Text, { whiteSpace: "pre-wrap", children: value }), " ", errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
7741
+ const formI18n = useFormI18n$1(column, prefix, schema);
7742
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsxRuntime.jsx(react.Text, { whiteSpace: "pre-wrap", children: value }), ' ', errors[colLabel] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }) }));
7027
7743
  };
7028
7744
 
7029
7745
  const TimeViewer = ({ column, schema, prefix }) => {
7030
7746
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
7031
- const { translate, timezone } = useSchemaContext();
7032
- const { required, gridColumn = "span 12", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
7747
+ const { timezone } = useSchemaContext();
7748
+ const { required, gridColumn = 'span 12', gridRow = 'span 1', displayTimeFormat = 'hh:mm A', } = schema;
7033
7749
  const isRequired = required?.some((columnId) => columnId === column);
7034
7750
  const colLabel = `${prefix}${column}`;
7035
7751
  const selectedDate = watch(colLabel);
7752
+ const formI18n = useFormI18n$1(column, prefix, schema);
7036
7753
  const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
7037
7754
  .tz(timezone)
7038
7755
  .isValid()
7039
7756
  ? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
7040
- : "";
7041
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
7042
- gridRow, children: [jsxRuntime.jsx(react.Text, { children: displayedTime }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
7757
+ : '';
7758
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7759
+ gridRow, children: [jsxRuntime.jsx(react.Text, { children: displayedTime }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
7043
7760
  };
7044
7761
 
7045
7762
  const DateTimeViewer = ({ column, schema, prefix }) => {
7046
7763
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
7047
- const { translate, timezone } = useSchemaContext();
7048
- const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
7764
+ const { timezone } = useSchemaContext();
7765
+ const { required, gridColumn = 'span 4', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD HH:mm:ss', } = schema;
7049
7766
  const isRequired = required?.some((columnId) => columnId === column);
7050
7767
  const colLabel = `${prefix}${column}`;
7051
7768
  const selectedDate = watch(colLabel);
7052
- const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
7053
- return (jsxRuntime.jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
7054
- gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
7769
+ const formI18n = useFormI18n$1(column, prefix, schema);
7770
+ const displayDate = dayjs(selectedDate)
7771
+ .tz(timezone)
7772
+ .format(displayDateFormat);
7773
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7774
+ gridRow, children: [jsxRuntime.jsxs(react.Text, { children: [" ", selectedDate !== undefined ? displayDate : ''] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
7055
7775
  };
7056
7776
 
7057
7777
  const SchemaViewer = ({ schema, prefix, column, }) => {
@@ -7092,7 +7812,7 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
7092
7812
  if (innerProperties) {
7093
7813
  return jsxRuntime.jsx(ObjectViewer, { schema: colSchema, prefix, column });
7094
7814
  }
7095
- return jsxRuntime.jsx(RecordInput, { schema: colSchema, prefix, column });
7815
+ return jsxRuntime.jsx(RecordViewer, { schema: colSchema, prefix, column });
7096
7816
  }
7097
7817
  if (type === 'array') {
7098
7818
  if (variant === 'id-picker') {
@@ -7140,7 +7860,7 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
7140
7860
  };
7141
7861
 
7142
7862
  const SubmitButton = () => {
7143
- const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, requireConfirmation, onFormSubmit, } = useSchemaContext();
7863
+ const { translate, setValidatedData, setIsError, setIsConfirming, requireConfirmation, onFormSubmit, formButtonLabels, } = useSchemaContext();
7144
7864
  const methods = reactHookForm.useFormContext();
7145
7865
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7146
7866
  const onValid = (data) => {
@@ -7169,11 +7889,11 @@ const SubmitButton = () => {
7169
7889
  };
7170
7890
  return (jsxRuntime.jsx(react.Button, { onClick: () => {
7171
7891
  methods.handleSubmit(onValid)();
7172
- }, formNoValidate: true, children: translate.t('submit') }));
7892
+ }, formNoValidate: true, children: formButtonLabels?.submit ?? translate.t('submit') }));
7173
7893
  };
7174
7894
 
7175
7895
  const FormBody = () => {
7176
- const { schema, order, ignore, include, translate, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, onFormSubmit, } = useSchemaContext();
7896
+ const { schema, order, ignore, include, translate, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, getUpdatedData, customErrorRenderer, customSuccessRenderer, displayConfig, onFormSubmit, formButtonLabels, } = useSchemaContext();
7177
7897
  const { showSubmitButton, showResetButton } = displayConfig;
7178
7898
  const methods = reactHookForm.useFormContext();
7179
7899
  const { properties } = schema;
@@ -7203,7 +7923,7 @@ const FormBody = () => {
7203
7923
  if (customSuccessRenderer) {
7204
7924
  return customSuccessRenderer(resetHandler);
7205
7925
  }
7206
- return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t('submit_success') }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: 'end', children: jsxRuntime.jsx(react.Button, { onClick: resetHandler, formNoValidate: true, children: translate.t('submit_again') }) })] }));
7926
+ return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsxs(react.Alert.Root, { status: "success", children: [jsxRuntime.jsx(react.Alert.Indicator, {}), jsxRuntime.jsx(react.Alert.Content, { children: jsxRuntime.jsx(react.Alert.Title, { children: translate.t('submit_success') }) })] }), jsxRuntime.jsx(react.Flex, { justifyContent: 'end', children: jsxRuntime.jsx(react.Button, { onClick: resetHandler, formNoValidate: true, children: formButtonLabels?.submitAgain ?? translate.t('submit_again') }) })] }));
7207
7927
  }
7208
7928
  if (isConfirming) {
7209
7929
  return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: 4, gridTemplateColumns: 'repeat(12, 1fr)', gridTemplateRows: 'repeat(12, max-content)', autoFlow: 'row', children: ordered.map((column) => {
@@ -7214,9 +7934,9 @@ const FormBody = () => {
7214
7934
  properties: properties, prefix: ``, column }, `form-viewer-${column}`));
7215
7935
  }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: '2', children: [jsxRuntime.jsx(react.Button, { onClick: () => {
7216
7936
  setIsConfirming(false);
7217
- }, variant: 'subtle', children: translate.t('cancel') }), jsxRuntime.jsx(react.Button, { onClick: () => {
7937
+ }, variant: 'subtle', children: formButtonLabels?.cancel ?? translate.t('cancel') }), jsxRuntime.jsx(react.Button, { onClick: () => {
7218
7938
  onFormSubmit(validatedData);
7219
- }, children: translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
7939
+ }, children: formButtonLabels?.confirm ?? translate.t('confirm') })] }), isSubmiting && (jsxRuntime.jsx(react.Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsxRuntime.jsx(react.Center, { h: "full", children: jsxRuntime.jsx(react.Spinner, { color: "teal.500" }) }) })), isError && customErrorRenderer && customErrorRenderer(error)] }));
7220
7940
  }
7221
7941
  return (jsxRuntime.jsxs(react.Flex, { flexFlow: 'column', gap: "2", children: [jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns: 'repeat(12, 1fr)', autoFlow: 'row', children: ordered.map((column) => {
7222
7942
  return (jsxRuntime.jsx(ColumnRenderer
@@ -7226,7 +7946,7 @@ const FormBody = () => {
7226
7946
  properties: properties, prefix: ``, parentRequired: schema.required, column }, `form-input-${column}`));
7227
7947
  }) }), jsxRuntime.jsxs(react.Flex, { justifyContent: 'end', gap: "2", children: [showResetButton && (jsxRuntime.jsx(react.Button, { onClick: () => {
7228
7948
  methods.reset();
7229
- }, variant: 'subtle', children: translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
7949
+ }, variant: 'subtle', children: formButtonLabels?.reset ?? translate.t('reset') })), showSubmitButton && jsxRuntime.jsx(SubmitButton, {})] }), isError && customErrorRenderer && customErrorRenderer(error)] }));
7230
7950
  };
7231
7951
 
7232
7952
  const FormTitle = () => {
@@ -7545,7 +8265,6 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
7545
8265
  return `minmax(${size}px, ${(size / totalWidths) * 100}%)`;
7546
8266
  })
7547
8267
  .join(' ');
7548
- console.log({ columnWidths }, 'hadfg');
7549
8268
  const cellProps = {
7550
8269
  flex: '1 0 0%',
7551
8270
  overflow: 'auto',
@@ -7562,22 +8281,22 @@ const TableDataDisplay = ({ colorPalette, emptyComponent, }) => {
7562
8281
  }
7563
8282
  return (jsxRuntime.jsxs(react.Grid, { templateColumns: `${columnWidths}`, overflow: 'auto', borderWidth: '1px', color: { base: 'colorPalette.900', _dark: 'colorPalette.100' }, borderColor: { base: 'colorPalette.200', _dark: 'colorPalette.800' }, colorPalette, children: [jsxRuntime.jsx(react.Grid, { templateColumns: `${columnWidths}`, column: `1/span ${columns.length}`, bg: { base: 'colorPalette.200', _dark: 'colorPalette.800' }, colorPalette, children: columnHeaders.map((header) => {
7564
8283
  const columnDef = columnsMap[header];
7565
- return (jsxRuntime.jsx(react.Box, { flex: '1 0 0%', paddingX: '2', py: '1', overflow: 'auto', textOverflow: 'ellipsis', children: columnDef?.meta?.displayName ?? header }));
7566
- }) }), data.map((record) => {
7567
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: columnHeaders.map((header) => {
8284
+ return (jsxRuntime.jsx(react.Box, { flex: '1 0 0%', paddingX: '2', py: '1', overflow: 'auto', textOverflow: 'ellipsis', children: columnDef?.meta?.displayName ?? header }, `chakra-table-header-${header}`));
8285
+ }) }), data.map((record, recordIndex) => {
8286
+ return (jsxRuntime.jsx(react.Box, { display: "contents", children: columnHeaders.map((header) => {
7568
8287
  const { cell } = columnsMap[header];
7569
8288
  const value = record[header];
7570
8289
  if (!!record === false) {
7571
- return (jsxRuntime.jsx(react.Box, { ...cellProps }));
8290
+ return (jsxRuntime.jsx(react.Box, { ...cellProps }, `chakra-table-cell-${recordIndex}-${header}`));
7572
8291
  }
7573
8292
  if (cell) {
7574
- return (jsxRuntime.jsx(react.Box, { ...cellProps, children: cell({ row: { original: record } }) }));
8293
+ return (jsxRuntime.jsx(react.Box, { ...cellProps, children: cell({ row: { original: record } }) }, `chakra-table-cell-${recordIndex}-${header}`));
7575
8294
  }
7576
8295
  if (typeof value === 'object') {
7577
- return (jsxRuntime.jsx(react.Box, { ...cellProps, children: jsxRuntime.jsx(RecordDisplay, { object: value }) }));
8296
+ return (jsxRuntime.jsx(react.Box, { ...cellProps, children: jsxRuntime.jsx(RecordDisplay, { object: value }) }, `chakra-table-cell-${recordIndex}-${header}`));
7578
8297
  }
7579
- return jsxRuntime.jsx(react.Box, { ...cellProps, children: value });
7580
- }) }));
8298
+ return (jsxRuntime.jsx(react.Box, { ...cellProps, children: value }, `chakra-table-cell-${recordIndex}-${header}`));
8299
+ }) }, `chakra-table-record-${recordIndex}`));
7581
8300
  })] }));
7582
8301
  };
7583
8302
 
@@ -7730,19 +8449,19 @@ const DataDisplay = ({ variant = '' }) => {
7730
8449
  return cell.id === `${rowId}_${column.id}`;
7731
8450
  });
7732
8451
  if (column.columns.length > 0) {
7733
- return (jsxRuntime.jsxs(react.Card.Root, { margin: '1', gridColumn: 'span 12', children: [jsxRuntime.jsx(react.Card.Header, { color: 'gray.400', children: column.columnDef.meta?.displayName ?? column.id }), jsxRuntime.jsx(react.Card.Body, { display: 'grid', gap: '4', gridTemplateColumns: 'repeat(12, 1fr)', children: column.columns.map((column) => {
7734
- if (!column.getIsVisible()) {
7735
- return jsxRuntime.jsx(jsxRuntime.Fragment, {});
8452
+ return (jsxRuntime.jsxs(react.Card.Root, { margin: '1', gridColumn: 'span 12', children: [jsxRuntime.jsx(react.Card.Header, { color: 'gray.400', children: column.columnDef.meta?.displayName ?? column.id }), jsxRuntime.jsx(react.Card.Body, { display: 'grid', gap: '4', gridTemplateColumns: 'repeat(12, 1fr)', children: column.columns.map((subColumn) => {
8453
+ if (!subColumn.getIsVisible()) {
8454
+ return null;
7736
8455
  }
7737
8456
  const foundCell = row
7738
8457
  .getVisibleCells()
7739
8458
  .find((cell) => {
7740
- return cell.id === `${rowId}_${column.id}`;
8459
+ return cell.id === `${rowId}_${subColumn.id}`;
7741
8460
  });
7742
- return jsxRuntime.jsx(CellRenderer, { cell: foundCell });
7743
- }) })] }, `chakra-table-card-${childCell?.id}`));
8461
+ return (jsxRuntime.jsx(CellRenderer, { cell: foundCell }, `chakra-table-cell-${rowId}-${subColumn.id}`));
8462
+ }) })] }, `chakra-table-card-${rowId}-${column.id}`));
7744
8463
  }
7745
- return jsxRuntime.jsx(CellRenderer, { cell: childCell });
8464
+ return (jsxRuntime.jsx(CellRenderer, { cell: childCell }, `chakra-table-cell-${rowId}-${column.id}`));
7746
8465
  }) }) }, `chakra-table-card-${rowId}`));
7747
8466
  }) }));
7748
8467
  };
@@ -8041,6 +8760,7 @@ exports.CardHeader = CardHeader;
8041
8760
  exports.DataDisplay = DataDisplay;
8042
8761
  exports.DataTable = DataTable;
8043
8762
  exports.DataTableServer = DataTableServer;
8763
+ exports.DatePickerInput = DatePickerInput;
8044
8764
  exports.DefaultCardTitle = DefaultCardTitle;
8045
8765
  exports.DefaultForm = DefaultForm;
8046
8766
  exports.DefaultTable = DefaultTable;
@@ -8086,6 +8806,7 @@ exports.buildFieldErrors = buildFieldErrors;
8086
8806
  exports.buildRequiredErrors = buildRequiredErrors;
8087
8807
  exports.convertToAjvErrorsFormat = convertToAjvErrorsFormat;
8088
8808
  exports.createErrorMessage = createErrorMessage;
8809
+ exports.defaultRenderDisplay = defaultRenderDisplay;
8089
8810
  exports.getColumns = getColumns;
8090
8811
  exports.getMultiDates = getMultiDates;
8091
8812
  exports.getRangeDates = getRangeDates;