@bsol-oss/react-datatable5 13.0.1-beta.4 → 13.0.1-beta.5

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.js CHANGED
@@ -31,8 +31,8 @@ var addFormats = require('ajv-formats');
31
31
  var dayjs = require('dayjs');
32
32
  var utc = require('dayjs/plugin/utc');
33
33
  var timezone = require('dayjs/plugin/timezone');
34
- var ti = require('react-icons/ti');
35
34
  var customParseFormat = require('dayjs/plugin/customParseFormat');
35
+ var ti = require('react-icons/ti');
36
36
  var matchSorterUtils = require('@tanstack/match-sorter-utils');
37
37
 
38
38
  function _interopNamespaceDefault(e) {
@@ -4545,6 +4545,9 @@ const CustomInput = ({ column, schema, prefix }) => {
4545
4545
  }));
4546
4546
  };
4547
4547
 
4548
+ dayjs.extend(utc);
4549
+ dayjs.extend(timezone);
4550
+ dayjs.extend(customParseFormat);
4548
4551
  const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
4549
4552
  const { labels } = React.useContext(DatePickerContext);
4550
4553
  const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
@@ -4614,6 +4617,9 @@ const DatePickerContext = React.createContext({
4614
4617
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4615
4618
  backButtonLabel: 'Back',
4616
4619
  forwardButtonLabel: 'Next',
4620
+ todayLabel: 'Today',
4621
+ yesterdayLabel: 'Yesterday',
4622
+ tomorrowLabel: 'Tomorrow',
4617
4623
  },
4618
4624
  });
