@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.
- package/dist/index.d.ts +38 -7
- package/dist/index.js +1242 -521
- package/dist/index.mjs +1244 -525
- package/dist/types/components/DataTable/display/RecordDisplay.d.ts +2 -2
- package/dist/types/components/DataTable/display/TextCell.d.ts +11 -4
- package/dist/types/components/DataTable/display/TextWithCopy.d.ts +8 -0
- package/dist/types/components/DatePicker/DatePickerInput.d.ts +18 -0
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +4 -1
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +2 -1
- package/dist/types/components/DatePicker/index.d.ts +2 -1
- package/dist/types/components/Form/SchemaFormContext.d.ts +2 -1
- package/dist/types/components/Form/components/core/FormRoot.d.ts +3 -4
- package/dist/types/components/Form/components/fields/ArrayRenderer.d.ts +1 -1
- package/dist/types/components/Form/components/fields/StringInputField.d.ts +0 -1
- package/dist/types/components/Form/components/fields/TextAreaInput.d.ts +0 -5
- package/dist/types/components/Form/components/types/CustomJSONSchema7.d.ts +8 -0
- package/dist/types/components/Form/components/viewers/ArrayViewer.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/BooleanViewer.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/DateViewer.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/IdViewer.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/ObjectViewer.d.ts +1 -1
- package/dist/types/components/Form/components/viewers/RecordViewer.d.ts +2 -2
- package/dist/types/components/Form/components/viewers/StringViewer.d.ts +1 -6
- package/dist/types/components/Form/components/viewers/TextAreaViewer.d.ts +1 -6
- package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +1 -1
- package/dist/types/components/Form/utils/useFormI18n.d.ts +5 -3
- package/dist/types/components/TimePicker/TimePicker.d.ts +2 -1
- package/dist/types/components/ui/pagination.d.ts +10 -7
- package/dist/types/index.d.ts +1 -0
- 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:
|
|
565
|
+
name: 'RootPropsProvider',
|
|
565
566
|
});
|
|
566
567
|
const variantMap = {
|
|
567
|
-
outline: { default:
|
|
568
|
-
solid: { default:
|
|
569
|
-
subtle: { default:
|
|
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 =
|
|
573
|
-
|
|
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 ===
|
|
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 =
|
|
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 ===
|
|
710
|
+
if (format === 'short')
|
|
615
711
|
return `${page} / ${totalPages}`;
|
|
616
|
-
if (format ===
|
|
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, {
|
|
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(
|
|
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()) }))] }
|
|
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.
|
|
3143
|
-
|
|
3144
|
-
|
|
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
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
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
|
-
|
|
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:
|
|
3516
|
-
|
|
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
|
|
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 =
|
|
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:
|
|
3931
|
-
base:
|
|
3932
|
-
_dark:
|
|
3933
|
-
}, children: [jsxRuntime.jsx(react.Grid, { gridTemplateColumns:
|
|
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:
|
|
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 ===
|
|
4232
|
+
if (type === 'number') {
|
|
3942
4233
|
setValue(colLabel, [...fields, 0]);
|
|
3943
4234
|
return;
|
|
3944
4235
|
}
|
|
3945
|
-
if (type ===
|
|
3946
|
-
setValue(colLabel, [...fields,
|
|
4236
|
+
if (type === 'string') {
|
|
4237
|
+
setValue(colLabel, [...fields, '']);
|
|
3947
4238
|
return;
|
|
3948
4239
|
}
|
|
3949
|
-
if (type ===
|
|
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:
|
|
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
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
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,
|
|
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
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
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:
|
|
5606
|
+
}, children: renderDisplay
|
|
5373
5607
|
? renderDisplay(item)
|
|
5374
|
-
: item
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
?
|
|
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: [
|
|
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:
|
|
5735
|
+
}) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
5498
5736
|
};
|
|
5499
5737
|
|
|
5500
|
-
const RecordInput
|
|
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
|
-
|
|
5510
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
?
|
|
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
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
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
|
|
5812
|
-
let
|
|
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
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
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
|
-
//
|
|
5877
|
-
const
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
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
|
|
5893
|
-
|
|
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
|
-
.
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
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
|
|
5922
|
-
}, [hour, minute, meridiem,
|
|
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
|
-
//
|
|
5956
|
-
const
|
|
5957
|
-
|
|
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(
|
|
5984
|
-
if (!
|
|
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 =
|
|
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
|
-
|
|
6203
|
+
if (parsedMinute < 0 || parsedMinute > 59) {
|
|
6204
|
+
// Parse failed, select first result
|
|
6205
|
+
selectFirstResult();
|
|
6206
|
+
return;
|
|
6207
|
+
}
|
|
6004
6208
|
setHour(parsedHour);
|
|
6005
|
-
setMinute(
|
|
6209
|
+
setMinute(parsedMinute);
|
|
6006
6210
|
setMeridiem(parsedMeridiem);
|
|
6007
6211
|
onChange({
|
|
6008
6212
|
hour: parsedHour,
|
|
6009
|
-
minute:
|
|
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(
|
|
6255
|
+
setMinute(parsedMinute);
|
|
6046
6256
|
setMeridiem(parsedMeridiem);
|
|
6047
6257
|
onChange({
|
|
6048
6258
|
hour: parsedHour,
|
|
6049
|
-
minute:
|
|
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.
|
|
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 {
|
|
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:
|
|
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
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
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
|
|
6176
|
-
let
|
|
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
|
-
|
|
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
|
-
//
|
|
6232
|
-
const
|
|
6233
|
-
if (
|
|
6234
|
-
|
|
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
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
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
|
|
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
|
-
|
|
6299
|
-
|
|
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(
|
|
6302
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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.
|
|
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
|
-
|
|
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(
|
|
6382
|
-
const [minute, setMinute] = React.useState(
|
|
6383
|
-
const [meridiem, setMeridiem] = React.useState(
|
|
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(
|
|
6386
|
-
const [second, setSecond] = React.useState(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6441
|
-
|
|
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
|
|
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
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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, {}),
|
|
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
|
|
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 =
|
|
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:
|
|
6714
|
-
base:
|
|
6715
|
-
_dark:
|
|
6716
|
-
}, children: jsxRuntime.jsx(react.Grid, { gap: "4", gridTemplateColumns:
|
|
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:
|
|
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 {
|
|
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
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
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 {
|
|
6750
|
-
const { required, gridColumn =
|
|
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
|
|
6755
|
-
|
|
6756
|
-
|
|
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 {
|
|
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
|
|
6787
|
-
return (jsxRuntime.jsx(Field, { label:
|
|
6788
|
-
return (jsxRuntime.jsx(react.Card.Root, { variant:
|
|
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 =
|
|
7549
|
+
const { required, gridColumn = 'span 12', gridRow = 'span 1', renderDisplay, foreign_key, } = schema;
|
|
6796
7550
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
6797
|
-
const
|
|
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
|
-
|
|
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:
|
|
6812
|
-
gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow:
|
|
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:
|
|
7574
|
+
return (jsxRuntime.jsx(Tag, { closable: true, children: renderDisplay
|
|
6818
7575
|
? renderDisplay(item)
|
|
6819
|
-
: item
|
|
6820
|
-
}) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: getPickedValue() }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color:
|
|
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:
|
|
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 =
|
|
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: [
|
|
6861
|
-
base:
|
|
6862
|
-
_dark:
|
|
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:
|
|
7626
|
+
}) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
|
|
6870
7627
|
};
|
|
6871
7628
|
|
|
6872
|
-
const
|
|
6873
|
-
const { formState: { errors },
|
|
6874
|
-
const {
|
|
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
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
7032
|
-
const { required, gridColumn =
|
|
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:
|
|
7042
|
-
gridRow, children: [jsxRuntime.jsx(react.Text, { children: displayedTime }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color:
|
|
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 {
|
|
7048
|
-
const { required, gridColumn =
|
|
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
|
|
7053
|
-
|
|
7054
|
-
|
|
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(
|
|
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,
|
|
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(
|
|
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((
|
|
7734
|
-
if (!
|
|
7735
|
-
return
|
|
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}_${
|
|
8459
|
+
return cell.id === `${rowId}_${subColumn.id}`;
|
|
7741
8460
|
});
|
|
7742
|
-
return jsxRuntime.jsx(CellRenderer, { cell: foundCell });
|
|
7743
|
-
}) })] }, `chakra-table-card-${
|
|
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;
|