@bsol-oss/react-datatable5 12.0.0-beta.90 → 12.0.0-beta.91
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 +28 -3
- package/dist/index.js +886 -237
- package/dist/index.mjs +889 -241
- 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/TimePicker/TimePicker.d.ts +2 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading } from '@chakra-ui/react';
|
|
2
|
+
import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, CheckboxCard as CheckboxCard$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, Tooltip as Tooltip$1, Group, InputElement, Icon, EmptyState as EmptyState$2, VStack, List, Table as Table$1, Checkbox as Checkbox$1, Card, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Clipboard, Badge, Link, Tag as Tag$1, Image, Alert, Field as Field$1, Popover, useFilter, useListCollection, Combobox, Tabs, Skeleton, NumberInput, Show, RadioCard, CheckboxGroup, InputGroup as InputGroup$1, Center, Heading } from '@chakra-ui/react';
|
|
3
3
|
import { AiOutlineColumnWidth } from 'react-icons/ai';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import React__default, { createContext, useContext, useState, useEffect, useRef, useMemo, forwardRef } from 'react';
|
|
6
|
-
import { LuX, LuCheck, LuChevronRight, LuSearch, LuImage, LuFile } from 'react-icons/lu';
|
|
5
|
+
import React__default, { createContext, useContext, useState, useEffect, useRef, useMemo, forwardRef, useCallback } from 'react';
|
|
6
|
+
import { LuX, LuCheck, LuChevronRight, LuCopy, LuExternalLink, LuSearch, LuImage, LuFile } from 'react-icons/lu';
|
|
7
7
|
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineChecklist, MdClear, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdDateRange } from 'react-icons/md';
|
|
8
8
|
import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
|
|
9
9
|
import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
|
|
@@ -33,6 +33,7 @@ import dayjs from 'dayjs';
|
|
|
33
33
|
import utc from 'dayjs/plugin/utc';
|
|
34
34
|
import timezone from 'dayjs/plugin/timezone';
|
|
35
35
|
import { TiDeleteOutline } from 'react-icons/ti';
|
|
36
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
36
37
|
import { rankItem } from '@tanstack/match-sorter-utils';
|
|
37
38
|
|
|
38
39
|
const DataTableContext = createContext({
|
|
@@ -3315,11 +3316,136 @@ const TableLoadingComponent = ({ render, }) => {
|
|
|
3315
3316
|
return jsx(Fragment, { children: render(query.isLoading) });
|
|
3316
3317
|
};
|
|
3317
3318
|
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3319
|
+
// Helper function to highlight matching text
|
|
3320
|
+
const highlightText$1 = (text, searchTerm) => {
|
|
3321
|
+
if (!searchTerm || searchTerm.trim() === '') {
|
|
3322
|
+
return String(text);
|
|
3323
|
+
}
|
|
3324
|
+
const textStr = String(text);
|
|
3325
|
+
const searchLower = searchTerm.toLowerCase();
|
|
3326
|
+
const textLower = textStr.toLowerCase();
|
|
3327
|
+
const parts = [];
|
|
3328
|
+
let lastIndex = 0;
|
|
3329
|
+
let index = textLower.indexOf(searchLower, lastIndex);
|
|
3330
|
+
while (index !== -1) {
|
|
3331
|
+
// Add text before match
|
|
3332
|
+
if (index > lastIndex) {
|
|
3333
|
+
parts.push(textStr.substring(lastIndex, index));
|
|
3334
|
+
}
|
|
3335
|
+
// Add highlighted match
|
|
3336
|
+
parts.push(jsx(Text, { as: "mark", bg: {
|
|
3337
|
+
base: 'yellow.200',
|
|
3338
|
+
_dark: 'yellow.800',
|
|
3339
|
+
}, color: {
|
|
3340
|
+
base: 'gray.900',
|
|
3341
|
+
_dark: 'gray.100',
|
|
3342
|
+
}, px: 0.5, borderRadius: "sm", children: textStr.substring(index, index + searchTerm.length) }, index));
|
|
3343
|
+
lastIndex = index + searchTerm.length;
|
|
3344
|
+
index = textLower.indexOf(searchLower, lastIndex);
|
|
3345
|
+
}
|
|
3346
|
+
// Add remaining text
|
|
3347
|
+
if (lastIndex < textStr.length) {
|
|
3348
|
+
parts.push(textStr.substring(lastIndex));
|
|
3349
|
+
}
|
|
3350
|
+
return parts.length > 0 ? jsx(Fragment, { children: parts }) : textStr;
|
|
3351
|
+
};
|
|
3352
|
+
const TextWithCopy = ({ text, globalFilter, highlightedText, }) => {
|
|
3353
|
+
const textValue = String(text ?? '');
|
|
3354
|
+
const displayText = highlightedText !== undefined
|
|
3355
|
+
? highlightedText
|
|
3356
|
+
: highlightText$1(textValue, globalFilter);
|
|
3357
|
+
return (jsxs(HStack, { gap: 2, alignItems: "center", children: [jsx(Text, { as: "span", children: displayText }), jsx(Clipboard.Root, { value: textValue, children: jsx(Clipboard.Trigger, { asChild: true, children: jsx(IconButton, { size: "xs", variant: "ghost", "aria-label": "Copy", children: jsx(Clipboard.Indicator, { copied: jsx(LuCheck, {}), children: jsx(LuCopy, {}) }) }) }) })] }));
|
|
3358
|
+
};
|
|
3359
|
+
|
|
3360
|
+
// Helper function to highlight matching text
|
|
3361
|
+
const highlightText = (text, searchTerm) => {
|
|
3362
|
+
if (!searchTerm || searchTerm.trim() === '') {
|
|
3363
|
+
return String(text);
|
|
3364
|
+
}
|
|
3365
|
+
const textStr = String(text);
|
|
3366
|
+
const searchLower = searchTerm.toLowerCase();
|
|
3367
|
+
const textLower = textStr.toLowerCase();
|
|
3368
|
+
const parts = [];
|
|
3369
|
+
let lastIndex = 0;
|
|
3370
|
+
let index = textLower.indexOf(searchLower, lastIndex);
|
|
3371
|
+
while (index !== -1) {
|
|
3372
|
+
// Add text before match
|
|
3373
|
+
if (index > lastIndex) {
|
|
3374
|
+
parts.push(textStr.substring(lastIndex, index));
|
|
3375
|
+
}
|
|
3376
|
+
// Add highlighted match
|
|
3377
|
+
parts.push(jsx(Text, { as: "mark", bg: {
|
|
3378
|
+
base: 'yellow.200',
|
|
3379
|
+
_dark: 'yellow.800',
|
|
3380
|
+
}, color: {
|
|
3381
|
+
base: 'gray.900',
|
|
3382
|
+
_dark: 'gray.100',
|
|
3383
|
+
}, px: 0.5, borderRadius: "sm", children: textStr.substring(index, index + searchTerm.length) }, index));
|
|
3384
|
+
lastIndex = index + searchTerm.length;
|
|
3385
|
+
index = textLower.indexOf(searchLower, lastIndex);
|
|
3386
|
+
}
|
|
3387
|
+
// Add remaining text
|
|
3388
|
+
if (lastIndex < textStr.length) {
|
|
3389
|
+
parts.push(textStr.substring(lastIndex));
|
|
3390
|
+
}
|
|
3391
|
+
return parts.length > 0 ? jsx(Fragment, { children: parts }) : textStr;
|
|
3392
|
+
};
|
|
3393
|
+
const RenderValue = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette, globalFilter, }) => {
|
|
3394
|
+
const highlightedText = useMemo(() => highlightText(text ?? '', globalFilter), [text, globalFilter]);
|
|
3395
|
+
if (isBadge) {
|
|
3396
|
+
return (jsx(Badge, { colorPalette: colorPalette || badgeColor, children: highlightedText }));
|
|
3397
|
+
}
|
|
3398
|
+
// onClick takes precedence over href
|
|
3399
|
+
if (onClick) {
|
|
3400
|
+
return (jsx(Box, { as: "button", onClick: onClick, cursor: "pointer", textAlign: "left", _hover: {
|
|
3401
|
+
textDecoration: 'underline',
|
|
3402
|
+
color: {
|
|
3403
|
+
base: 'blue.500',
|
|
3404
|
+
_dark: 'blue.400',
|
|
3405
|
+
},
|
|
3406
|
+
}, transition: "all 0.2s", children: highlightedText }));
|
|
3321
3407
|
}
|
|
3322
|
-
|
|
3408
|
+
if (href) {
|
|
3409
|
+
return (jsxs(Link, { href: href, target: "_blank", rel: "noopener noreferrer", _hover: {
|
|
3410
|
+
textDecoration: 'underline',
|
|
3411
|
+
}, children: [highlightedText, " ", jsx(Icon, { as: LuExternalLink })] }));
|
|
3412
|
+
}
|
|
3413
|
+
if (isCopyable) {
|
|
3414
|
+
return (jsx(TextWithCopy, { text: text, globalFilter: globalFilter, highlightedText: highlightedText }));
|
|
3415
|
+
}
|
|
3416
|
+
return jsx(Fragment, { children: highlightedText });
|
|
3417
|
+
};
|
|
3418
|
+
const TextCell = ({ text, href, onClick, isCopyable, isBadge, badgeColor, colorPalette,
|
|
3419
|
+
// Legacy props
|
|
3420
|
+
label, containerProps = {}, textProps = {}, children, }) => {
|
|
3421
|
+
// Get globalFilter from context
|
|
3422
|
+
// If not in DataTable context, will use default empty string from context
|
|
3423
|
+
const { globalFilter } = useDataTableContext();
|
|
3424
|
+
// Legacy API: if children is provided, use old behavior
|
|
3425
|
+
if (children !== undefined) {
|
|
3426
|
+
const displayText = typeof children === 'string' || typeof children === 'number'
|
|
3427
|
+
? String(children)
|
|
3428
|
+
: children;
|
|
3429
|
+
const highlightedDisplayText = typeof displayText === 'string' || typeof displayText === 'number'
|
|
3430
|
+
? highlightText(displayText, globalFilter)
|
|
3431
|
+
: displayText;
|
|
3432
|
+
if (label) {
|
|
3433
|
+
return (jsx(Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsx(Tooltip, { content: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', children: label }), children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }) }));
|
|
3434
|
+
}
|
|
3435
|
+
return (jsx(Flex, { alignItems: 'center', height: '100%', ...containerProps, children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: 'ellipsis', wordBreak: 'break-all', ...textProps, children: highlightedDisplayText }) }));
|
|
3436
|
+
}
|
|
3437
|
+
// New API: use text prop
|
|
3438
|
+
const displayValue = text ?? children;
|
|
3439
|
+
if (Array.isArray(displayValue)) {
|
|
3440
|
+
return (jsx(Flex, { gap: 2, flexWrap: "wrap", children: displayValue.map((item, index) => {
|
|
3441
|
+
const highlightedItem = highlightText(item, globalFilter);
|
|
3442
|
+
return (jsx(Badge, { colorPalette: colorPalette || badgeColor, children: highlightedItem }, index));
|
|
3443
|
+
}) }));
|
|
3444
|
+
}
|
|
3445
|
+
if (!!displayValue === false) {
|
|
3446
|
+
return (jsx(Text, { textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", wordBreak: "break-all", display: "flex", alignItems: "center", height: "100%", children: "-" }));
|
|
3447
|
+
}
|
|
3448
|
+
return (jsx(Box, { textOverflow: "ellipsis", whiteSpace: "nowrap", wordBreak: "break-all", overflow: "auto", display: "flex", alignItems: "center", height: "100%", children: jsx(RenderValue, { text: displayValue, href: href, onClick: onClick, isCopyable: isCopyable, isBadge: isBadge, badgeColor: badgeColor, colorPalette: colorPalette, globalFilter: globalFilter }) }));
|
|
3323
3449
|
};
|
|
3324
3450
|
|
|
3325
3451
|
const Tag = React.forwardRef(function Tag(props, ref) {
|
|
@@ -5295,15 +5421,15 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5295
5421
|
// Check if we're currently searching (user typed but debounce hasn't fired yet)
|
|
5296
5422
|
const isSearching = searchText !== debouncedSearchText;
|
|
5297
5423
|
// Transform data for combobox collection
|
|
5424
|
+
// label is used for filtering/searching (must be a string)
|
|
5425
|
+
// raw item is stored for custom rendering
|
|
5298
5426
|
const comboboxItems = useMemo(() => {
|
|
5299
5427
|
return dataList.map((item) => ({
|
|
5300
|
-
label:
|
|
5301
|
-
? String(renderDisplay(item))
|
|
5302
|
-
: String(item[display_column] ?? ''),
|
|
5428
|
+
label: String(item[display_column] ?? ''), // Always use display_column for filtering
|
|
5303
5429
|
value: String(item[column_ref]),
|
|
5304
5430
|
raw: item,
|
|
5305
5431
|
}));
|
|
5306
|
-
}, [dataList, display_column, column_ref
|
|
5432
|
+
}, [dataList, display_column, column_ref]);
|
|
5307
5433
|
// Use filter hook for combobox
|
|
5308
5434
|
const { contains } = useFilter({ sensitivity: 'base' });
|
|
5309
5435
|
// Create collection for combobox
|
|
@@ -5362,13 +5488,17 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
5362
5488
|
? idPickerLabels?.emptySearchResult ??
|
|
5363
5489
|
formI18n.t('empty_search_result')
|
|
5364
5490
|
: idPickerLabels?.initialResults ??
|
|
5365
|
-
formI18n.t('initial_results') })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children:
|
|
5491
|
+
formI18n.t('initial_results') })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplay === true
|
|
5492
|
+
? renderDisplay(item.raw)
|
|
5493
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) })) : (jsx(Portal, { children: jsx(Combobox.Positioner, { children: jsx(Combobox.Content, { children: isError ? (jsx(Text, { p: 2, color: "fg.error", fontSize: "sm", children: formI18n.t('loading_failed') })) : isFetching || isLoading || isPending || isSearching ? (
|
|
5366
5494
|
// Show skeleton items to prevent UI shift
|
|
5367
5495
|
jsx(Fragment, { children: Array.from({ length: 5 }).map((_, index) => (jsx(Flex, { p: 2, align: "center", gap: 2, children: jsx(Skeleton, { height: "20px", flex: "1" }) }, `skeleton-${index}`))) })) : collection.items.length === 0 ? (jsx(Combobox.Empty, { children: searchText
|
|
5368
5496
|
? idPickerLabels?.emptySearchResult ??
|
|
5369
5497
|
formI18n.t('empty_search_result')
|
|
5370
5498
|
: idPickerLabels?.initialResults ??
|
|
5371
|
-
formI18n.t('initial_results') })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children:
|
|
5499
|
+
formI18n.t('initial_results') })) : (jsx(Fragment, { children: collection.items.map((item, index) => (jsxs(Combobox.Item, { item: item, children: [jsx(Combobox.ItemText, { children: !!renderDisplay === true
|
|
5500
|
+
? renderDisplay(item.raw)
|
|
5501
|
+
: item.label }), jsx(Combobox.ItemIndicator, {})] }, item.value ?? `item-${index}`))) })) }) }) }))] })] }));
|
|
5372
5502
|
};
|
|
5373
5503
|
|
|
5374
5504
|
const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
|
|
@@ -5747,7 +5877,7 @@ meridiemLabel: _meridiemLabel = {
|
|
|
5747
5877
|
pm: 'pm',
|
|
5748
5878
|
},
|
|
5749
5879
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5750
|
-
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, }) {
|
|
5880
|
+
onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedDate, portalled = true, }) {
|
|
5751
5881
|
// Generate time options (every 15 minutes)
|
|
5752
5882
|
const timeOptions = useMemo(() => {
|
|
5753
5883
|
const options = [];
|
|
@@ -5770,12 +5900,10 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5770
5900
|
for (let h = 1; h <= 12; h++) {
|
|
5771
5901
|
for (let m = 0; m < 60; m += 15) {
|
|
5772
5902
|
const hour24 = mer === 'am' ? (h === 12 ? 0 : h) : h === 12 ? 12 : h + 12;
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
.format('HH:mmZ');
|
|
5778
|
-
const displayTime = dayjs(`1970-01-01T${timeStr}`, 'HH:mmZ').format('hh:mm a');
|
|
5903
|
+
// Format time directly without using dayjs with dummy dates
|
|
5904
|
+
const formattedHour = h.toString().padStart(2, '0');
|
|
5905
|
+
const formattedMinute = m.toString().padStart(2, '0');
|
|
5906
|
+
const displayTime = `${formattedHour}:${formattedMinute} ${mer}`;
|
|
5779
5907
|
// Filter out times that would result in negative duration (only when dates are the same)
|
|
5780
5908
|
if (startDateTime && selectedDate && shouldFilterByDate) {
|
|
5781
5909
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
@@ -5788,8 +5916,8 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5788
5916
|
continue; // Skip this option as it would result in negative duration
|
|
5789
5917
|
}
|
|
5790
5918
|
}
|
|
5791
|
-
// Calculate
|
|
5792
|
-
let
|
|
5919
|
+
// Calculate duration if startTime is provided
|
|
5920
|
+
let durationText;
|
|
5793
5921
|
if (startDateTime && selectedDate) {
|
|
5794
5922
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
5795
5923
|
const optionDateTime = selectedDateObj
|
|
@@ -5802,21 +5930,30 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5802
5930
|
const diffMs = optionDateTime.diff(startDateTime);
|
|
5803
5931
|
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
5804
5932
|
const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5933
|
+
const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
|
|
5934
|
+
if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
|
|
5935
|
+
let diffText = '';
|
|
5936
|
+
if (diffHours > 0) {
|
|
5937
|
+
diffText = `${diffHours}h ${diffMinutes}m`;
|
|
5938
|
+
}
|
|
5939
|
+
else if (diffMinutes > 0) {
|
|
5940
|
+
diffText = `${diffMinutes}m ${diffSeconds}s`;
|
|
5941
|
+
}
|
|
5942
|
+
else {
|
|
5943
|
+
diffText = `${diffSeconds}s`;
|
|
5944
|
+
}
|
|
5945
|
+
durationText = `+${diffText}`;
|
|
5810
5946
|
}
|
|
5811
5947
|
}
|
|
5812
5948
|
}
|
|
5813
5949
|
options.push({
|
|
5814
|
-
label,
|
|
5950
|
+
label: displayTime,
|
|
5815
5951
|
value: `${h}:${m.toString().padStart(2, '0')}:${mer}`,
|
|
5816
5952
|
hour: h,
|
|
5817
5953
|
minute: m,
|
|
5818
5954
|
meridiem: mer,
|
|
5819
5955
|
searchText: displayTime, // Use base time without duration for searching
|
|
5956
|
+
durationText,
|
|
5820
5957
|
});
|
|
5821
5958
|
}
|
|
5822
5959
|
}
|
|
@@ -5830,22 +5967,6 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5830
5967
|
itemToValue: (item) => item.value,
|
|
5831
5968
|
filter: contains,
|
|
5832
5969
|
});
|
|
5833
|
-
// Track input mode vs display mode
|
|
5834
|
-
const [isInputMode, setIsInputMode] = useState(false);
|
|
5835
|
-
const [inputValue, setInputValue] = useState('');
|
|
5836
|
-
const inputRef = useRef(null);
|
|
5837
|
-
// Switch to display mode when value is selected
|
|
5838
|
-
useEffect(() => {
|
|
5839
|
-
if (hour !== null && minute !== null && meridiem !== null) {
|
|
5840
|
-
setIsInputMode(false);
|
|
5841
|
-
}
|
|
5842
|
-
}, [hour, minute, meridiem]);
|
|
5843
|
-
// Focus input when switching to input mode
|
|
5844
|
-
useEffect(() => {
|
|
5845
|
-
if (isInputMode && inputRef.current) {
|
|
5846
|
-
inputRef.current.focus();
|
|
5847
|
-
}
|
|
5848
|
-
}, [isInputMode]);
|
|
5849
5970
|
// Get current value string for combobox
|
|
5850
5971
|
const currentValue = useMemo(() => {
|
|
5851
5972
|
if (hour === null || minute === null || meridiem === null) {
|
|
@@ -5853,14 +5974,14 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5853
5974
|
}
|
|
5854
5975
|
return `${hour}:${minute.toString().padStart(2, '0')}:${meridiem}`;
|
|
5855
5976
|
}, [hour, minute, meridiem]);
|
|
5856
|
-
//
|
|
5857
|
-
const
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
return
|
|
5977
|
+
// Calculate duration difference
|
|
5978
|
+
const durationDiff = useMemo(() => {
|
|
5979
|
+
if (!startTime ||
|
|
5980
|
+
!selectedDate ||
|
|
5981
|
+
hour === null ||
|
|
5982
|
+
minute === null ||
|
|
5983
|
+
meridiem === null) {
|
|
5984
|
+
return null;
|
|
5864
5985
|
}
|
|
5865
5986
|
const hour24 = meridiem === 'am'
|
|
5866
5987
|
? hour === 12
|
|
@@ -5869,45 +5990,42 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5869
5990
|
: hour === 12
|
|
5870
5991
|
? 12
|
|
5871
5992
|
: hour + 12;
|
|
5872
|
-
const
|
|
5873
|
-
|
|
5993
|
+
const startDateObj = dayjs(startTime).tz(timezone);
|
|
5994
|
+
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
5995
|
+
const currentDateTime = selectedDateObj
|
|
5874
5996
|
.hour(hour24)
|
|
5875
5997
|
.minute(minute)
|
|
5876
|
-
.
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
}
|
|
5998
|
+
.second(0)
|
|
5999
|
+
.millisecond(0);
|
|
6000
|
+
if (!startDateObj.isValid() || !currentDateTime.isValid()) {
|
|
6001
|
+
return null;
|
|
6002
|
+
}
|
|
6003
|
+
const diffMs = currentDateTime.diff(startDateObj);
|
|
6004
|
+
if (diffMs < 0) {
|
|
6005
|
+
return null;
|
|
6006
|
+
}
|
|
6007
|
+
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
6008
|
+
const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
6009
|
+
const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
|
|
6010
|
+
if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
|
|
6011
|
+
let diffText = '';
|
|
6012
|
+
if (diffHours > 0) {
|
|
6013
|
+
diffText = `${diffHours}h ${diffMinutes}m`;
|
|
6014
|
+
}
|
|
6015
|
+
else if (diffMinutes > 0) {
|
|
6016
|
+
diffText = `${diffMinutes}m ${diffSeconds}s`;
|
|
6017
|
+
}
|
|
6018
|
+
else {
|
|
6019
|
+
diffText = `${diffSeconds}s`;
|
|
5899
6020
|
}
|
|
6021
|
+
return `+${diffText}`;
|
|
5900
6022
|
}
|
|
5901
|
-
return
|
|
5902
|
-
}, [hour, minute, meridiem,
|
|
5903
|
-
// Choose text based on mode
|
|
5904
|
-
const displayText = isInputMode ? inputModeText : displayModeText;
|
|
6023
|
+
return null;
|
|
6024
|
+
}, [hour, minute, meridiem, startTime, selectedDate, timezone]);
|
|
5905
6025
|
const handleClear = () => {
|
|
5906
6026
|
setHour(null);
|
|
5907
6027
|
setMinute(null);
|
|
5908
6028
|
setMeridiem(null);
|
|
5909
|
-
setIsInputMode(false);
|
|
5910
|
-
setInputValue('');
|
|
5911
6029
|
filter(''); // Reset filter to show all options
|
|
5912
6030
|
onChange({ hour: null, minute: null, meridiem: null });
|
|
5913
6031
|
};
|
|
@@ -5922,8 +6040,6 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5922
6040
|
setHour(selectedOption.hour);
|
|
5923
6041
|
setMinute(selectedOption.minute);
|
|
5924
6042
|
setMeridiem(selectedOption.meridiem);
|
|
5925
|
-
setIsInputMode(false); // Switch to display mode
|
|
5926
|
-
setInputValue('');
|
|
5927
6043
|
filter(''); // Reset filter after selection
|
|
5928
6044
|
onChange({
|
|
5929
6045
|
hour: selectedOption.hour,
|
|
@@ -5932,41 +6048,16 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5932
6048
|
});
|
|
5933
6049
|
}
|
|
5934
6050
|
};
|
|
5935
|
-
//
|
|
5936
|
-
const
|
|
5937
|
-
|
|
5938
|
-
e.preventDefault();
|
|
5939
|
-
const firstOption = collection.items[0];
|
|
5940
|
-
if (firstOption) {
|
|
5941
|
-
const selectedOption = timeOptions.find((opt) => opt.value === firstOption.value);
|
|
5942
|
-
if (selectedOption) {
|
|
5943
|
-
setHour(selectedOption.hour);
|
|
5944
|
-
setMinute(selectedOption.minute);
|
|
5945
|
-
setMeridiem(selectedOption.meridiem);
|
|
5946
|
-
setIsInputMode(false); // Switch to display mode
|
|
5947
|
-
setInputValue('');
|
|
5948
|
-
filter('');
|
|
5949
|
-
onChange({
|
|
5950
|
-
hour: selectedOption.hour,
|
|
5951
|
-
minute: selectedOption.minute,
|
|
5952
|
-
meridiem: selectedOption.meridiem,
|
|
5953
|
-
});
|
|
5954
|
-
}
|
|
5955
|
-
}
|
|
5956
|
-
}
|
|
5957
|
-
};
|
|
5958
|
-
const handleInputValueChange = (details) => {
|
|
5959
|
-
const inputValue = details.inputValue.trim();
|
|
5960
|
-
setInputValue(inputValue);
|
|
5961
|
-
setIsInputMode(true); // Switch to input mode
|
|
6051
|
+
// Parse input value and update state
|
|
6052
|
+
const parseAndCommitInput = (value) => {
|
|
6053
|
+
const trimmedValue = value.trim();
|
|
5962
6054
|
// Filter the collection based on input
|
|
5963
|
-
filter(
|
|
5964
|
-
if (!
|
|
5965
|
-
setIsInputMode(false);
|
|
6055
|
+
filter(trimmedValue);
|
|
6056
|
+
if (!trimmedValue) {
|
|
5966
6057
|
return;
|
|
5967
6058
|
}
|
|
5968
6059
|
// Try to parse custom input using explicit regex patterns
|
|
5969
|
-
const normalized =
|
|
6060
|
+
const normalized = trimmedValue.toLowerCase().replace(/\s+/g, '');
|
|
5970
6061
|
// Pattern 1: 12-hour format with meridiem (e.g., "930pm", "1230am", "9:30pm", "12:30am")
|
|
5971
6062
|
// Matches: 1-2 digits hour, optional colon, 2 digits minute, am/pm
|
|
5972
6063
|
const pattern12HourWithMeridiem = /^(\d{1,2}):?(\d{2})(am|pm)$/;
|
|
@@ -5977,29 +6068,43 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
5977
6068
|
const parsedMeridiem = match12Hour[3];
|
|
5978
6069
|
// Validate hour (1-12)
|
|
5979
6070
|
if (parsedHour < 1 || parsedHour > 12) {
|
|
6071
|
+
// Parse failed, select first result
|
|
6072
|
+
selectFirstResult();
|
|
5980
6073
|
return;
|
|
5981
6074
|
}
|
|
5982
6075
|
// Validate minute (0-59)
|
|
5983
|
-
|
|
6076
|
+
if (parsedMinute < 0 || parsedMinute > 59) {
|
|
6077
|
+
// Parse failed, select first result
|
|
6078
|
+
selectFirstResult();
|
|
6079
|
+
return;
|
|
6080
|
+
}
|
|
5984
6081
|
setHour(parsedHour);
|
|
5985
|
-
setMinute(
|
|
6082
|
+
setMinute(parsedMinute);
|
|
5986
6083
|
setMeridiem(parsedMeridiem);
|
|
5987
6084
|
onChange({
|
|
5988
6085
|
hour: parsedHour,
|
|
5989
|
-
minute:
|
|
6086
|
+
minute: parsedMinute,
|
|
5990
6087
|
meridiem: parsedMeridiem,
|
|
5991
6088
|
});
|
|
5992
6089
|
return;
|
|
5993
6090
|
}
|
|
5994
6091
|
// Pattern 2: 24-hour format (e.g., "2130", "09:30", "21:30")
|
|
5995
6092
|
// Matches: 1-2 digits hour, optional colon, 2 digits minute
|
|
5996
|
-
const pattern24Hour = /^(\d{2}):?(\d{2})$/;
|
|
6093
|
+
const pattern24Hour = /^(\d{1,2}):?(\d{2})$/;
|
|
5997
6094
|
const match24Hour = normalized.match(pattern24Hour);
|
|
5998
6095
|
if (match24Hour) {
|
|
5999
6096
|
let parsedHour = parseInt(match24Hour[1], 10);
|
|
6000
6097
|
const parsedMinute = parseInt(match24Hour[2], 10);
|
|
6001
6098
|
// Validate hour (0-23)
|
|
6002
|
-
if (parsedHour > 23) {
|
|
6099
|
+
if (parsedHour < 0 || parsedHour > 23) {
|
|
6100
|
+
// Parse failed, select first result
|
|
6101
|
+
selectFirstResult();
|
|
6102
|
+
return;
|
|
6103
|
+
}
|
|
6104
|
+
// Validate minute (0-59)
|
|
6105
|
+
if (parsedMinute < 0 || parsedMinute > 59) {
|
|
6106
|
+
// Parse failed, select first result
|
|
6107
|
+
selectFirstResult();
|
|
6003
6108
|
return;
|
|
6004
6109
|
}
|
|
6005
6110
|
// Convert 24-hour to 12-hour format
|
|
@@ -6019,23 +6124,62 @@ onChange = (_newValue) => { }, timezone = 'Asia/Hong_Kong', startTime, selectedD
|
|
|
6019
6124
|
else {
|
|
6020
6125
|
parsedMeridiem = 'am';
|
|
6021
6126
|
}
|
|
6022
|
-
// Validate minute (0-59)
|
|
6023
|
-
const validMinute = parsedMinute > 59 ? 0 : parsedMinute;
|
|
6024
6127
|
setHour(parsedHour);
|
|
6025
|
-
setMinute(
|
|
6128
|
+
setMinute(parsedMinute);
|
|
6026
6129
|
setMeridiem(parsedMeridiem);
|
|
6027
6130
|
onChange({
|
|
6028
6131
|
hour: parsedHour,
|
|
6029
|
-
minute:
|
|
6132
|
+
minute: parsedMinute,
|
|
6030
6133
|
meridiem: parsedMeridiem,
|
|
6031
6134
|
});
|
|
6032
6135
|
return;
|
|
6033
6136
|
}
|
|
6137
|
+
// Parse failed, select first result
|
|
6138
|
+
selectFirstResult();
|
|
6034
6139
|
};
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6140
|
+
// Select first result from filtered collection
|
|
6141
|
+
const selectFirstResult = () => {
|
|
6142
|
+
if (collection.items.length > 0) {
|
|
6143
|
+
const firstItem = collection.items[0];
|
|
6144
|
+
setHour(firstItem.hour);
|
|
6145
|
+
setMinute(firstItem.minute);
|
|
6146
|
+
setMeridiem(firstItem.meridiem);
|
|
6147
|
+
filter(''); // Reset filter after selection
|
|
6148
|
+
onChange({
|
|
6149
|
+
hour: firstItem.hour,
|
|
6150
|
+
minute: firstItem.minute,
|
|
6151
|
+
meridiem: firstItem.meridiem,
|
|
6152
|
+
});
|
|
6153
|
+
}
|
|
6154
|
+
};
|
|
6155
|
+
const handleInputValueChange = (details) => {
|
|
6156
|
+
// Filter the collection based on input, but don't parse yet
|
|
6157
|
+
filter(details.inputValue);
|
|
6158
|
+
};
|
|
6159
|
+
const handleFocus = (e) => {
|
|
6160
|
+
// Select all text when focusing
|
|
6161
|
+
e.target.select();
|
|
6162
|
+
};
|
|
6163
|
+
const handleBlur = (e) => {
|
|
6164
|
+
// Parse and commit the input value when losing focus
|
|
6165
|
+
const inputValue = e.target.value;
|
|
6166
|
+
if (inputValue) {
|
|
6167
|
+
parseAndCommitInput(inputValue);
|
|
6168
|
+
}
|
|
6169
|
+
};
|
|
6170
|
+
const handleKeyDown = (e) => {
|
|
6171
|
+
// Commit input on Enter key
|
|
6172
|
+
if (e.key === 'Enter') {
|
|
6173
|
+
e.preventDefault();
|
|
6174
|
+
const inputValue = e.currentTarget.value;
|
|
6175
|
+
if (inputValue) {
|
|
6176
|
+
parseAndCommitInput(inputValue);
|
|
6177
|
+
}
|
|
6178
|
+
// Blur the input
|
|
6179
|
+
e.currentTarget?.blur();
|
|
6180
|
+
}
|
|
6181
|
+
};
|
|
6182
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder: "hh:mm a", onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsx(Combobox.IndicatorGroup, { children: jsx(Combobox.Trigger, {}) })] }), jsx(Portal, { disabled: !portalled, children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [jsx(Combobox.Empty, { children: "No time found" }), collection.items.map((item) => (jsxs(Combobox.Item, { item: item, children: [jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsx(Text, { flex: 1, children: item.label }), item.durationText && (jsx(Tag$1.Root, { size: "sm", colorPalette: "blue", children: jsx(Tag$1.Label, { children: item.durationText }) }))] }), jsx(Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: durationDiff }) })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(Icon, { children: jsx(MdCancel, {}) }) })] }) }));
|
|
6039
6183
|
}
|
|
6040
6184
|
|
|
6041
6185
|
dayjs.extend(timezone);
|
|
@@ -6113,11 +6257,138 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
6113
6257
|
} }) }) }) }) }))] }) }));
|
|
6114
6258
|
};
|
|
6115
6259
|
|
|
6260
|
+
dayjs.extend(utc);
|
|
6261
|
+
dayjs.extend(timezone);
|
|
6262
|
+
dayjs.extend(customParseFormat);
|
|
6263
|
+
function DatePickerInput({ value, onChange, placeholder = 'Select a date', dateFormat = 'YYYY-MM-DD', displayFormat = 'YYYY-MM-DD', labels = {
|
|
6264
|
+
monthNamesShort: [
|
|
6265
|
+
'Jan',
|
|
6266
|
+
'Feb',
|
|
6267
|
+
'Mar',
|
|
6268
|
+
'Apr',
|
|
6269
|
+
'May',
|
|
6270
|
+
'Jun',
|
|
6271
|
+
'Jul',
|
|
6272
|
+
'Aug',
|
|
6273
|
+
'Sep',
|
|
6274
|
+
'Oct',
|
|
6275
|
+
'Nov',
|
|
6276
|
+
'Dec',
|
|
6277
|
+
],
|
|
6278
|
+
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6279
|
+
backButtonLabel: 'Back',
|
|
6280
|
+
forwardButtonLabel: 'Next',
|
|
6281
|
+
}, timezone = 'Asia/Hong_Kong', minDate, maxDate, firstDayOfWeek, showOutsideDays, monthsToDisplay = 1, insideDialog = false, readOnly = false, }) {
|
|
6282
|
+
const [open, setOpen] = useState(false);
|
|
6283
|
+
const [inputValue, setInputValue] = useState('');
|
|
6284
|
+
// Update input value when prop value changes
|
|
6285
|
+
useEffect(() => {
|
|
6286
|
+
if (value) {
|
|
6287
|
+
const formatted = typeof value === 'string'
|
|
6288
|
+
? dayjs(value).tz(timezone).isValid()
|
|
6289
|
+
? dayjs(value).tz(timezone).format(displayFormat)
|
|
6290
|
+
: ''
|
|
6291
|
+
: dayjs(value).tz(timezone).format(displayFormat);
|
|
6292
|
+
setInputValue(formatted);
|
|
6293
|
+
}
|
|
6294
|
+
else {
|
|
6295
|
+
setInputValue('');
|
|
6296
|
+
}
|
|
6297
|
+
}, [value, displayFormat, timezone]);
|
|
6298
|
+
// Convert value to Date object for DatePicker
|
|
6299
|
+
const selectedDate = value
|
|
6300
|
+
? typeof value === 'string'
|
|
6301
|
+
? dayjs(value).tz(timezone).isValid()
|
|
6302
|
+
? dayjs(value).tz(timezone).toDate()
|
|
6303
|
+
: new Date()
|
|
6304
|
+
: value
|
|
6305
|
+
: new Date();
|
|
6306
|
+
// Shared function to parse and validate input value
|
|
6307
|
+
const parseAndValidateInput = (inputVal) => {
|
|
6308
|
+
// If empty, clear the value
|
|
6309
|
+
if (!inputVal.trim()) {
|
|
6310
|
+
onChange?.(undefined);
|
|
6311
|
+
setInputValue('');
|
|
6312
|
+
return;
|
|
6313
|
+
}
|
|
6314
|
+
// Try parsing with displayFormat first
|
|
6315
|
+
let parsedDate = dayjs(inputVal, displayFormat, true);
|
|
6316
|
+
// If that fails, try common date formats
|
|
6317
|
+
if (!parsedDate.isValid()) {
|
|
6318
|
+
parsedDate = dayjs(inputVal);
|
|
6319
|
+
}
|
|
6320
|
+
// If still invalid, try parsing with dateFormat
|
|
6321
|
+
if (!parsedDate.isValid()) {
|
|
6322
|
+
parsedDate = dayjs(inputVal, dateFormat, true);
|
|
6323
|
+
}
|
|
6324
|
+
// If valid, check constraints and update
|
|
6325
|
+
if (parsedDate.isValid()) {
|
|
6326
|
+
const dateObj = parsedDate.tz(timezone).toDate();
|
|
6327
|
+
// Check min/max constraints
|
|
6328
|
+
if (minDate && dateObj < minDate) {
|
|
6329
|
+
// Invalid: before minDate, reset to prop value
|
|
6330
|
+
resetToPropValue();
|
|
6331
|
+
return;
|
|
6332
|
+
}
|
|
6333
|
+
if (maxDate && dateObj > maxDate) {
|
|
6334
|
+
// Invalid: after maxDate, reset to prop value
|
|
6335
|
+
resetToPropValue();
|
|
6336
|
+
return;
|
|
6337
|
+
}
|
|
6338
|
+
// Valid date - format and update
|
|
6339
|
+
const formattedDate = parsedDate.tz(timezone).format(dateFormat);
|
|
6340
|
+
const formattedDisplay = parsedDate.tz(timezone).format(displayFormat);
|
|
6341
|
+
onChange?.(formattedDate);
|
|
6342
|
+
setInputValue(formattedDisplay);
|
|
6343
|
+
}
|
|
6344
|
+
else {
|
|
6345
|
+
// Invalid date - reset to prop value
|
|
6346
|
+
resetToPropValue();
|
|
6347
|
+
}
|
|
6348
|
+
};
|
|
6349
|
+
// Helper function to reset input to prop value
|
|
6350
|
+
const resetToPropValue = () => {
|
|
6351
|
+
if (value) {
|
|
6352
|
+
const formatted = typeof value === 'string'
|
|
6353
|
+
? dayjs(value).tz(timezone).isValid()
|
|
6354
|
+
? dayjs(value).tz(timezone).format(displayFormat)
|
|
6355
|
+
: ''
|
|
6356
|
+
: dayjs(value).tz(timezone).format(displayFormat);
|
|
6357
|
+
setInputValue(formatted);
|
|
6358
|
+
}
|
|
6359
|
+
else {
|
|
6360
|
+
setInputValue('');
|
|
6361
|
+
}
|
|
6362
|
+
};
|
|
6363
|
+
const handleInputChange = (e) => {
|
|
6364
|
+
// Only update the input value, don't parse yet
|
|
6365
|
+
setInputValue(e.target.value);
|
|
6366
|
+
};
|
|
6367
|
+
const handleInputBlur = () => {
|
|
6368
|
+
// Parse and validate when input loses focus
|
|
6369
|
+
parseAndValidateInput(inputValue);
|
|
6370
|
+
};
|
|
6371
|
+
const handleKeyDown = (e) => {
|
|
6372
|
+
// Parse and validate when Enter is pressed
|
|
6373
|
+
if (e.key === 'Enter') {
|
|
6374
|
+
e.preventDefault();
|
|
6375
|
+
parseAndValidateInput(inputValue);
|
|
6376
|
+
}
|
|
6377
|
+
};
|
|
6378
|
+
const handleDateSelected = ({ date }) => {
|
|
6379
|
+
const formattedDate = dayjs(date).tz(timezone).format(dateFormat);
|
|
6380
|
+
onChange?.(formattedDate);
|
|
6381
|
+
setOpen(false);
|
|
6382
|
+
};
|
|
6383
|
+
const datePickerContent = (jsx(DatePicker$1, { selected: selectedDate, onDateSelected: handleDateSelected, labels: labels, minDate: minDate, maxDate: maxDate, firstDayOfWeek: firstDayOfWeek, showOutsideDays: showOutsideDays, monthsToDisplay: monthsToDisplay }));
|
|
6384
|
+
return (jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsx(InputGroup, { endElement: jsx(Popover.Trigger, { asChild: true, children: jsx(IconButton, { variant: "ghost", size: "2xs", "aria-label": "Open calendar", onClick: () => setOpen(true), children: jsx(Icon, { children: jsx(MdDateRange, {}) }) }) }), children: jsx(Input, { value: inputValue, onChange: handleInputChange, onBlur: handleInputBlur, onKeyDown: handleKeyDown, placeholder: placeholder, readOnly: readOnly }) }), insideDialog ? (jsx(Popover.Positioner, { children: jsx(Popover.Content, { width: "fit-content", minH: "25rem", children: jsx(Popover.Body, { children: datePickerContent }) }) })) : (jsx(Portal, { children: jsx(Popover.Positioner, { children: jsx(Popover.Content, { width: "fit-content", minH: "25rem", children: jsx(Popover.Body, { children: datePickerContent }) }) }) }))] }));
|
|
6385
|
+
}
|
|
6386
|
+
|
|
6116
6387
|
dayjs.extend(utc);
|
|
6117
6388
|
dayjs.extend(timezone);
|
|
6118
6389
|
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
|
|
6119
6390
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6120
|
-
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', }) {
|
|
6391
|
+
onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Kong', portalled = true, }) {
|
|
6121
6392
|
// Generate time options (every 15 minutes, seconds always 0)
|
|
6122
6393
|
const timeOptions = useMemo(() => {
|
|
6123
6394
|
const options = [];
|
|
@@ -6152,8 +6423,8 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6152
6423
|
continue; // Skip this option as it would result in negative duration
|
|
6153
6424
|
}
|
|
6154
6425
|
}
|
|
6155
|
-
// Calculate
|
|
6156
|
-
let
|
|
6426
|
+
// Calculate duration if startTime is provided
|
|
6427
|
+
let durationText;
|
|
6157
6428
|
if (startDateTime && selectedDate) {
|
|
6158
6429
|
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
6159
6430
|
const optionDateTime = selectedDateObj
|
|
@@ -6178,17 +6449,18 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6178
6449
|
else {
|
|
6179
6450
|
diffText = `${diffSeconds}s`;
|
|
6180
6451
|
}
|
|
6181
|
-
|
|
6452
|
+
durationText = `+${diffText}`;
|
|
6182
6453
|
}
|
|
6183
6454
|
}
|
|
6184
6455
|
}
|
|
6185
6456
|
options.push({
|
|
6186
|
-
label,
|
|
6457
|
+
label: timeDisplay,
|
|
6187
6458
|
value: `${h}:${m}:0`,
|
|
6188
6459
|
hour: h,
|
|
6189
6460
|
minute: m,
|
|
6190
6461
|
second: 0,
|
|
6191
6462
|
searchText: timeDisplay, // Use base time without duration for searching
|
|
6463
|
+
durationText,
|
|
6192
6464
|
});
|
|
6193
6465
|
}
|
|
6194
6466
|
}
|
|
@@ -6208,46 +6480,46 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6208
6480
|
}
|
|
6209
6481
|
return `${hour}:${minute}:${second}`;
|
|
6210
6482
|
}, [hour, minute, second]);
|
|
6211
|
-
//
|
|
6212
|
-
const
|
|
6213
|
-
if (
|
|
6214
|
-
|
|
6483
|
+
// Calculate duration difference
|
|
6484
|
+
const durationDiff = useMemo(() => {
|
|
6485
|
+
if (!startTime ||
|
|
6486
|
+
!selectedDate ||
|
|
6487
|
+
hour === null ||
|
|
6488
|
+
minute === null ||
|
|
6489
|
+
second === null) {
|
|
6490
|
+
return null;
|
|
6215
6491
|
}
|
|
6216
|
-
const
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
diffText = `${diffMinutes}m ${diffSeconds}s`;
|
|
6241
|
-
}
|
|
6242
|
-
else {
|
|
6243
|
-
diffText = `${diffSeconds}s`;
|
|
6244
|
-
}
|
|
6245
|
-
return `${timeDisplay} (+${diffText})`;
|
|
6246
|
-
}
|
|
6247
|
-
}
|
|
6492
|
+
const startDateObj = dayjs(startTime).tz(timezone);
|
|
6493
|
+
const selectedDateObj = dayjs(selectedDate).tz(timezone);
|
|
6494
|
+
const currentDateTime = selectedDateObj
|
|
6495
|
+
.hour(hour)
|
|
6496
|
+
.minute(minute)
|
|
6497
|
+
.second(second ?? 0)
|
|
6498
|
+
.millisecond(0);
|
|
6499
|
+
if (!startDateObj.isValid() || !currentDateTime.isValid()) {
|
|
6500
|
+
return null;
|
|
6501
|
+
}
|
|
6502
|
+
const diffMs = currentDateTime.diff(startDateObj);
|
|
6503
|
+
if (diffMs < 0) {
|
|
6504
|
+
return null;
|
|
6505
|
+
}
|
|
6506
|
+
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
6507
|
+
const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
6508
|
+
const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
|
|
6509
|
+
if (diffHours > 0 || diffMinutes > 0 || diffSeconds > 0) {
|
|
6510
|
+
let diffText = '';
|
|
6511
|
+
if (diffHours > 0) {
|
|
6512
|
+
diffText = `${diffHours}h ${diffMinutes}m`;
|
|
6513
|
+
}
|
|
6514
|
+
else if (diffMinutes > 0) {
|
|
6515
|
+
diffText = `${diffMinutes}m ${diffSeconds}s`;
|
|
6248
6516
|
}
|
|
6517
|
+
else {
|
|
6518
|
+
diffText = `${diffSeconds}s`;
|
|
6519
|
+
}
|
|
6520
|
+
return `+${diffText}`;
|
|
6249
6521
|
}
|
|
6250
|
-
return
|
|
6522
|
+
return null;
|
|
6251
6523
|
}, [hour, minute, second, startTime, selectedDate, timezone]);
|
|
6252
6524
|
const handleClear = () => {
|
|
6253
6525
|
setHour(null);
|
|
@@ -6275,16 +6547,17 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6275
6547
|
});
|
|
6276
6548
|
}
|
|
6277
6549
|
};
|
|
6278
|
-
|
|
6279
|
-
|
|
6550
|
+
// Parse input value and update state
|
|
6551
|
+
const parseAndCommitInput = (value) => {
|
|
6552
|
+
const trimmedValue = value.trim();
|
|
6280
6553
|
// Filter the collection based on input
|
|
6281
|
-
filter(
|
|
6282
|
-
if (!
|
|
6554
|
+
filter(trimmedValue);
|
|
6555
|
+
if (!trimmedValue) {
|
|
6283
6556
|
return;
|
|
6284
6557
|
}
|
|
6285
6558
|
// Parse HH:mm:ss or HH:mm format
|
|
6286
6559
|
const timePattern = /^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/;
|
|
6287
|
-
const match =
|
|
6560
|
+
const match = trimmedValue.match(timePattern);
|
|
6288
6561
|
if (match) {
|
|
6289
6562
|
const parsedHour = parseInt(match[1], 10);
|
|
6290
6563
|
const parsedMinute = parseInt(match[2], 10);
|
|
@@ -6304,11 +6577,12 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6304
6577
|
minute: parsedMinute,
|
|
6305
6578
|
second: parsedSecond,
|
|
6306
6579
|
});
|
|
6580
|
+
return;
|
|
6307
6581
|
}
|
|
6308
6582
|
}
|
|
6309
6583
|
else {
|
|
6310
6584
|
// Try to parse formats like "123045" (HHmmss) or "1230" (HHmm)
|
|
6311
|
-
const numbersOnly =
|
|
6585
|
+
const numbersOnly = trimmedValue.replace(/[^0-9]/g, '');
|
|
6312
6586
|
if (numbersOnly.length >= 4) {
|
|
6313
6587
|
const parsedHour = parseInt(numbersOnly.slice(0, 2), 10);
|
|
6314
6588
|
const parsedMinute = parseInt(numbersOnly.slice(2, 4), 10);
|
|
@@ -6328,11 +6602,56 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
|
|
|
6328
6602
|
minute: parsedMinute,
|
|
6329
6603
|
second: parsedSecond,
|
|
6330
6604
|
});
|
|
6605
|
+
return;
|
|
6331
6606
|
}
|
|
6332
6607
|
}
|
|
6333
6608
|
}
|
|
6609
|
+
// Parse failed, select first result
|
|
6610
|
+
selectFirstResult();
|
|
6611
|
+
};
|
|
6612
|
+
// Select first result from filtered collection
|
|
6613
|
+
const selectFirstResult = () => {
|
|
6614
|
+
if (collection.items.length > 0) {
|
|
6615
|
+
const firstItem = collection.items[0];
|
|
6616
|
+
setHour(firstItem.hour);
|
|
6617
|
+
setMinute(firstItem.minute);
|
|
6618
|
+
setSecond(firstItem.second);
|
|
6619
|
+
filter(''); // Reset filter after selection
|
|
6620
|
+
onChange({
|
|
6621
|
+
hour: firstItem.hour,
|
|
6622
|
+
minute: firstItem.minute,
|
|
6623
|
+
second: firstItem.second,
|
|
6624
|
+
});
|
|
6625
|
+
}
|
|
6626
|
+
};
|
|
6627
|
+
const handleInputValueChange = (details) => {
|
|
6628
|
+
// Filter the collection based on input, but don't parse yet
|
|
6629
|
+
filter(details.inputValue);
|
|
6630
|
+
};
|
|
6631
|
+
const handleFocus = (e) => {
|
|
6632
|
+
// Select all text when focusing
|
|
6633
|
+
e.target.select();
|
|
6634
|
+
};
|
|
6635
|
+
const handleBlur = (e) => {
|
|
6636
|
+
// Parse and commit the input value when losing focus
|
|
6637
|
+
const inputValue = e.target.value;
|
|
6638
|
+
if (inputValue) {
|
|
6639
|
+
parseAndCommitInput(inputValue);
|
|
6640
|
+
}
|
|
6641
|
+
};
|
|
6642
|
+
const handleKeyDown = (e) => {
|
|
6643
|
+
// Commit input on Enter key
|
|
6644
|
+
if (e.key === 'Enter') {
|
|
6645
|
+
e.preventDefault();
|
|
6646
|
+
const inputValue = e.currentTarget.value;
|
|
6647
|
+
if (inputValue) {
|
|
6648
|
+
parseAndCommitInput(inputValue);
|
|
6649
|
+
}
|
|
6650
|
+
// Blur the input
|
|
6651
|
+
e.currentTarget?.blur();
|
|
6652
|
+
}
|
|
6334
6653
|
};
|
|
6335
|
-
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(
|
|
6654
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Flex, { alignItems: "center", gap: "2", width: "auto", minWidth: "300px", children: [jsxs(Combobox.Root, { collection: collection, value: currentValue ? [currentValue] : [], onValueChange: handleValueChange, onInputValueChange: handleInputValueChange, allowCustomValue: true, selectionBehavior: "replace", openOnClick: true, flex: 1, children: [jsxs(Combobox.Control, { children: [jsx(InputGroup$1, { startElement: jsx(BsClock, {}), children: jsx(Combobox.Input, { placeholder: "HH:mm:ss", onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), jsx(Combobox.IndicatorGroup, { children: jsx(Combobox.Trigger, {}) })] }), jsx(Portal, { disabled: !portalled, children: jsx(Combobox.Positioner, { children: jsxs(Combobox.Content, { children: [jsx(Combobox.Empty, { children: "No time found" }), collection.items.map((item) => (jsxs(Combobox.Item, { item: item, children: [jsxs(Flex, { alignItems: "center", gap: 2, width: "100%", children: [jsx(Text, { flex: 1, children: item.label }), item.durationText && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: item.durationText }) }))] }), jsx(Combobox.ItemIndicator, {})] }, item.value)))] }) }) })] }), durationDiff && (jsx(Tag$1.Root, { size: "sm", children: jsx(Tag$1.Label, { children: durationDiff }) })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(Icon, { children: jsx(MdCancel, {}) }) })] }) }));
|
|
6336
6655
|
}
|
|
6337
6656
|
|
|
6338
6657
|
dayjs.extend(utc);
|
|
@@ -6355,30 +6674,193 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6355
6674
|
weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
6356
6675
|
backButtonLabel: 'Back',
|
|
6357
6676
|
forwardButtonLabel: 'Next',
|
|
6358
|
-
}, timezone = 'Asia/Hong_Kong', startTime, }) {
|
|
6359
|
-
|
|
6677
|
+
}, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
|
|
6678
|
+
console.log('[DateTimePicker] Component initialized with props:', {
|
|
6679
|
+
value,
|
|
6680
|
+
format,
|
|
6681
|
+
showSeconds,
|
|
6682
|
+
timezone,
|
|
6683
|
+
startTime,
|
|
6684
|
+
minDate,
|
|
6685
|
+
maxDate,
|
|
6686
|
+
});
|
|
6687
|
+
// Initialize selectedDate from value prop, converting ISO to YYYY-MM-DD format
|
|
6688
|
+
const getDateString = useCallback((val) => {
|
|
6689
|
+
if (!val)
|
|
6690
|
+
return '';
|
|
6691
|
+
const dateObj = dayjs(val).tz(timezone);
|
|
6692
|
+
return dateObj.isValid() ? dateObj.format('YYYY-MM-DD') : '';
|
|
6693
|
+
}, [timezone]);
|
|
6694
|
+
const [selectedDate, setSelectedDate] = useState(getDateString(value));
|
|
6695
|
+
// Helper to get time values from value prop with timezone
|
|
6696
|
+
const getTimeFromValue = useCallback((val) => {
|
|
6697
|
+
console.log('[DateTimePicker] getTimeFromValue called:', {
|
|
6698
|
+
val,
|
|
6699
|
+
timezone,
|
|
6700
|
+
showSeconds,
|
|
6701
|
+
});
|
|
6702
|
+
if (!val) {
|
|
6703
|
+
console.log('[DateTimePicker] No value provided, returning nulls');
|
|
6704
|
+
return {
|
|
6705
|
+
hour12: null,
|
|
6706
|
+
minute: null,
|
|
6707
|
+
meridiem: null,
|
|
6708
|
+
hour24: null,
|
|
6709
|
+
second: null,
|
|
6710
|
+
};
|
|
6711
|
+
}
|
|
6712
|
+
const dateObj = dayjs(val).tz(timezone);
|
|
6713
|
+
console.log('[DateTimePicker] Parsed date object:', {
|
|
6714
|
+
original: val,
|
|
6715
|
+
timezone,
|
|
6716
|
+
isValid: dateObj.isValid(),
|
|
6717
|
+
formatted: dateObj.format('YYYY-MM-DD HH:mm:ss Z'),
|
|
6718
|
+
hour24: dateObj.hour(),
|
|
6719
|
+
minute: dateObj.minute(),
|
|
6720
|
+
second: dateObj.second(),
|
|
6721
|
+
});
|
|
6722
|
+
if (!dateObj.isValid()) {
|
|
6723
|
+
console.log('[DateTimePicker] Invalid date object, returning nulls');
|
|
6724
|
+
return {
|
|
6725
|
+
hour12: null,
|
|
6726
|
+
minute: null,
|
|
6727
|
+
meridiem: null,
|
|
6728
|
+
hour24: null,
|
|
6729
|
+
second: null,
|
|
6730
|
+
};
|
|
6731
|
+
}
|
|
6732
|
+
const hour24Value = dateObj.hour();
|
|
6733
|
+
const hour12Value = hour24Value % 12 || 12;
|
|
6734
|
+
const minuteValue = dateObj.minute();
|
|
6735
|
+
const meridiemValue = hour24Value >= 12 ? 'pm' : 'am';
|
|
6736
|
+
const secondValue = showSeconds ? dateObj.second() : null;
|
|
6737
|
+
const result = {
|
|
6738
|
+
hour12: hour12Value,
|
|
6739
|
+
minute: minuteValue,
|
|
6740
|
+
meridiem: meridiemValue,
|
|
6741
|
+
hour24: hour24Value,
|
|
6742
|
+
second: secondValue,
|
|
6743
|
+
};
|
|
6744
|
+
console.log('[DateTimePicker] Extracted time values:', result);
|
|
6745
|
+
return result;
|
|
6746
|
+
}, [timezone, showSeconds]);
|
|
6747
|
+
const initialTime = getTimeFromValue(value);
|
|
6748
|
+
console.log('[DateTimePicker] Initial time from value:', {
|
|
6749
|
+
value,
|
|
6750
|
+
initialTime,
|
|
6751
|
+
});
|
|
6360
6752
|
// Time state for 12-hour format
|
|
6361
|
-
const [hour12, setHour12] = useState(
|
|
6362
|
-
const [minute, setMinute] = useState(
|
|
6363
|
-
const [meridiem, setMeridiem] = useState(
|
|
6753
|
+
const [hour12, setHour12] = useState(initialTime.hour12);
|
|
6754
|
+
const [minute, setMinute] = useState(initialTime.minute);
|
|
6755
|
+
const [meridiem, setMeridiem] = useState(initialTime.meridiem);
|
|
6364
6756
|
// Time state for 24-hour format
|
|
6365
|
-
const [hour24, setHour24] = useState(
|
|
6366
|
-
const [second, setSecond] = useState(
|
|
6757
|
+
const [hour24, setHour24] = useState(initialTime.hour24);
|
|
6758
|
+
const [second, setSecond] = useState(initialTime.second);
|
|
6759
|
+
// Sync selectedDate and time states when value prop changes
|
|
6760
|
+
useEffect(() => {
|
|
6761
|
+
console.log('[DateTimePicker] useEffect triggered - value changed:', {
|
|
6762
|
+
value,
|
|
6763
|
+
timezone,
|
|
6764
|
+
format,
|
|
6765
|
+
});
|
|
6766
|
+
// If value is null, undefined, or invalid, clear all fields
|
|
6767
|
+
if (!value || value === null || value === undefined) {
|
|
6768
|
+
console.log('[DateTimePicker] Value is null/undefined, clearing all fields');
|
|
6769
|
+
setSelectedDate('');
|
|
6770
|
+
setHour12(null);
|
|
6771
|
+
setMinute(null);
|
|
6772
|
+
setMeridiem(null);
|
|
6773
|
+
setHour24(null);
|
|
6774
|
+
setSecond(null);
|
|
6775
|
+
return;
|
|
6776
|
+
}
|
|
6777
|
+
// Check if value is valid
|
|
6778
|
+
const dateObj = dayjs(value).tz(timezone);
|
|
6779
|
+
if (!dateObj.isValid()) {
|
|
6780
|
+
console.log('[DateTimePicker] Invalid value, clearing all fields');
|
|
6781
|
+
setSelectedDate('');
|
|
6782
|
+
setHour12(null);
|
|
6783
|
+
setMinute(null);
|
|
6784
|
+
setMeridiem(null);
|
|
6785
|
+
setHour24(null);
|
|
6786
|
+
setSecond(null);
|
|
6787
|
+
return;
|
|
6788
|
+
}
|
|
6789
|
+
const dateString = getDateString(value);
|
|
6790
|
+
console.log('[DateTimePicker] Setting selectedDate:', dateString);
|
|
6791
|
+
setSelectedDate(dateString);
|
|
6792
|
+
const timeData = getTimeFromValue(value);
|
|
6793
|
+
console.log('[DateTimePicker] Updating time states:', {
|
|
6794
|
+
timeData,
|
|
6795
|
+
});
|
|
6796
|
+
setHour12(timeData.hour12);
|
|
6797
|
+
setMinute(timeData.minute);
|
|
6798
|
+
setMeridiem(timeData.meridiem);
|
|
6799
|
+
setHour24(timeData.hour24);
|
|
6800
|
+
setSecond(timeData.second);
|
|
6801
|
+
}, [value, getTimeFromValue, getDateString, timezone]);
|
|
6367
6802
|
const handleDateChange = (date) => {
|
|
6803
|
+
console.log('[DateTimePicker] handleDateChange called:', {
|
|
6804
|
+
date,
|
|
6805
|
+
timezone,
|
|
6806
|
+
showSeconds,
|
|
6807
|
+
currentTimeStates: { hour12, minute, meridiem, hour24, second },
|
|
6808
|
+
});
|
|
6809
|
+
// If date is empty or invalid, clear all fields
|
|
6810
|
+
if (!date || date === '') {
|
|
6811
|
+
console.log('[DateTimePicker] Empty date, clearing all fields');
|
|
6812
|
+
setSelectedDate('');
|
|
6813
|
+
setHour12(null);
|
|
6814
|
+
setMinute(null);
|
|
6815
|
+
setMeridiem(null);
|
|
6816
|
+
setHour24(null);
|
|
6817
|
+
setSecond(null);
|
|
6818
|
+
onChange?.(undefined);
|
|
6819
|
+
return;
|
|
6820
|
+
}
|
|
6368
6821
|
setSelectedDate(date);
|
|
6822
|
+
// Parse the date string (YYYY-MM-DD) in the specified timezone
|
|
6823
|
+
const dateObj = dayjs.tz(date, timezone);
|
|
6824
|
+
console.log('[DateTimePicker] Parsed date object:', {
|
|
6825
|
+
date,
|
|
6826
|
+
timezone,
|
|
6827
|
+
isValid: dateObj.isValid(),
|
|
6828
|
+
isoString: dateObj.toISOString(),
|
|
6829
|
+
formatted: dateObj.format('YYYY-MM-DD HH:mm:ss Z'),
|
|
6830
|
+
});
|
|
6831
|
+
if (!dateObj.isValid()) {
|
|
6832
|
+
console.warn('[DateTimePicker] Invalid date object in handleDateChange, clearing fields');
|
|
6833
|
+
setSelectedDate('');
|
|
6834
|
+
setHour12(null);
|
|
6835
|
+
setMinute(null);
|
|
6836
|
+
setMeridiem(null);
|
|
6837
|
+
setHour24(null);
|
|
6838
|
+
setSecond(null);
|
|
6839
|
+
onChange?.(undefined);
|
|
6840
|
+
return;
|
|
6841
|
+
}
|
|
6369
6842
|
// When showSeconds is false, ignore seconds from the date
|
|
6370
|
-
|
|
6371
|
-
if (!showSeconds && dateObj.isValid()) {
|
|
6843
|
+
if (!showSeconds) {
|
|
6372
6844
|
const dateWithoutSeconds = dateObj.second(0).millisecond(0).toISOString();
|
|
6845
|
+
console.log('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
|
|
6373
6846
|
updateDateTime(dateWithoutSeconds);
|
|
6374
6847
|
}
|
|
6375
6848
|
else {
|
|
6376
|
-
|
|
6849
|
+
const dateWithSeconds = dateObj.toISOString();
|
|
6850
|
+
console.log('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
|
|
6851
|
+
updateDateTime(dateWithSeconds);
|
|
6377
6852
|
}
|
|
6378
6853
|
};
|
|
6379
6854
|
const handleTimeChange = (timeData) => {
|
|
6855
|
+
console.log('[DateTimePicker] handleTimeChange called:', {
|
|
6856
|
+
timeData,
|
|
6857
|
+
format,
|
|
6858
|
+
selectedDate,
|
|
6859
|
+
timezone,
|
|
6860
|
+
});
|
|
6380
6861
|
if (format === 'iso-date-time') {
|
|
6381
6862
|
const data = timeData;
|
|
6863
|
+
console.log('[DateTimePicker] ISO format - setting 24-hour time:', data);
|
|
6382
6864
|
setHour24(data.hour);
|
|
6383
6865
|
setMinute(data.minute);
|
|
6384
6866
|
if (showSeconds) {
|
|
@@ -6391,60 +6873,161 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6391
6873
|
}
|
|
6392
6874
|
else {
|
|
6393
6875
|
const data = timeData;
|
|
6876
|
+
console.log('[DateTimePicker] 12-hour format - setting time:', data);
|
|
6394
6877
|
setHour12(data.hour);
|
|
6395
6878
|
setMinute(data.minute);
|
|
6396
6879
|
setMeridiem(data.meridiem);
|
|
6397
6880
|
}
|
|
6398
|
-
// Use selectedDate if valid, otherwise
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6881
|
+
// Use selectedDate if valid, otherwise clear all fields
|
|
6882
|
+
if (!selectedDate || !dayjs(selectedDate).isValid()) {
|
|
6883
|
+
console.log('[DateTimePicker] No valid selectedDate, clearing all fields');
|
|
6884
|
+
setSelectedDate('');
|
|
6885
|
+
setHour12(null);
|
|
6886
|
+
setMinute(null);
|
|
6887
|
+
setMeridiem(null);
|
|
6888
|
+
setHour24(null);
|
|
6889
|
+
setSecond(null);
|
|
6890
|
+
onChange?.(undefined);
|
|
6891
|
+
return;
|
|
6892
|
+
}
|
|
6893
|
+
const dateObj = dayjs(selectedDate).tz(timezone);
|
|
6403
6894
|
if (dateObj.isValid()) {
|
|
6404
6895
|
updateDateTime(dateObj.toISOString(), timeData);
|
|
6405
6896
|
}
|
|
6897
|
+
else {
|
|
6898
|
+
console.warn('[DateTimePicker] Invalid date object in handleTimeChange, clearing fields');
|
|
6899
|
+
setSelectedDate('');
|
|
6900
|
+
setHour12(null);
|
|
6901
|
+
setMinute(null);
|
|
6902
|
+
setMeridiem(null);
|
|
6903
|
+
setHour24(null);
|
|
6904
|
+
setSecond(null);
|
|
6905
|
+
onChange?.(undefined);
|
|
6906
|
+
}
|
|
6406
6907
|
};
|
|
6407
6908
|
const updateDateTime = (date, timeData) => {
|
|
6408
|
-
|
|
6909
|
+
console.log('[DateTimePicker] updateDateTime called:', {
|
|
6910
|
+
date,
|
|
6911
|
+
timeData,
|
|
6912
|
+
format,
|
|
6913
|
+
currentStates: { hour12, minute, meridiem, hour24, second },
|
|
6914
|
+
});
|
|
6915
|
+
if (!date || date === null || date === undefined) {
|
|
6916
|
+
console.log('[DateTimePicker] No date provided, clearing all fields and calling onChange(undefined)');
|
|
6917
|
+
setSelectedDate('');
|
|
6918
|
+
setHour12(null);
|
|
6919
|
+
setMinute(null);
|
|
6920
|
+
setMeridiem(null);
|
|
6921
|
+
setHour24(null);
|
|
6922
|
+
setSecond(null);
|
|
6409
6923
|
onChange?.(undefined);
|
|
6410
6924
|
return;
|
|
6411
6925
|
}
|
|
6412
6926
|
// use dayjs to convert the date to the timezone
|
|
6413
6927
|
const dateObj = dayjs(date).tz(timezone);
|
|
6414
6928
|
if (!dateObj.isValid()) {
|
|
6929
|
+
console.warn('[DateTimePicker] Invalid date object in updateDateTime, clearing fields:', date);
|
|
6930
|
+
setSelectedDate('');
|
|
6931
|
+
setHour12(null);
|
|
6932
|
+
setMinute(null);
|
|
6933
|
+
setMeridiem(null);
|
|
6934
|
+
setHour24(null);
|
|
6935
|
+
setSecond(null);
|
|
6936
|
+
onChange?.(undefined);
|
|
6415
6937
|
return;
|
|
6416
6938
|
}
|
|
6417
6939
|
const newDate = dateObj.toDate();
|
|
6418
6940
|
if (format === 'iso-date-time') {
|
|
6419
6941
|
const data = timeData;
|
|
6420
|
-
|
|
6421
|
-
|
|
6942
|
+
// Use timeData values if provided, otherwise fall back to current state
|
|
6943
|
+
// But if timeData is explicitly provided with nulls, we need to check if all are null
|
|
6944
|
+
const h = data !== undefined ? data.hour : hour24;
|
|
6945
|
+
const m = data !== undefined ? data.minute : minute;
|
|
6422
6946
|
// Always ignore seconds when showSeconds is false - set to 0
|
|
6423
|
-
const s = showSeconds
|
|
6947
|
+
const s = showSeconds
|
|
6948
|
+
? data !== undefined
|
|
6949
|
+
? data.second ?? null
|
|
6950
|
+
: second ?? 0
|
|
6951
|
+
: 0;
|
|
6952
|
+
// If all time values are null, clear the value
|
|
6953
|
+
if (h === null && m === null && (showSeconds ? s === null : true)) {
|
|
6954
|
+
console.log('[DateTimePicker] All time values are null, clearing value');
|
|
6955
|
+
onChange?.(undefined);
|
|
6956
|
+
return;
|
|
6957
|
+
}
|
|
6958
|
+
console.log('[DateTimePicker] ISO format - setting time on date:', {
|
|
6959
|
+
h,
|
|
6960
|
+
m,
|
|
6961
|
+
s,
|
|
6962
|
+
showSeconds,
|
|
6963
|
+
});
|
|
6424
6964
|
if (h !== null)
|
|
6425
6965
|
newDate.setHours(h);
|
|
6426
6966
|
if (m !== null)
|
|
6427
6967
|
newDate.setMinutes(m);
|
|
6428
|
-
newDate.setSeconds(s);
|
|
6968
|
+
newDate.setSeconds(s ?? 0);
|
|
6429
6969
|
}
|
|
6430
6970
|
else {
|
|
6431
6971
|
const data = timeData;
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6972
|
+
console.log('[DateTimePicker] Processing 12-hour format:', {
|
|
6973
|
+
'data !== undefined': data !== undefined,
|
|
6974
|
+
'data?.hour': data?.hour,
|
|
6975
|
+
'data?.minute': data?.minute,
|
|
6976
|
+
'data?.meridiem': data?.meridiem,
|
|
6977
|
+
'current hour12': hour12,
|
|
6978
|
+
'current minute': minute,
|
|
6979
|
+
'current meridiem': meridiem,
|
|
6980
|
+
});
|
|
6981
|
+
// Use timeData values if provided, otherwise fall back to current state
|
|
6982
|
+
const h = data !== undefined ? data.hour : hour12;
|
|
6983
|
+
const m = data !== undefined ? data.minute : minute;
|
|
6984
|
+
const mer = data !== undefined ? data.meridiem : meridiem;
|
|
6985
|
+
console.log('[DateTimePicker] Resolved time values:', { h, m, mer });
|
|
6986
|
+
// If all time values are null, clear the value
|
|
6987
|
+
if (h === null && m === null && mer === null) {
|
|
6988
|
+
console.log('[DateTimePicker] All time values are null, clearing value');
|
|
6989
|
+
onChange?.(undefined);
|
|
6990
|
+
return;
|
|
6991
|
+
}
|
|
6992
|
+
console.log('[DateTimePicker] 12-hour format - converting time:', {
|
|
6993
|
+
h,
|
|
6994
|
+
m,
|
|
6995
|
+
mer,
|
|
6996
|
+
});
|
|
6435
6997
|
if (h !== null && mer !== null) {
|
|
6436
6998
|
let hour24 = h;
|
|
6437
6999
|
if (mer === 'am' && h === 12)
|
|
6438
7000
|
hour24 = 0;
|
|
6439
7001
|
else if (mer === 'pm' && h < 12)
|
|
6440
7002
|
hour24 = h + 12;
|
|
7003
|
+
console.log('[DateTimePicker] Converted to 24-hour:', {
|
|
7004
|
+
h,
|
|
7005
|
+
mer,
|
|
7006
|
+
hour24,
|
|
7007
|
+
});
|
|
6441
7008
|
newDate.setHours(hour24);
|
|
6442
7009
|
}
|
|
6443
|
-
|
|
7010
|
+
else {
|
|
7011
|
+
console.log('[DateTimePicker] Skipping hour update - h or mer is null:', {
|
|
7012
|
+
h,
|
|
7013
|
+
mer,
|
|
7014
|
+
});
|
|
7015
|
+
}
|
|
7016
|
+
if (m !== null) {
|
|
6444
7017
|
newDate.setMinutes(m);
|
|
7018
|
+
}
|
|
7019
|
+
else {
|
|
7020
|
+
console.log('[DateTimePicker] Skipping minute update - m is null');
|
|
7021
|
+
}
|
|
6445
7022
|
newDate.setSeconds(0);
|
|
6446
7023
|
}
|
|
6447
|
-
|
|
7024
|
+
const finalISO = dayjs(newDate).tz(timezone).toISOString();
|
|
7025
|
+
console.log('[DateTimePicker] Final ISO string to emit:', {
|
|
7026
|
+
newDate: newDate.toISOString(),
|
|
7027
|
+
timezone,
|
|
7028
|
+
finalISO,
|
|
7029
|
+
});
|
|
7030
|
+
onChange?.(finalISO);
|
|
6448
7031
|
};
|
|
6449
7032
|
const handleClear = () => {
|
|
6450
7033
|
setSelectedDate('');
|
|
@@ -6460,14 +7043,92 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
|
|
|
6460
7043
|
const normalizedStartTime = startTime
|
|
6461
7044
|
? dayjs(startTime).tz(timezone).millisecond(0).toISOString()
|
|
6462
7045
|
: undefined;
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
7046
|
+
// Determine minDate: prioritize explicit minDate prop, then fall back to startTime
|
|
7047
|
+
const effectiveMinDate = minDate
|
|
7048
|
+
? minDate
|
|
7049
|
+
: normalizedStartTime && dayjs(normalizedStartTime).tz(timezone).isValid()
|
|
7050
|
+
? dayjs(normalizedStartTime).tz(timezone).startOf('day').toDate()
|
|
7051
|
+
: undefined;
|
|
7052
|
+
// Log current state before render
|
|
7053
|
+
useEffect(() => {
|
|
7054
|
+
console.log('[DateTimePicker] Current state before render:', {
|
|
7055
|
+
isISO,
|
|
7056
|
+
hour12,
|
|
7057
|
+
minute,
|
|
7058
|
+
meridiem,
|
|
7059
|
+
hour24,
|
|
7060
|
+
second,
|
|
7061
|
+
selectedDate,
|
|
7062
|
+
normalizedStartTime,
|
|
7063
|
+
timezone,
|
|
7064
|
+
});
|
|
7065
|
+
}, [
|
|
7066
|
+
isISO,
|
|
7067
|
+
hour12,
|
|
7068
|
+
minute,
|
|
7069
|
+
meridiem,
|
|
7070
|
+
hour24,
|
|
7071
|
+
second,
|
|
7072
|
+
selectedDate,
|
|
7073
|
+
normalizedStartTime,
|
|
7074
|
+
timezone,
|
|
7075
|
+
]);
|
|
7076
|
+
// Compute display text from current state
|
|
7077
|
+
const displayText = useMemo(() => {
|
|
7078
|
+
if (!selectedDate)
|
|
7079
|
+
return null;
|
|
7080
|
+
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7081
|
+
if (!dateObj.isValid())
|
|
7082
|
+
return null;
|
|
7083
|
+
if (isISO) {
|
|
7084
|
+
// For ISO format, use hour24, minute, second
|
|
7085
|
+
if (hour24 === null || minute === null)
|
|
7086
|
+
return null;
|
|
7087
|
+
const dateTimeObj = dateObj
|
|
7088
|
+
.hour(hour24)
|
|
7089
|
+
.minute(minute)
|
|
7090
|
+
.second(second ?? 0);
|
|
7091
|
+
return dateTimeObj.format(showSeconds ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD HH:mm');
|
|
7092
|
+
}
|
|
7093
|
+
else {
|
|
7094
|
+
// For 12-hour format, use hour12, minute, meridiem
|
|
7095
|
+
if (hour12 === null || minute === null || meridiem === null)
|
|
7096
|
+
return null;
|
|
7097
|
+
// Convert to 24-hour format for dayjs
|
|
7098
|
+
let hour24Value = hour12;
|
|
7099
|
+
if (meridiem === 'am' && hour12 === 12)
|
|
7100
|
+
hour24Value = 0;
|
|
7101
|
+
else if (meridiem === 'pm' && hour12 < 12)
|
|
7102
|
+
hour24Value = hour12 + 12;
|
|
7103
|
+
const dateTimeObj = dateObj.hour(hour24Value).minute(minute).second(0);
|
|
7104
|
+
return dateTimeObj.format('YYYY-MM-DD hh:mm A');
|
|
7105
|
+
}
|
|
7106
|
+
}, [
|
|
7107
|
+
selectedDate,
|
|
7108
|
+
isISO,
|
|
7109
|
+
hour12,
|
|
7110
|
+
minute,
|
|
7111
|
+
meridiem,
|
|
7112
|
+
hour24,
|
|
7113
|
+
second,
|
|
7114
|
+
showSeconds,
|
|
7115
|
+
timezone,
|
|
7116
|
+
]);
|
|
7117
|
+
const timezoneOffset = useMemo(() => {
|
|
7118
|
+
if (!selectedDate)
|
|
7119
|
+
return null;
|
|
7120
|
+
const dateObj = dayjs.tz(selectedDate, timezone);
|
|
7121
|
+
return dateObj.isValid() ? dateObj.format('Z') : null;
|
|
7122
|
+
}, [selectedDate, timezone]);
|
|
7123
|
+
return (jsxs(Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
|
|
7124
|
+
if (date) {
|
|
7125
|
+
handleDateChange(date);
|
|
7126
|
+
}
|
|
7127
|
+
else {
|
|
7128
|
+
setSelectedDate('');
|
|
7129
|
+
onChange?.(undefined);
|
|
7130
|
+
}
|
|
7131
|
+
}, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: true }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (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 })) : (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 })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), displayText && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: displayText }), timezoneOffset && (jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezoneOffset })), jsx(Text, { fontSize: "sm", color: { base: 'gray.600', _dark: 'gray.600' }, children: timezone })] }))] }));
|
|
6471
7132
|
}
|
|
6472
7133
|
|
|
6473
7134
|
dayjs.extend(utc);
|
|
@@ -6483,32 +7144,9 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
6483
7144
|
const colLabel = formI18n.colLabel;
|
|
6484
7145
|
const [open, setOpen] = useState(false);
|
|
6485
7146
|
const selectedDate = watch(colLabel);
|
|
6486
|
-
const displayDate = dayjs(selectedDate)
|
|
6487
|
-
.tz(timezone)
|
|
6488
|
-
|
|
6489
|
-
useEffect(() => {
|
|
6490
|
-
try {
|
|
6491
|
-
if (selectedDate) {
|
|
6492
|
-
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
6493
|
-
// For example, parse as UTC:
|
|
6494
|
-
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
6495
|
-
if (!parsedDate.isValid())
|
|
6496
|
-
return;
|
|
6497
|
-
// Format according to dateFormat from schema
|
|
6498
|
-
const formatted = parsedDate.format(dateFormat);
|
|
6499
|
-
// Update the form value only if different to avoid loops
|
|
6500
|
-
if (formatted !== selectedDate) {
|
|
6501
|
-
setValue(colLabel, formatted, {
|
|
6502
|
-
shouldValidate: true,
|
|
6503
|
-
shouldDirty: true,
|
|
6504
|
-
});
|
|
6505
|
-
}
|
|
6506
|
-
}
|
|
6507
|
-
}
|
|
6508
|
-
catch (e) {
|
|
6509
|
-
console.error(e);
|
|
6510
|
-
}
|
|
6511
|
-
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
7147
|
+
const displayDate = selectedDate && dayjs(selectedDate).tz(timezone).isValid()
|
|
7148
|
+
? dayjs(selectedDate).tz(timezone).format(displayDateFormat)
|
|
7149
|
+
: '';
|
|
6512
7150
|
const dateTimePickerLabelsConfig = {
|
|
6513
7151
|
monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
|
|
6514
7152
|
formI18n.translate.t(`common.month_1`, {
|
|
@@ -6581,12 +7219,22 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
|
6581
7219
|
}),
|
|
6582
7220
|
};
|
|
6583
7221
|
const dateTimePickerContent = (jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
6584
|
-
|
|
7222
|
+
if (!date || date === null || date === undefined) {
|
|
7223
|
+
setValue(colLabel, undefined);
|
|
7224
|
+
return;
|
|
7225
|
+
}
|
|
7226
|
+
const dateObj = dayjs(date).tz(timezone);
|
|
7227
|
+
if (dateObj.isValid()) {
|
|
7228
|
+
setValue(colLabel, dateObj.format(dateFormat));
|
|
7229
|
+
}
|
|
7230
|
+
else {
|
|
7231
|
+
setValue(colLabel, undefined);
|
|
7232
|
+
}
|
|
6585
7233
|
}, timezone: timezone, labels: dateTimePickerLabelsConfig }));
|
|
6586
7234
|
return (jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
|
|
6587
|
-
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
7235
|
+
gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, autoFocus: false, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
6588
7236
|
setOpen(true);
|
|
6589
|
-
}, justifyContent: 'start', children: [jsx(MdDateRange, {}),
|
|
7237
|
+
}, justifyContent: 'start', children: [jsx(MdDateRange, {}), displayDate || ''] }) }), insideDialog ? (jsx(Popover.Positioner, { children: jsx(Popover.Content, { width: "fit-content", minW: "450px", minH: "25rem", children: jsx(Popover.Body, { children: dateTimePickerContent }) }) })) : (jsx(Portal, { children: jsx(Popover.Positioner, { children: jsx(Popover.Content, { width: "fit-content", minW: "450px", minH: "25rem", children: jsx(Popover.Body, { children: dateTimePickerContent }) }) }) }))] }) }));
|
|
6590
7238
|
};
|
|
6591
7239
|
|
|
6592
7240
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
@@ -8017,4 +8665,4 @@ function DataTableServer({ columns, enableRowSelection = true, enableMultiRowSel
|
|
|
8017
8665
|
}, children: jsx(DataTableServerContext.Provider, { value: { url, query }, children: children }) }));
|
|
8018
8666
|
}
|
|
8019
8667
|
|
|
8020
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
|
8668
|
+
export { CardHeader, DataDisplay, DataTable, DataTableServer, DatePickerInput, DefaultCardTitle, DefaultForm, DefaultTable, DefaultTableServer, DensityToggleButton, EditSortingButton, EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, MediaLibraryBrowser, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, SelectAllRowsToggle, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, buildErrorMessages, buildFieldErrors, buildRequiredErrors, convertToAjvErrorsFormat, createErrorMessage, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|