4619
4625
  const DatePicker$1 = ({ labels = {
@@ -4634,6 +4640,9 @@ const DatePicker$1 = ({ labels = {
4634
4640
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4635
4641
  backButtonLabel: 'Back',
4636
4642
  forwardButtonLabel: 'Next',
4643
+ todayLabel: 'Today',
4644
+ yesterdayLabel: 'Yesterday',
4645
+ tomorrowLabel: 'Tomorrow',
4637
4646
  }, onDateSelected, selected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
4638
4647
  const calendarData = useCalendar({
4639
4648
  onDateSelected,
@@ -4648,9 +4657,164 @@ const DatePicker$1 = ({ labels = {
4648
4657
  return (jsxRuntime.jsx(DatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsxRuntime.jsx(Calendar, { ...calendarData,
4649
4658
  firstDayOfWeek })) }));
4650
4659
  };
4660
+ function DatePickerInput({ value, onChange, placeholder = 'Select a date', dateFormat = 'YYYY-MM-DD', displayFormat = 'YYYY-MM-DD', labels = {
4661
+ monthNamesShort: [
4662
+ 'Jan',
4663
+ 'Feb',
4664
+ 'Mar',
4665
+ 'Apr',
4666
+ 'May',
4667
+ 'Jun',
4668
+ 'Jul',
4669
+ 'Aug',
4670
+ 'Sep',
4671
+ 'Oct',
4672
+ 'Nov',
4673
+ 'Dec',
4674
+ ],
4675
+ weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4676
+ backButtonLabel: 'Back',
4677
+ forwardButtonLabel: 'Next',
4678
+ todayLabel: 'Today',
4679
+ yesterdayLabel: 'Yesterday',
4680
+ tomorrowLabel: 'Tomorrow',
4681
+ }, timezone = 'Asia/Hong_Kong', minDate, maxDate, firstDayOfWeek, showOutsideDays, monthsToDisplay = 1, insideDialog = false, readOnly = false, showHelperButtons = true, }) {
4682
+ const [open, setOpen] = React.useState(false);
4683
+ const [inputValue, setInputValue] = React.useState('');
4684
+ // Update input value when prop value changes
4685
+ React.useEffect(() => {
4686
+ if (value) {
4687
+ const formatted = typeof value === 'string'
4688
+ ? dayjs(value).tz(timezone).isValid()
4689
+ ? dayjs(value).tz(timezone).format(displayFormat)
4690
+ : ''
4691
+ : dayjs(value).tz(timezone).format(displayFormat);
4692
+ setInputValue(formatted);
4693
+ }
4694
+ else {
4695
+ setInputValue('');
4696
+ }
4697
+ }, [value, displayFormat, timezone]);
4698
+ // Convert value to Date object for DatePicker
4699
+ const selectedDate = value
4700
+ ? typeof value === 'string'
4701
+ ? dayjs(value).tz(timezone).isValid()
4702
+ ? dayjs(value).tz(timezone).toDate()
4703
+ : new Date()
4704
+ : value
4705
+ : new Date();
4706
+ // Shared function to parse and validate input value
4707
+ const parseAndValidateInput = (inputVal) => {
4708
+ // If empty, clear the value
4709
+ if (!inputVal.trim()) {
4710
+ onChange?.(undefined);
4711
+ setInputValue('');
4712
+ return;
4713
+ }
4714
+ // Try parsing with displayFormat first
4715
+ let parsedDate = dayjs(inputVal, displayFormat, true);
4716
+ // If that fails, try common date formats
4717
+ if (!parsedDate.isValid()) {
4718
+ parsedDate = dayjs(inputVal);
4719
+ }
4720
+ // If still invalid, try parsing with dateFormat
4721
+ if (!parsedDate.isValid()) {
4722
+ parsedDate = dayjs(inputVal, dateFormat, true);
4723
+ }
4724
+ // If valid, check constraints and update
4725
+ if (parsedDate.isValid()) {
4726
+ const dateObj = parsedDate.tz(timezone).toDate();
4727
+ // Check min/max constraints
4728
+ if (minDate && dateObj < minDate) {
4729
+ // Invalid: before minDate, reset to prop value
4730
+ resetToPropValue();
4731
+ return;
4732
+ }
4733
+ if (maxDate && dateObj > maxDate) {
4734
+ // Invalid: after maxDate, reset to prop value
4735
+ resetToPropValue();
4736
+ return;
4737
+ }
4738
+ // Valid date - format and update
4739
+ const formattedDate = parsedDate.tz(timezone).format(dateFormat);
4740
+ const formattedDisplay = parsedDate.tz(timezone).format(displayFormat);
4741
+ onChange?.(formattedDate);
4742
+ setInputValue(formattedDisplay);
4743
+ }
4744
+ else {
4745
+ // Invalid date - reset to prop value
4746
+ resetToPropValue();
4747
+ }
4748
+ };
4749
+ // Helper function to reset input to prop value
4750
+ const resetToPropValue = () => {
4751
+ if (value) {
4752
+ const formatted = typeof value === 'string'
4753
+ ? dayjs(value).tz(timezone).isValid()
4754
+ ? dayjs(value).tz(timezone).format(displayFormat)
4755
+ : ''
4756
+ : dayjs(value).tz(timezone).format(displayFormat);
4757
+ setInputValue(formatted);
4758
+ }
4759
+ else {
4760
+ setInputValue('');
4761
+ }
4762
+ };
4763
+ const handleInputChange = (e) => {
4764
+ // Only update the input value, don't parse yet
4765
+ setInputValue(e.target.value);
4766
+ };
4767
+ const handleInputBlur = () => {
4768
+ // Parse and validate when input loses focus
4769
+ parseAndValidateInput(inputValue);
4770
+ };
4771
+ const handleKeyDown = (e) => {
4772
+ // Parse and validate when Enter is pressed
4773
+ if (e.key === 'Enter') {
4774
+ e.preventDefault();
4775
+ parseAndValidateInput(inputValue);
4776
+ }
4777
+ };
4778
+ const handleDateSelected = ({ date }) => {
4779
+ const formattedDate = dayjs(date).tz(timezone).format(dateFormat);
4780
+ onChange?.(formattedDate);
4781
+ setOpen(false);
4782
+ };
4783
+ // Helper function to get dates in the correct timezone
4784
+ const getToday = () => dayjs().tz(timezone).startOf('day').toDate();
4785
+ const getYesterday = () => dayjs().tz(timezone).subtract(1, 'day').startOf('day').toDate();
4786
+ const getTomorrow = () => dayjs().tz(timezone).add(1, 'day').startOf('day').toDate();
4787
+ // Check if a date is within min/max constraints
4788
+ const isDateValid = (date) => {
4789
+ if (minDate) {
4790
+ const minDateStart = dayjs(minDate).tz(timezone).startOf('day').toDate();
4791
+ const dateStart = dayjs(date).tz(timezone).startOf('day').toDate();
4792
+ if (dateStart < minDateStart)
4793
+ return false;
4794
+ }
4795
+ if (maxDate) {
4796
+ const maxDateStart = dayjs(maxDate).tz(timezone).startOf('day').toDate();
4797
+ const dateStart = dayjs(date).tz(timezone).startOf('day').toDate();
4798
+ if (dateStart > maxDateStart)
4799
+ return false;
4800
+ }
4801
+ return true;
4802
+ };
4803
+ const handleHelperButtonClick = (date) => {
4804
+ if (isDateValid(date)) {
4805
+ handleDateSelected({ date });
4806
+ }
4807
+ };
4808
+ const today = getToday();
4809
+ const yesterday = getYesterday();
4810
+ const tomorrow = getTomorrow();
4811
+ const datePickerContent = (jsxRuntime.jsxs(react.Grid, { gap: 2, children: [showHelperButtons && (jsxRuntime.jsxs(react.Grid, { templateColumns: "repeat(3, 1fr)", gap: 2, children: [jsxRuntime.jsx(react.Button, { size: "sm", variant: "outline", onClick: () => handleHelperButtonClick(yesterday), disabled: !isDateValid(yesterday), children: labels.yesterdayLabel ?? 'Yesterday' }), jsxRuntime.jsx(react.Button, { size: "sm", variant: "outline", onClick: () => handleHelperButtonClick(today), disabled: !isDateValid(today), children: labels.todayLabel ?? 'Today' }), jsxRuntime.jsx(react.Button, { size: "sm", variant: "outline", onClick: () => handleHelperButtonClick(tomorrow), disabled: !isDateValid(tomorrow), children: labels.tomorrowLabel ?? 'Tomorrow' })] })), jsxRuntime.jsx(DatePicker$1, { selected: selectedDate, onDateSelected: handleDateSelected, labels: labels, minDate: minDate, maxDate: maxDate, firstDayOfWeek: firstDayOfWeek, showOutsideDays: showOutsideDays, monthsToDisplay: monthsToDisplay })] }));
4812
+ 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 }) }) }) }))] }));
4813
+ }
4651
4814
 
4652
4815
  dayjs.extend(utc);
4653
4816
  dayjs.extend(timezone);
4817
+ dayjs.extend(customParseFormat);
4654
4818
  const DatePicker = ({ column, schema, prefix }) => {
4655
4819
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4656
4820
  const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
@@ -4659,15 +4823,29 @@ const DatePicker = ({ column, schema, prefix }) => {
4659
4823
  const isRequired = required?.some((columnId) => columnId === column);
4660
4824
  const colLabel = formI18n.colLabel;
4661
4825
  const [open, setOpen] = React.useState(false);
4826
+ const [inputValue, setInputValue] = React.useState('');
4662
4827
  const selectedDate = watch(colLabel);
4663
- const displayDate = dayjs(selectedDate)
4664
- .tz(timezone)
4665
- .format(displayDateFormat);
4828
+ // Update input value when form value changes
4829
+ React.useEffect(() => {
4830
+ if (selectedDate) {
4831
+ const parsedDate = dayjs(selectedDate).tz(timezone);
4832
+ if (parsedDate.isValid()) {
4833
+ const formatted = parsedDate.format(displayDateFormat);
4834
+ setInputValue(formatted);
4835
+ }
4836
+ else {
4837
+ setInputValue('');
4838
+ }
4839
+ }
4840
+ else {
4841
+ setInputValue('');
4842
+ }
4843
+ }, [selectedDate, displayDateFormat, timezone]);
4844
+ // Format and validate existing value
4666
4845
  React.useEffect(() => {
4667
4846
  try {
4668
4847
  if (selectedDate) {
4669
4848
  // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
4670
- // For example, parse as UTC:
4671
4849
  const parsedDate = dayjs(selectedDate).tz(timezone);
4672
4850
  if (!parsedDate.isValid())
4673
4851
  return;
@@ -4685,7 +4863,7 @@ const DatePicker = ({ column, schema, prefix }) => {
4685
4863
  catch (e) {
4686
4864
  console.error(e);
4687
4865
  }
4688
- }, [selectedDate, dateFormat, colLabel, setValue]);
4866
+ }, [selectedDate, dateFormat, colLabel, setValue, timezone]);
4689
4867
  const datePickerLabels = {
4690
4868
  monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4691
4869
  'January',
@@ -4713,14 +4891,92 @@ const DatePicker = ({ column, schema, prefix }) => {
4713
4891
  backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
4714
4892
  forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
4715
4893
  };
4716
- const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4717
- setValue(colLabel, dayjs(date).format(dateFormat));
4718
- setOpen(false);
4719
- }, labels: datePickerLabels }));
4894
+ // Convert value to Date object for DatePicker
4895
+ const selectedDateObj = selectedDate
4896
+ ? dayjs(selectedDate).tz(timezone).isValid()
4897
+ ? dayjs(selectedDate).tz(timezone).toDate()
4898
+ : new Date()
4899
+ : new Date();
4900
+ // Shared function to parse and validate input value
4901
+ const parseAndValidateInput = (inputVal) => {
4902
+ // If empty, clear the value
4903
+ if (!inputVal.trim()) {
4904
+ setValue(colLabel, undefined, {
4905
+ shouldValidate: true,
4906
+ shouldDirty: true,
4907
+ });
4908
+ setInputValue('');
4909
+ return;
4910
+ }
4911
+ // Try parsing with displayDateFormat first
4912
+ let parsedDate = dayjs(inputVal, displayDateFormat, true);
4913
+ // If that fails, try common date formats
4914
+ if (!parsedDate.isValid()) {
4915
+ parsedDate = dayjs(inputVal);
4916
+ }
4917
+ // If still invalid, try parsing with dateFormat
4918
+ if (!parsedDate.isValid()) {
4919
+ parsedDate = dayjs(inputVal, dateFormat, true);
4920
+ }
4921
+ // If valid, format and update
4922
+ if (parsedDate.isValid()) {
4923
+ const formattedDate = parsedDate.tz(timezone).format(dateFormat);
4924
+ const formattedDisplay = parsedDate
4925
+ .tz(timezone)
4926
+ .format(displayDateFormat);
4927
+ setValue(colLabel, formattedDate, {
4928
+ shouldValidate: true,
4929
+ shouldDirty: true,
4930
+ });
4931
+ setInputValue(formattedDisplay);
4932
+ }
4933
+ else {
4934
+ // Invalid date - reset to prop value
4935
+ resetToPropValue();
4936
+ }
4937
+ };
4938
+ // Helper function to reset input to prop value
4939
+ const resetToPropValue = () => {
4940
+ if (selectedDate) {
4941
+ const parsedDate = dayjs(selectedDate).tz(timezone);
4942
+ if (parsedDate.isValid()) {
4943
+ const formatted = parsedDate.format(displayDateFormat);
4944
+ setInputValue(formatted);
4945
+ }
4946
+ else {
4947
+ setInputValue('');
4948
+ }
4949
+ }
4950
+ else {
4951
+ setInputValue('');
4952
+ }
4953
+ };
4954
+ const handleInputChange = (e) => {
4955
+ // Only update the input value, don't parse yet
4956
+ setInputValue(e.target.value);
4957
+ };
4958
+ const handleInputBlur = () => {
4959
+ // Parse and validate when input loses focus
4960
+ parseAndValidateInput(inputValue);
4961
+ };
4962
+ const handleKeyDown = (e) => {
4963
+ // Parse and validate when Enter is pressed
4964
+ if (e.key === 'Enter') {
4965
+ e.preventDefault();
4966
+ parseAndValidateInput(inputValue);
4967
+ }
4968
+ };
4969
+ const handleDateSelected = ({ date }) => {
4970
+ const formattedDate = dayjs(date).tz(timezone).format(dateFormat);
4971
+ setValue(colLabel, formattedDate, {
4972
+ shouldValidate: true,
4973
+ shouldDirty: true,
4974
+ });
4975
+ setOpen(false);
4976
+ };
4977
+ const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: selectedDateObj, onDateSelected: handleDateSelected, labels: datePickerLabels }));
4720
4978
  return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4721
- 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: () => {
4722
- setOpen(true);
4723
- }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", 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 }) }) }) }))] }) }));
4979
+ 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(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: formI18n.label(), size: "sm" }) }), 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 }) }) }) }))] }) }));
4724
4980
  };
4725
4981
 
4726
4982
  dayjs.extend(utc);
@@ -6452,14 +6708,74 @@ const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem,
6452
6708
  }
6453
6709
  }
6454
6710
  }
6455
- return options;
6711
+ // Sort options by time (convert to 24-hour for proper chronological sorting)
6712
+ return options.sort((a, b) => {
6713
+ // Convert 12-hour to 24-hour for comparison
6714
+ let hour24A = a.hour;
6715
+ if (a.meridiem === 'am' && a.hour === 12)
6716
+ hour24A = 0;
6717
+ else if (a.meridiem === 'pm' && a.hour < 12)
6718
+ hour24A = a.hour + 12;
6719
+ let hour24B = b.hour;
6720
+ if (b.meridiem === 'am' && b.hour === 12)
6721
+ hour24B = 0;
6722
+ else if (b.meridiem === 'pm' && b.hour < 12)
6723
+ hour24B = b.hour + 12;
6724
+ // Compare by hour first, then minute
6725
+ if (hour24A !== hour24B) {
6726
+ return hour24A - hour24B;
6727
+ }
6728
+ return a.minute - b.minute;
6729
+ });
6456
6730
  }, [startTime, selectedDate, timezone]);
6457
- const { contains } = react.useFilter({ sensitivity: 'base' });
6731
+ // itemToString returns only the clean display text (no metadata)
6732
+ const itemToString = React.useMemo(() => {
6733
+ return (item) => {
6734
+ return item.searchText; // Clean display text only
6735
+ };
6736
+ }, []);
6737
+ // Custom filter function that filters by time and supports 24-hour format input
6738
+ const customTimeFilter = React.useMemo(() => {
6739
+ return (itemText, filterText) => {
6740
+ if (!filterText) {
6741
+ return true; // Show all items when no filter
6742
+ }
6743
+ const lowerItemText = itemText.toLowerCase();
6744
+ const lowerFilterText = filterText.toLowerCase();
6745
+ // First, try matching against the display text (12-hour format)
6746
+ if (lowerItemText.includes(lowerFilterText)) {
6747
+ return true;
6748
+ }
6749
+ // Find the corresponding item to check 24-hour format matches
6750
+ const item = timeOptions.find((opt) => opt.searchText.toLowerCase() === lowerItemText);
6751
+ if (!item) {
6752
+ return false;
6753
+ }
6754
+ // Convert item to 24-hour format for matching
6755
+ let hour24 = item.hour;
6756
+ if (item.meridiem === 'am' && item.hour === 12)
6757
+ hour24 = 0;
6758
+ else if (item.meridiem === 'pm' && item.hour < 12)
6759
+ hour24 = item.hour + 12;
6760
+ const hour24Str = hour24.toString().padStart(2, '0');
6761
+ const minuteStr = item.minute.toString().padStart(2, '0');
6762
+ // Check if filterText matches 24-hour format variations
6763
+ const formats = [
6764
+ `${hour24Str}:${minuteStr}`, // "13:30"
6765
+ `${hour24Str}${minuteStr}`, // "1330"
6766
+ hour24Str, // "13"
6767
+ `${hour24}:${minuteStr}`, // "13:30" (without padding)
6768
+ hour24.toString(), // "13" (without padding)
6769
+ ];
6770
+ return formats.some((format) => format.toLowerCase().includes(lowerFilterText) ||
6771
+ lowerFilterText.includes(format.toLowerCase()));
6772
+ };
6773
+ }, [timeOptions]);
6458
6774
  const { collection, filter } = react.useListCollection({
6459
6775
  initialItems: timeOptions,
6460
- itemToString: (item) => item.searchText, // Use searchText (without duration) for filtering
6776
+ itemToString: itemToString,
6461
6777
  itemToValue: (item) => item.value,
6462
- filter: contains,
6778
+ filter: customTimeFilter,
6463
6779
  });
6464
6780
  // Get current value string for combobox
6465
6781
  const currentValue = React.useMemo(() => {
@@ -6549,6 +6865,47 @@ const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem,
6549
6865
  if (!trimmedValue) {
6550
6866
  return;
6551
6867
  }
6868
+ // Parse 24-hour format first (e.g., "13:30", "14:00", "1330", "1400", "9:05", "905")
6869
+ const timePattern24Hour = /^(\d{1,2}):?(\d{2})$/;
6870
+ const match24Hour = trimmedValue.match(timePattern24Hour);
6871
+ if (match24Hour) {
6872
+ const parsedHour24 = parseInt(match24Hour[1], 10);
6873
+ const parsedMinute = parseInt(match24Hour[2], 10);
6874
+ // Validate 24-hour format ranges
6875
+ if (parsedHour24 >= 0 &&
6876
+ parsedHour24 <= 23 &&
6877
+ parsedMinute >= 0 &&
6878
+ parsedMinute <= 59) {
6879
+ // Convert 24-hour to 12-hour format
6880
+ let hour12;
6881
+ let meridiem;
6882
+ if (parsedHour24 === 0) {
6883
+ hour12 = 12;
6884
+ meridiem = 'am';
6885
+ }
6886
+ else if (parsedHour24 === 12) {
6887
+ hour12 = 12;
6888
+ meridiem = 'pm';
6889
+ }
6890
+ else if (parsedHour24 > 12) {
6891
+ hour12 = parsedHour24 - 12;
6892
+ meridiem = 'pm';
6893
+ }
6894
+ else {
6895
+ hour12 = parsedHour24;
6896
+ meridiem = 'am';
6897
+ }
6898
+ setHour(hour12);
6899
+ setMinute(parsedMinute);
6900
+ setMeridiem(meridiem);
6901
+ onChange({
6902
+ hour: hour12,
6903
+ minute: parsedMinute,
6904
+ meridiem: meridiem,
6905
+ });
6906
+ return;
6907
+ }
6908
+ }
6552
6909
  // Parse formats like "1:30 PM", "1:30PM", "1:30 pm", "1:30pm"
6553
6910
  const timePattern12Hour = /^(\d{1,2}):(\d{1,2})\s*(am|pm|AM|PM)$/i;
6554
6911
  const match12Hour = trimmedValue.match(timePattern12Hour);
@@ -6714,133 +7071,6 @@ const TimePicker = ({ column, schema, prefix }) => {
6714
7071
  }, 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, labels: timePickerLabels }) }) }) })) : (jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { children: jsxRuntime.jsx(react.Popover.Body, { children: jsxRuntime.jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, labels: timePickerLabels }) }) }) }) }))] }) }));
6715
7072
  };
6716
7073
 
6717
- dayjs.extend(utc);
6718
- dayjs.extend(timezone);
6719
- dayjs.extend(customParseFormat);
6720
- function DatePickerInput({ value, onChange, placeholder = 'Select a date', dateFormat = 'YYYY-MM-DD', displayFormat = 'YYYY-MM-DD', labels = {
6721
- monthNamesShort: [
6722
- 'Jan',
6723
- 'Feb',
6724
- 'Mar',
6725
- 'Apr',
6726
- 'May',
6727
- 'Jun',
6728
- 'Jul',
6729
- 'Aug',
6730
- 'Sep',
6731
- 'Oct',
6732
- 'Nov',
6733
- 'Dec',
6734
- ],
6735
- weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
6736
- backButtonLabel: 'Back',
6737
- forwardButtonLabel: 'Next',
6738
- }, timezone = 'Asia/Hong_Kong', minDate, maxDate, firstDayOfWeek, showOutsideDays, monthsToDisplay = 1, insideDialog = false, readOnly = false, }) {
6739
- const [open, setOpen] = React.useState(false);
6740
- const [inputValue, setInputValue] = React.useState('');
6741
- // Update input value when prop value changes
6742
- React.useEffect(() => {
6743
- if (value) {
6744
- const formatted = typeof value === 'string'
6745
- ? dayjs(value).tz(timezone).isValid()
6746
- ? dayjs(value).tz(timezone).format(displayFormat)
6747
- : ''
6748
- : dayjs(value).tz(timezone).format(displayFormat);
6749
- setInputValue(formatted);
6750
- }
6751
- else {
6752
- setInputValue('');
6753
- }
6754
- }, [value, displayFormat, timezone]);
6755
- // Convert value to Date object for DatePicker
6756
- const selectedDate = value
6757
- ? typeof value === 'string'
6758
- ? dayjs(value).tz(timezone).isValid()
6759
- ? dayjs(value).tz(timezone).toDate()
6760
- : new Date()
6761
- : value
6762
- : new Date();
6763
- // Shared function to parse and validate input value
6764
- const parseAndValidateInput = (inputVal) => {
6765
- // If empty, clear the value
6766
- if (!inputVal.trim()) {
6767
- onChange?.(undefined);
6768
- setInputValue('');
6769
- return;
6770
- }
6771
- // Try parsing with displayFormat first
6772
- let parsedDate = dayjs(inputVal, displayFormat, true);
6773
- // If that fails, try common date formats
6774
- if (!parsedDate.isValid()) {
6775
- parsedDate = dayjs(inputVal);
6776
- }
6777
- // If still invalid, try parsing with dateFormat
6778
- if (!parsedDate.isValid()) {
6779
- parsedDate = dayjs(inputVal, dateFormat, true);
6780
- }
6781
- // If valid, check constraints and update
6782
- if (parsedDate.isValid()) {
6783
- const dateObj = parsedDate.tz(timezone).toDate();
6784
- // Check min/max constraints
6785
- if (minDate && dateObj < minDate) {
6786
- // Invalid: before minDate, reset to prop value
6787
- resetToPropValue();
6788
- return;
6789
- }
6790
- if (maxDate && dateObj > maxDate) {
6791
- // Invalid: after maxDate, reset to prop value
6792
- resetToPropValue();
6793
- return;
6794
- }
6795
- // Valid date - format and update
6796
- const formattedDate = parsedDate.tz(timezone).format(dateFormat);
6797
- const formattedDisplay = parsedDate.tz(timezone).format(displayFormat);
6798
- onChange?.(formattedDate);
6799
- setInputValue(formattedDisplay);
6800
- }
6801
- else {
6802
- // Invalid date - reset to prop value
6803
- resetToPropValue();
6804
- }
6805
- };
6806
- // Helper function to reset input to prop value
6807
- const resetToPropValue = () => {
6808
- if (value) {
6809
- const formatted = typeof value === 'string'
6810
- ? dayjs(value).tz(timezone).isValid()
6811
- ? dayjs(value).tz(timezone).format(displayFormat)
6812
- : ''
6813
- : dayjs(value).tz(timezone).format(displayFormat);
6814
- setInputValue(formatted);
6815
- }
6816
- else {
6817
- setInputValue('');
6818
- }
6819
- };
6820
- const handleInputChange = (e) => {
6821
- // Only update the input value, don't parse yet
6822
- setInputValue(e.target.value);
6823
- };
6824
- const handleInputBlur = () => {
6825
- // Parse and validate when input loses focus
6826
- parseAndValidateInput(inputValue);
6827
- };
6828
- const handleKeyDown = (e) => {
6829
- // Parse and validate when Enter is pressed
6830
- if (e.key === 'Enter') {
6831
- e.preventDefault();
6832
- parseAndValidateInput(inputValue);
6833
- }
6834
- };
6835
- const handleDateSelected = ({ date }) => {
6836
- const formattedDate = dayjs(date).tz(timezone).format(dateFormat);
6837
- onChange?.(formattedDate);
6838
- setOpen(false);
6839
- };
6840
- const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: selectedDate, onDateSelected: handleDateSelected, labels: labels, minDate: minDate, maxDate: maxDate, firstDayOfWeek: firstDayOfWeek, showOutsideDays: showOutsideDays, monthsToDisplay: monthsToDisplay }));
6841
- 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 }) }) }) }))] }));
6842
- }
6843
-
6844
7074
  dayjs.extend(utc);
6845
7075
  dayjs.extend(timezone);
6846
7076
  function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
@@ -7084,7 +7314,20 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
7084
7314
  });
7085
7315
  }
7086
7316
  };
7317
+ const [inputValue, setInputValue] = React.useState('');
7318
+ // Sync inputValue with currentValue when time changes externally
7319
+ React.useEffect(() => {
7320
+ if (hour !== null && minute !== null && second !== null) {
7321
+ const formattedValue = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}`;
7322
+ setInputValue(formattedValue);
7323
+ }
7324
+ else {
7325
+ setInputValue('');
7326
+ }
7327
+ }, [hour, minute, second]);
7087
7328
  const handleInputValueChange = (details) => {
7329
+ // Update local input value state
7330
+ setInputValue(details.inputValue);
7088
7331
  // Filter the collection based on input, but don't parse yet
7089
7332
  filter(details.inputValue);
7090
7333
  };
@@ -7094,24 +7337,26 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
7094
7337
  };
7095
7338
  const handleBlur = (e) => {
7096
7339
  // Parse and commit the input value when losing focus
7097
- const inputValue = e.target.value;
7098
- if (inputValue) {
7099
- parseAndCommitInput(inputValue);
7340
+ const inputVal = e.target.value;
7341
+ setInputValue(inputVal);
7342
+ if (inputVal) {
7343
+ parseAndCommitInput(inputVal);
7100
7344
  }
7101
7345
  };
7102
7346
  const handleKeyDown = (e) => {
7103
7347
  // Commit input on Enter key
7104
7348
  if (e.key === 'Enter') {
7105
7349
  e.preventDefault();
7106
- const inputValue = e.currentTarget.value;
7107
- if (inputValue) {
7108
- parseAndCommitInput(inputValue);
7350
+ const inputVal = e.currentTarget.value;
7351
+ setInputValue(inputVal);
7352
+ if (inputVal) {
7353
+ parseAndCommitInput(inputVal);
7109
7354
  }
7110
7355
  // Blur the input
7111
7356
  e.currentTarget?.blur();
7112
7357
  }
7113
7358
  };
7114
- 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: labels.placeholder, 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: labels.emptyMessage }), 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, {}) }) })] }) }));
7359
+ 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, { value: inputValue, placeholder: labels.placeholder, 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: labels.emptyMessage }), 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, {}) }) })] }) }));
7115
7360
  }
7116
7361
 
7117
7362
  dayjs.extend(utc);
@@ -7134,7 +7379,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7134
7379
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
7135
7380
  backButtonLabel: 'Back',
7136
7381
  forwardButtonLabel: 'Next',
7137
- }, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
7382
+ }, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, defaultDate, defaultTime, }) {
7138
7383
  console.log('[DateTimePicker] Component initialized with props:', {
7139
7384
  value,
7140
7385
  format,
@@ -7209,13 +7454,77 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7209
7454
  value,
7210
7455
  initialTime,
7211
7456
  });
7457
+ // Normalize startTime to ignore milliseconds (needed for effectiveDefaultDate calculation)
7458
+ const normalizedStartTime = startTime
7459
+ ? dayjs(startTime).tz(timezone).millisecond(0).toISOString()
7460
+ : undefined;
7461
+ // Calculate effective defaultDate: use prop if provided, otherwise use startTime date, otherwise use today
7462
+ const effectiveDefaultDate = React.useMemo(() => {
7463
+ if (defaultDate) {
7464
+ return defaultDate;
7465
+ }
7466
+ if (normalizedStartTime &&
7467
+ dayjs(normalizedStartTime).tz(timezone).isValid()) {
7468
+ return dayjs(normalizedStartTime).tz(timezone).format('YYYY-MM-DD');
7469
+ }
7470
+ return dayjs().tz(timezone).format('YYYY-MM-DD');
7471
+ }, [defaultDate, normalizedStartTime, timezone]);
7472
+ // Initialize time with default values if no value is provided
7473
+ const getInitialTimeValues = () => {
7474
+ if (value && initialTime.hour12 !== null) {
7475
+ return initialTime;
7476
+ }
7477
+ // If no value or no time in value, use defaultTime or 00:00
7478
+ if (defaultTime) {
7479
+ if (format === 'iso-date-time') {
7480
+ const defaultTime24 = defaultTime;
7481
+ return {
7482
+ hour12: null,
7483
+ minute: defaultTime24.minute ?? 0,
7484
+ meridiem: null,
7485
+ hour24: defaultTime24.hour ?? 0,
7486
+ second: showSeconds ? defaultTime24.second ?? 0 : null,
7487
+ };
7488
+ }
7489
+ else {
7490
+ const defaultTime12 = defaultTime;
7491
+ return {
7492
+ hour12: defaultTime12.hour ?? 12,
7493
+ minute: defaultTime12.minute ?? 0,
7494
+ meridiem: defaultTime12.meridiem ?? 'am',
7495
+ hour24: null,
7496
+ second: null,
7497
+ };
7498
+ }
7499
+ }
7500
+ // Default to 00:00
7501
+ if (format === 'iso-date-time') {
7502
+ return {
7503
+ hour12: null,
7504
+ minute: 0,
7505
+ meridiem: null,
7506
+ hour24: 0,
7507
+ second: showSeconds ? 0 : null,
7508
+ };
7509
+ }
7510
+ else {
7511
+ return {
7512
+ hour12: 12,
7513
+ minute: 0,
7514
+ meridiem: 'am',
7515
+ hour24: null,
7516
+ second: null,
7517
+ };
7518
+ }
7519
+ };
7520
+ const initialTimeValues = getInitialTimeValues();
7212
7521
  // Time state for 12-hour format
7213
- const [hour12, setHour12] = React.useState(initialTime.hour12);
7214
- const [minute, setMinute] = React.useState(initialTime.minute);
7215
- const [meridiem, setMeridiem] = React.useState(initialTime.meridiem);
7522
+ const [hour12, setHour12] = React.useState(initialTimeValues.hour12);
7523
+ const [minute, setMinute] = React.useState(initialTimeValues.minute);
7524
+ const [meridiem, setMeridiem] = React.useState(initialTimeValues.meridiem);
7216
7525
  // Time state for 24-hour format
7217
- const [hour24, setHour24] = React.useState(initialTime.hour24);
7218
- const [second, setSecond] = React.useState(initialTime.second);
7526
+ const [hour24, setHour24] = React.useState(initialTimeValues.hour24);
7527
+ const [second, setSecond] = React.useState(initialTimeValues.second);
7219
7528
  // Sync selectedDate and time states when value prop changes
7220
7529
  React.useEffect(() => {
7221
7530
  console.log('[DateTimePicker] useEffect triggered - value changed:', {
@@ -7223,27 +7532,47 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7223
7532
  timezone,
7224
7533
  format,
7225
7534
  });
7226
- // If value is null, undefined, or invalid, clear all fields
7535
+ // If value is null, undefined, or invalid, clear date but keep default time values
7227
7536
  if (!value || value === null || value === undefined) {
7228
- console.log('[DateTimePicker] Value is null/undefined, clearing all fields');
7537
+ console.log('[DateTimePicker] Value is null/undefined, clearing date but keeping default time');
7229
7538
  setSelectedDate('');
7230
- setHour12(null);
7231
- setMinute(null);
7232
- setMeridiem(null);
7233
- setHour24(null);
7234
- setSecond(null);
7539
+ // Keep default time values instead of clearing them
7540
+ if (format === 'iso-date-time') {
7541
+ setHour24(defaultTime ? defaultTime.hour ?? 0 : 0);
7542
+ setMinute(defaultTime ? defaultTime.minute ?? 0 : 0);
7543
+ setSecond(showSeconds
7544
+ ? defaultTime
7545
+ ? defaultTime.second ?? 0
7546
+ : 0
7547
+ : null);
7548
+ }
7549
+ else {
7550
+ setHour12(defaultTime ? defaultTime.hour ?? 12 : 12);
7551
+ setMinute(defaultTime ? defaultTime.minute ?? 0 : 0);
7552
+ setMeridiem(defaultTime ? defaultTime.meridiem ?? 'am' : 'am');
7553
+ }
7235
7554
  return;
7236
7555
  }
7237
7556
  // Check if value is valid
7238
7557
  const dateObj = dayjs(value).tz(timezone);
7239
7558
  if (!dateObj.isValid()) {
7240
- console.log('[DateTimePicker] Invalid value, clearing all fields');
7559
+ console.log('[DateTimePicker] Invalid value, clearing date but keeping default time');
7241
7560
  setSelectedDate('');
7242
- setHour12(null);
7243
- setMinute(null);
7244
- setMeridiem(null);
7245
- setHour24(null);
7246
- setSecond(null);
7561
+ // Keep default time values instead of clearing them
7562
+ if (format === 'iso-date-time') {
7563
+ setHour24(defaultTime ? defaultTime.hour ?? 0 : 0);
7564
+ setMinute(defaultTime ? defaultTime.minute ?? 0 : 0);
7565
+ setSecond(showSeconds
7566
+ ? defaultTime
7567
+ ? defaultTime.second ?? 0
7568
+ : 0
7569
+ : null);
7570
+ }
7571
+ else {
7572
+ setHour12(defaultTime ? defaultTime.hour ?? 12 : 12);
7573
+ setMinute(defaultTime ? defaultTime.minute ?? 0 : 0);
7574
+ setMeridiem(defaultTime ? defaultTime.meridiem ?? 'am' : 'am');
7575
+ }
7247
7576
  return;
7248
7577
  }
7249
7578
  const dateString = getDateString(value);
@@ -7299,16 +7628,76 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7299
7628
  onChange?.(undefined);
7300
7629
  return;
7301
7630
  }
7631
+ // Check if time values are null - if so, use defaultTime or set to 00:00
7632
+ const hasTimeValues = format === 'iso-date-time'
7633
+ ? hour24 !== null || minute !== null
7634
+ : hour12 !== null || minute !== null || meridiem !== null;
7635
+ let timeDataToUse = undefined;
7636
+ if (!hasTimeValues) {
7637
+ // Use defaultTime if provided, otherwise default to 00:00
7638
+ if (defaultTime) {
7639
+ console.log('[DateTimePicker] No time values set, using defaultTime');
7640
+ if (format === 'iso-date-time') {
7641
+ const defaultTime24 = defaultTime;
7642
+ setHour24(defaultTime24.hour ?? 0);
7643
+ setMinute(defaultTime24.minute ?? 0);
7644
+ if (showSeconds) {
7645
+ setSecond(defaultTime24.second ?? 0);
7646
+ }
7647
+ timeDataToUse = {
7648
+ hour: defaultTime24.hour ?? 0,
7649
+ minute: defaultTime24.minute ?? 0,
7650
+ second: showSeconds ? defaultTime24.second ?? 0 : undefined,
7651
+ };
7652
+ }
7653
+ else {
7654
+ const defaultTime12 = defaultTime;
7655
+ setHour12(defaultTime12.hour ?? 12);
7656
+ setMinute(defaultTime12.minute ?? 0);
7657
+ setMeridiem(defaultTime12.meridiem ?? 'am');
7658
+ timeDataToUse = {
7659
+ hour: defaultTime12.hour ?? 12,
7660
+ minute: defaultTime12.minute ?? 0,
7661
+ meridiem: defaultTime12.meridiem ?? 'am',
7662
+ };
7663
+ }
7664
+ }
7665
+ else {
7666
+ console.log('[DateTimePicker] No time values set, defaulting to 00:00');
7667
+ if (format === 'iso-date-time') {
7668
+ setHour24(0);
7669
+ setMinute(0);
7670
+ if (showSeconds) {
7671
+ setSecond(0);
7672
+ }
7673
+ timeDataToUse = {
7674
+ hour: 0,
7675
+ minute: 0,
7676
+ second: showSeconds ? 0 : undefined,
7677
+ };
7678
+ }
7679
+ else {
7680
+ setHour12(12);
7681
+ setMinute(0);
7682
+ setMeridiem('am');
7683
+ timeDataToUse = {
7684
+ hour: 12,
7685
+ minute: 0,
7686
+ meridiem: 'am',
7687
+ };
7688
+ }
7689
+ }
7690
+ }
7302
7691
  // When showSeconds is false, ignore seconds from the date
7303
7692
  if (!showSeconds) {
7304
7693
  const dateWithoutSeconds = dateObj.second(0).millisecond(0).toISOString();
7305
7694
  console.log('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
7306
- updateDateTime(dateWithoutSeconds);
7695
+ updateDateTime(dateWithoutSeconds, timeDataToUse);
7307
7696
  }
7308
7697
  else {
7309
7698
  const dateWithSeconds = dateObj.toISOString();
7310
7699
  console.log('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
7311
- updateDateTime(dateWithSeconds);
7700
+ updateDateTime(dateWithSeconds, timeDataToUse);
7312
7701
  }
7313
7702
  };
7314
7703
  const handleTimeChange = (timeData) => {
@@ -7338,17 +7727,36 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7338
7727
  setMinute(data.minute);
7339
7728
  setMeridiem(data.meridiem);
7340
7729
  }
7341
- // Use selectedDate if valid, otherwise clear all fields
7730
+ // Use selectedDate if valid, otherwise use effectiveDefaultDate or clear all fields
7342
7731
  if (!selectedDate || !dayjs(selectedDate).isValid()) {
7343
- console.log('[DateTimePicker] No valid selectedDate, clearing all fields');
7344
- setSelectedDate('');
7345
- setHour12(null);
7346
- setMinute(null);
7347
- setMeridiem(null);
7348
- setHour24(null);
7349
- setSecond(null);
7350
- onChange?.(undefined);
7351
- return;
7732
+ // If effectiveDefaultDate is available, use it instead of clearing
7733
+ if (effectiveDefaultDate && dayjs(effectiveDefaultDate).isValid()) {
7734
+ console.log('[DateTimePicker] No valid selectedDate, using effectiveDefaultDate:', effectiveDefaultDate);
7735
+ setSelectedDate(effectiveDefaultDate);
7736
+ const dateObj = dayjs(effectiveDefaultDate).tz(timezone);
7737
+ if (dateObj.isValid()) {
7738
+ updateDateTime(dateObj.toISOString(), timeData);
7739
+ }
7740
+ else {
7741
+ console.warn('[DateTimePicker] Invalid effectiveDefaultDate, clearing fields');
7742
+ setSelectedDate('');
7743
+ setHour12(null);
7744
+ setMinute(null);
7745
+ setMeridiem(null);
7746
+ setHour24(null);
7747
+ setSecond(null);
7748
+ onChange?.(undefined);
7749
+ }
7750
+ return;
7751
+ }
7752
+ else {
7753
+ console.log('[DateTimePicker] No valid selectedDate and no effectiveDefaultDate, keeping time values but no date');
7754
+ // Keep the time values that were just set, but don't set a date
7755
+ // This should rarely happen as effectiveDefaultDate always defaults to today
7756
+ setSelectedDate('');
7757
+ onChange?.(undefined);
7758
+ return;
7759
+ }
7352
7760
  }
7353
7761
  const dateObj = dayjs(selectedDate).tz(timezone);
7354
7762
  if (dateObj.isValid()) {
@@ -7491,18 +7899,24 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7491
7899
  };
7492
7900
  const handleClear = () => {
7493
7901
  setSelectedDate('');
7494
- setHour12(null);
7495
- setHour24(null);
7496
- setMinute(null);
7497
- setSecond(null);
7498
- setMeridiem(null);
7902
+ // Reset to default time values instead of clearing them
7903
+ if (format === 'iso-date-time') {
7904
+ setHour24(defaultTime ? defaultTime.hour ?? 0 : 0);
7905
+ setMinute(defaultTime ? defaultTime.minute ?? 0 : 0);
7906
+ setSecond(showSeconds
7907
+ ? defaultTime
7908
+ ? defaultTime.second ?? 0
7909
+ : 0
7910
+ : null);
7911
+ }
7912
+ else {
7913
+ setHour12(defaultTime ? defaultTime.hour ?? 12 : 12);
7914
+ setMinute(defaultTime ? defaultTime.minute ?? 0 : 0);
7915
+ setMeridiem(defaultTime ? defaultTime.meridiem ?? 'am' : 'am');
7916
+ }
7499
7917
  onChange?.(undefined);
7500
7918
  };
7501
7919
  const isISO = format === 'iso-date-time';
7502
- // Normalize startTime to ignore milliseconds
7503
- const normalizedStartTime = startTime
7504
- ? dayjs(startTime).tz(timezone).millisecond(0).toISOString()
7505
- : undefined;
7506
7920
  // Determine minDate: prioritize explicit minDate prop, then fall back to startTime
7507
7921
  const effectiveMinDate = minDate
7508
7922
  ? minDate
@@ -7580,7 +7994,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7580
7994
  const dateObj = dayjs.tz(selectedDate, timezone);
7581
7995
  return dateObj.isValid() ? dateObj.format('Z') : null;
7582
7996
  }, [selectedDate, timezone]);
7583
- return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 4, children: [jsxRuntime.jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
7997
+ return (jsxRuntime.jsxs(react.Flex, { direction: "column", gap: 2, children: [jsxRuntime.jsx(DatePickerInput, { value: selectedDate || undefined, onChange: (date) => {
7584
7998
  if (date) {
7585
7999
  handleDateChange(date);
7586
8000
  }
@@ -7588,7 +8002,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7588
8002
  setSelectedDate('');
7589
8003
  onChange?.(undefined);
7590
8004
  }
7591
- }, 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, labels: timePickerLabels })) : (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, labels: timePickerLabels })), 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 })] }))] }));
8005
+ }, placeholder: "Select a date", dateFormat: "YYYY-MM-DD", displayFormat: "YYYY-MM-DD", labels: labels, timezone: timezone, minDate: effectiveMinDate, maxDate: maxDate, monthsToDisplay: 1, readOnly: false }), jsxRuntime.jsxs(react.Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 2, 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, labels: timePickerLabels })) : (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, labels: timePickerLabels })), 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 })] }))] }));
7592
8006
  }
7593
8007
 
7594
8008
  dayjs.extend(utc);
@@ -7650,7 +8064,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
7650
8064
  return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7651
8065
  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: () => {
7652
8066
  setOpen(true);
7653
- }, 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 }) }) }) }))] }) }));
8067
+ }, justifyContent: 'start', children: [jsxRuntime.jsx(md.MdDateRange, {}), displayDate || ''] }) }), insideDialog ? (jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { width: "fit-content", minW: "350px", minH: "10rem", 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: "350px", minH: "10rem", children: jsxRuntime.jsx(react.Popover.Body, { children: dateTimePickerContent }) }) }) }))] }) }));
7654
8068
  };
7655
8069
 
7656
8070
  const SchemaRenderer = ({ schema, prefix, column, }) => {