@bsol-oss/react-datatable5 13.0.1-beta.3 → 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) {
@@ -4146,6 +4146,22 @@ const convertAjvErrorsToFieldErrors = (errors, schema) => {
4146
4146
  // Get the schema node for this field to check for custom error messages
4147
4147
  const fieldSchema = getSchemaNodeForField(schema, fieldName);
4148
4148
  const customMessage = fieldSchema?.errorMessages?.[error.keyword];
4149
+ // Debug log when error message is missing
4150
+ if (!customMessage) {
4151
+ console.debug(`[Form Validation] Missing error message for field '${fieldName}' with keyword '${error.keyword}'. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`, {
4152
+ fieldName,
4153
+ keyword: error.keyword,
4154
+ instancePath: error.instancePath,
4155
+ schemaPath: error.schemaPath,
4156
+ params: error.params,
4157
+ fieldSchema: fieldSchema
4158
+ ? {
4159
+ type: fieldSchema.type,
4160
+ errorMessages: fieldSchema.errorMessages,
4161
+ }
4162
+ : undefined,
4163
+ });
4164
+ }
4149
4165
  // Provide helpful fallback message if no custom message is provided
4150
4166
  const fallbackMessage = customMessage ||
4151
4167
  `Missing error message for ${error.keyword}. Add errorMessages.${error.keyword} to schema for field '${fieldName}'`;
@@ -4388,7 +4404,7 @@ function removeIndex(str) {
4388
4404
  *
4389
4405
  * @param column - The column name
4390
4406
  * @param prefix - The prefix for the field (usually empty string or parent path)
4391
- * @param schema - Optional schema object with title property
4407
+ * @param schema - Required schema object with title property
4392
4408
  * @returns Object with label helper functions
4393
4409
  *
4394
4410
  * @example
@@ -4421,9 +4437,21 @@ const useFormI18n = (column, prefix = '', schema) => {
4421
4437
  * Uses schema.title if available, otherwise: translate.t(removeIndex(`${colLabel}.field_label`))
4422
4438
  */
4423
4439
  label: (options) => {
4424
- if (schema?.title) {
4440
+ if (schema.title) {
4425
4441
  return schema.title;
4426
4442
  }
4443
+ // Debug log when field title is missing
4444
+ console.debug(`[Form Field Label] Missing title for field '${colLabel}'. Add title property to schema for field '${colLabel}'.`, {
4445
+ fieldName: column,
4446
+ colLabel,
4447
+ prefix,
4448
+ schema: {
4449
+ type: schema.type,
4450
+ errorMessages: schema.errorMessages
4451
+ ? Object.keys(schema.errorMessages)
4452
+ : undefined,
4453
+ },
4454
+ });
4427
4455
  return translate.t(removeIndex(`${colLabel}.field_label`), options);
4428
4456
  },
4429
4457
  /**
@@ -4517,6 +4545,9 @@ const CustomInput = ({ column, schema, prefix }) => {
4517
4545
  }));
4518
4546
  };
4519
4547
 
4548
+ dayjs.extend(utc);
4549
+ dayjs.extend(timezone);
4550
+ dayjs.extend(customParseFormat);
4520
4551
  const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
4521
4552
  const { labels } = React.useContext(DatePickerContext);
4522
4553
  const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel, } = labels;
@@ -4586,6 +4617,9 @@ const DatePickerContext = React.createContext({
4586
4617
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4587
4618
  backButtonLabel: 'Back',
4588
4619
  forwardButtonLabel: 'Next',
4620
+ todayLabel: 'Today',
4621
+ yesterdayLabel: 'Yesterday',
4622
+ tomorrowLabel: 'Tomorrow',
4589
4623
  },
4590
4624
  });
4591
4625
  const DatePicker$1 = ({ labels = {
@@ -4606,6 +4640,9 @@ const DatePicker$1 = ({ labels = {
4606
4640
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4607
4641
  backButtonLabel: 'Back',
4608
4642
  forwardButtonLabel: 'Next',
4643
+ todayLabel: 'Today',
4644
+ yesterdayLabel: 'Yesterday',
4645
+ tomorrowLabel: 'Tomorrow',
4609
4646
  }, onDateSelected, selected, firstDayOfWeek, showOutsideDays, date, minDate, maxDate, monthsToDisplay, render, }) => {
4610
4647
  const calendarData = useCalendar({
4611
4648
  onDateSelected,
@@ -4620,9 +4657,164 @@ const DatePicker$1 = ({ labels = {
4620
4657
  return (jsxRuntime.jsx(DatePickerContext.Provider, { value: { labels }, children: render ? (render(calendarData)) : (jsxRuntime.jsx(Calendar, { ...calendarData,
4621
4658
  firstDayOfWeek })) }));
4622
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
+ }
4623
4814
 
4624
4815
  dayjs.extend(utc);
4625
4816
  dayjs.extend(timezone);
4817
+ dayjs.extend(customParseFormat);
4626
4818
  const DatePicker = ({ column, schema, prefix }) => {
4627
4819
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4628
4820
  const { timezone, dateTimePickerLabels, insideDialog } = useSchemaContext();
@@ -4631,15 +4823,29 @@ const DatePicker = ({ column, schema, prefix }) => {
4631
4823
  const isRequired = required?.some((columnId) => columnId === column);
4632
4824
  const colLabel = formI18n.colLabel;
4633
4825
  const [open, setOpen] = React.useState(false);
4826
+ const [inputValue, setInputValue] = React.useState('');
4634
4827
  const selectedDate = watch(colLabel);
4635
- const displayDate = dayjs(selectedDate)
4636
- .tz(timezone)
4637
- .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
4638
4845
  React.useEffect(() => {
4639
4846
  try {
4640
4847
  if (selectedDate) {
4641
4848
  // Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
4642
- // For example, parse as UTC:
4643
4849
  const parsedDate = dayjs(selectedDate).tz(timezone);
4644
4850
  if (!parsedDate.isValid())
4645
4851
  return;
@@ -4657,7 +4863,7 @@ const DatePicker = ({ column, schema, prefix }) => {
4657
4863
  catch (e) {
4658
4864
  console.error(e);
4659
4865
  }
4660
- }, [selectedDate, dateFormat, colLabel, setValue]);
4866
+ }, [selectedDate, dateFormat, colLabel, setValue, timezone]);
4661
4867
  const datePickerLabels = {
4662
4868
  monthNamesShort: dateTimePickerLabels?.monthNamesShort ?? [
4663
4869
  'January',
@@ -4685,14 +4891,92 @@ const DatePicker = ({ column, schema, prefix }) => {
4685
4891
  backButtonLabel: dateTimePickerLabels?.backButtonLabel ?? 'Back',
4686
4892
  forwardButtonLabel: dateTimePickerLabels?.forwardButtonLabel ?? 'Forward',
4687
4893
  };
4688
- const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
4689
- setValue(colLabel, dayjs(date).format(dateFormat));
4690
- setOpen(false);
4691
- }, 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 }));
4692
4978
  return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
4693
- 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: () => {
4694
- setOpen(true);
4695
- }, 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 }) }) }) }))] }) }));
4696
4980
  };
4697
4981
 
4698
4982
  dayjs.extend(utc);
@@ -4700,7 +4984,7 @@ dayjs.extend(timezone);
4700
4984
  const DateRangePicker = ({ column, schema, prefix, }) => {
4701
4985
  const { watch, formState: { errors }, setValue, } = reactHookForm.useFormContext();
4702
4986
  const { timezone, insideDialog } = useSchemaContext();
4703
- const formI18n = useFormI18n(column, prefix);
4987
+ const formI18n = useFormI18n(column, prefix, schema);
4704
4988
  const { required, gridColumn = 'span 12', gridRow = 'span 1', displayDateFormat = 'YYYY-MM-DD', dateFormat = 'YYYY-MM-DD', } = schema;
4705
4989
  const isRequired = required?.some((columnId) => columnId === column);
4706
4990
  const colLabel = formI18n.colLabel;
@@ -5345,7 +5629,7 @@ const MediaLibraryBrowser = ({ onFetchFiles, filterImageOnly = false, labels, en
5345
5629
  }) })) }))] }));
5346
5630
  };
5347
5631
 
5348
- function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, colLabel, }) {
5632
+ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly = false, onFetchFiles, onUploadFile, enableUpload = false, labels, }) {
5349
5633
  const [selectedFile, setSelectedFile] = React.useState(undefined);
5350
5634
  const [activeTab, setActiveTab] = React.useState('browse');
5351
5635
  const [uploadingFiles, setUploadingFiles] = React.useState(new Set());
@@ -5429,7 +5713,7 @@ function MediaBrowserDialog({ open, onClose, onSelect, title, filterImageOnly =
5429
5713
  const FilePicker = ({ column, schema, prefix }) => {
5430
5714
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
5431
5715
  const { filePickerLabels } = useSchemaContext();
5432
- const formI18n = useFormI18n(column, prefix);
5716
+ const formI18n = useFormI18n(column, prefix, schema);
5433
5717
  const { required, gridColumn = 'span 12', gridRow = 'span 1', type, } = schema;
5434
5718
  const isRequired = required?.some((columnId) => columnId === column);
5435
5719
  const isSingleSelect = type === 'string';
@@ -5505,7 +5789,7 @@ const FilePicker = ({ column, schema, prefix }) => {
5505
5789
  const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5506
5790
  const { setValue, formState: { errors }, watch, } = reactHookForm.useFormContext();
5507
5791
  const { filePickerLabels } = useSchemaContext();
5508
- const formI18n = useFormI18n(column, prefix);
5792
+ const formI18n = useFormI18n(column, prefix, schema);
5509
5793
  const { required, gridColumn = 'span 12', gridRow = 'span 1', filePicker, type, } = schema;
5510
5794
  const isRequired = required?.some((columnId) => columnId === column);
5511
5795
  const isSingleSelect = type === 'string';
@@ -5600,9 +5884,7 @@ const FormMediaLibraryBrowser = ({ column, schema, prefix, }) => {
5600
5884
  return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
5601
5885
  gridRow, errorText: errors[`${colLabel}`] ? formI18n.required() : undefined, invalid: !!errors[colLabel], children: [jsxRuntime.jsx(react.VStack, { align: "stretch", gap: 2, children: jsxRuntime.jsx(react.Button, { variant: "outline", onClick: () => setDialogOpen(true), borderColor: "border.default", bg: "bg.panel", _hover: { bg: 'bg.muted' }, children: filePickerLabels?.browseLibrary ??
5602
5886
  formI18n.t('browse_library') ??
5603
- 'Browse from Library' }) }), jsxRuntime.jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ??
5604
- filePickerLabels?.dialogTitle ??
5605
- 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
5887
+ 'Browse from Library' }) }), jsxRuntime.jsx(MediaBrowserDialog, { open: dialogOpen, onClose: () => setDialogOpen(false), onSelect: handleMediaLibrarySelect, title: filePickerLabels?.dialogTitle ?? formI18n.label() ?? 'Select File', filterImageOnly: filterImageOnly, onFetchFiles: onFetchFiles, onUploadFile: onUploadFile, enableUpload: enableUpload, labels: filePickerLabels, colLabel: colLabel }), jsxRuntime.jsx(react.Flex, { flexFlow: 'column', gap: 1, children: currentFileIds.map((fileId, index) => {
5606
5888
  const file = fileMap.get(fileId);
5607
5889
  const isImage = file
5608
5890
  ? /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i.test(file.name)
@@ -5693,7 +5975,8 @@ const useIdPickerData = ({ column, schema, prefix, isMultiple, }) => {
5693
5975
  }
5694
5976
  // Use schema's loadInitialValues (required for id-picker)
5695
5977
  if (!loadInitialValues) {
5696
- throw new Error(`loadInitialValues is required in schema for IdPicker field '${column}'.`);
5978
+ console.warn(`loadInitialValues is required in schema for IdPicker field '${column}'. Returning empty idMap.`);
5979
+ return { data: [], count: 0 };
5697
5980
  }
5698
5981
  const result = await loadInitialValues({
5699
5982
  ids: missingIds,
@@ -6425,14 +6708,74 @@ const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem,
6425
6708
  }
6426
6709
  }
6427
6710
  }
6428
- 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
+ });
6429
6730
  }, [startTime, selectedDate, timezone]);
6430
- 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]);
6431
6774
  const { collection, filter } = react.useListCollection({
6432
6775
  initialItems: timeOptions,
6433
- itemToString: (item) => item.searchText, // Use searchText (without duration) for filtering
6776
+ itemToString: itemToString,
6434
6777
  itemToValue: (item) => item.value,
6435
- filter: contains,
6778
+ filter: customTimeFilter,
6436
6779
  });
6437
6780
  // Get current value string for combobox
6438
6781
  const currentValue = React.useMemo(() => {
@@ -6522,6 +6865,47 @@ const TimePicker$1 = ({ hour, setHour, minute, setMinute, meridiem, setMeridiem,
6522
6865
  if (!trimmedValue) {
6523
6866
  return;
6524
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
+ }
6525
6909
  // Parse formats like "1:30 PM", "1:30PM", "1:30 pm", "1:30pm"
6526
6910
  const timePattern12Hour = /^(\d{1,2}):(\d{1,2})\s*(am|pm|AM|PM)$/i;
6527
6911
  const match12Hour = trimmedValue.match(timePattern12Hour);
@@ -6687,133 +7071,6 @@ const TimePicker = ({ column, schema, prefix }) => {
6687
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 }) }) }) }) }))] }) }));
6688
7072
  };
6689
7073
 
6690
- dayjs.extend(utc);
6691
- dayjs.extend(timezone);
6692
- dayjs.extend(customParseFormat);
6693
- function DatePickerInput({ value, onChange, placeholder = 'Select a date', dateFormat = 'YYYY-MM-DD', displayFormat = 'YYYY-MM-DD', labels = {
6694
- monthNamesShort: [
6695
- 'Jan',
6696
- 'Feb',
6697
- 'Mar',
6698
- 'Apr',
6699
- 'May',
6700
- 'Jun',
6701
- 'Jul',
6702
- 'Aug',
6703
- 'Sep',
6704
- 'Oct',
6705
- 'Nov',
6706
- 'Dec',
6707
- ],
6708
- weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
6709
- backButtonLabel: 'Back',
6710
- forwardButtonLabel: 'Next',
6711
- }, timezone = 'Asia/Hong_Kong', minDate, maxDate, firstDayOfWeek, showOutsideDays, monthsToDisplay = 1, insideDialog = false, readOnly = false, }) {
6712
- const [open, setOpen] = React.useState(false);
6713
- const [inputValue, setInputValue] = React.useState('');
6714
- // Update input value when prop value changes
6715
- React.useEffect(() => {
6716
- if (value) {
6717
- const formatted = typeof value === 'string'
6718
- ? dayjs(value).tz(timezone).isValid()
6719
- ? dayjs(value).tz(timezone).format(displayFormat)
6720
- : ''
6721
- : dayjs(value).tz(timezone).format(displayFormat);
6722
- setInputValue(formatted);
6723
- }
6724
- else {
6725
- setInputValue('');
6726
- }
6727
- }, [value, displayFormat, timezone]);
6728
- // Convert value to Date object for DatePicker
6729
- const selectedDate = value
6730
- ? typeof value === 'string'
6731
- ? dayjs(value).tz(timezone).isValid()
6732
- ? dayjs(value).tz(timezone).toDate()
6733
- : new Date()
6734
- : value
6735
- : new Date();
6736
- // Shared function to parse and validate input value
6737
- const parseAndValidateInput = (inputVal) => {
6738
- // If empty, clear the value
6739
- if (!inputVal.trim()) {
6740
- onChange?.(undefined);
6741
- setInputValue('');
6742
- return;
6743
- }
6744
- // Try parsing with displayFormat first
6745
- let parsedDate = dayjs(inputVal, displayFormat, true);
6746
- // If that fails, try common date formats
6747
- if (!parsedDate.isValid()) {
6748
- parsedDate = dayjs(inputVal);
6749
- }
6750
- // If still invalid, try parsing with dateFormat
6751
- if (!parsedDate.isValid()) {
6752
- parsedDate = dayjs(inputVal, dateFormat, true);
6753
- }
6754
- // If valid, check constraints and update
6755
- if (parsedDate.isValid()) {
6756
- const dateObj = parsedDate.tz(timezone).toDate();
6757
- // Check min/max constraints
6758
- if (minDate && dateObj < minDate) {
6759
- // Invalid: before minDate, reset to prop value
6760
- resetToPropValue();
6761
- return;
6762
- }
6763
- if (maxDate && dateObj > maxDate) {
6764
- // Invalid: after maxDate, reset to prop value
6765
- resetToPropValue();
6766
- return;
6767
- }
6768
- // Valid date - format and update
6769
- const formattedDate = parsedDate.tz(timezone).format(dateFormat);
6770
- const formattedDisplay = parsedDate.tz(timezone).format(displayFormat);
6771
- onChange?.(formattedDate);
6772
- setInputValue(formattedDisplay);
6773
- }
6774
- else {
6775
- // Invalid date - reset to prop value
6776
- resetToPropValue();
6777
- }
6778
- };
6779
- // Helper function to reset input to prop value
6780
- const resetToPropValue = () => {
6781
- if (value) {
6782
- const formatted = typeof value === 'string'
6783
- ? dayjs(value).tz(timezone).isValid()
6784
- ? dayjs(value).tz(timezone).format(displayFormat)
6785
- : ''
6786
- : dayjs(value).tz(timezone).format(displayFormat);
6787
- setInputValue(formatted);
6788
- }
6789
- else {
6790
- setInputValue('');
6791
- }
6792
- };
6793
- const handleInputChange = (e) => {
6794
- // Only update the input value, don't parse yet
6795
- setInputValue(e.target.value);
6796
- };
6797
- const handleInputBlur = () => {
6798
- // Parse and validate when input loses focus
6799
- parseAndValidateInput(inputValue);
6800
- };
6801
- const handleKeyDown = (e) => {
6802
- // Parse and validate when Enter is pressed
6803
- if (e.key === 'Enter') {
6804
- e.preventDefault();
6805
- parseAndValidateInput(inputValue);
6806
- }
6807
- };
6808
- const handleDateSelected = ({ date }) => {
6809
- const formattedDate = dayjs(date).tz(timezone).format(dateFormat);
6810
- onChange?.(formattedDate);
6811
- setOpen(false);
6812
- };
6813
- const datePickerContent = (jsxRuntime.jsx(DatePicker$1, { selected: selectedDate, onDateSelected: handleDateSelected, labels: labels, minDate: minDate, maxDate: maxDate, firstDayOfWeek: firstDayOfWeek, showOutsideDays: showOutsideDays, monthsToDisplay: monthsToDisplay }));
6814
- 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 }) }) }) }))] }));
6815
- }
6816
-
6817
7074
  dayjs.extend(utc);
6818
7075
  dayjs.extend(timezone);
6819
7076
  function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond,
@@ -7057,7 +7314,20 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
7057
7314
  });
7058
7315
  }
7059
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]);
7060
7328
  const handleInputValueChange = (details) => {
7329
+ // Update local input value state
7330
+ setInputValue(details.inputValue);
7061
7331
  // Filter the collection based on input, but don't parse yet
7062
7332
  filter(details.inputValue);
7063
7333
  };
@@ -7067,24 +7337,26 @@ onChange = (_newValue) => { }, startTime, selectedDate, timezone = 'Asia/Hong_Ko
7067
7337
  };
7068
7338
  const handleBlur = (e) => {
7069
7339
  // Parse and commit the input value when losing focus
7070
- const inputValue = e.target.value;
7071
- if (inputValue) {
7072
- parseAndCommitInput(inputValue);
7340
+ const inputVal = e.target.value;
7341
+ setInputValue(inputVal);
7342
+ if (inputVal) {
7343
+ parseAndCommitInput(inputVal);
7073
7344
  }
7074
7345
  };
7075
7346
  const handleKeyDown = (e) => {
7076
7347
  // Commit input on Enter key
7077
7348
  if (e.key === 'Enter') {
7078
7349
  e.preventDefault();
7079
- const inputValue = e.currentTarget.value;
7080
- if (inputValue) {
7081
- parseAndCommitInput(inputValue);
7350
+ const inputVal = e.currentTarget.value;
7351
+ setInputValue(inputVal);
7352
+ if (inputVal) {
7353
+ parseAndCommitInput(inputVal);
7082
7354
  }
7083
7355
  // Blur the input
7084
7356
  e.currentTarget?.blur();
7085
7357
  }
7086
7358
  };
7087
- 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, {}) }) })] }) }));
7088
7360
  }
7089
7361
 
7090
7362
  dayjs.extend(utc);
@@ -7107,7 +7379,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7107
7379
  weekdayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
7108
7380
  backButtonLabel: 'Back',
7109
7381
  forwardButtonLabel: 'Next',
7110
- }, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, }) {
7382
+ }, timePickerLabels, timezone = 'Asia/Hong_Kong', startTime, minDate, maxDate, portalled = false, defaultDate, defaultTime, }) {
7111
7383
  console.log('[DateTimePicker] Component initialized with props:', {
7112
7384
  value,
7113
7385
  format,
@@ -7182,13 +7454,77 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7182
7454
  value,
7183
7455
  initialTime,
7184
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();
7185
7521
  // Time state for 12-hour format
7186
- const [hour12, setHour12] = React.useState(initialTime.hour12);
7187
- const [minute, setMinute] = React.useState(initialTime.minute);
7188
- 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);
7189
7525
  // Time state for 24-hour format
7190
- const [hour24, setHour24] = React.useState(initialTime.hour24);
7191
- const [second, setSecond] = React.useState(initialTime.second);
7526
+ const [hour24, setHour24] = React.useState(initialTimeValues.hour24);
7527
+ const [second, setSecond] = React.useState(initialTimeValues.second);
7192
7528
  // Sync selectedDate and time states when value prop changes
7193
7529
  React.useEffect(() => {
7194
7530
  console.log('[DateTimePicker] useEffect triggered - value changed:', {
@@ -7196,27 +7532,47 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7196
7532
  timezone,
7197
7533
  format,
7198
7534
  });
7199
- // 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
7200
7536
  if (!value || value === null || value === undefined) {
7201
- console.log('[DateTimePicker] Value is null/undefined, clearing all fields');
7537
+ console.log('[DateTimePicker] Value is null/undefined, clearing date but keeping default time');
7202
7538
  setSelectedDate('');
7203
- setHour12(null);
7204
- setMinute(null);
7205
- setMeridiem(null);
7206
- setHour24(null);
7207
- 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
+ }
7208
7554
  return;
7209
7555
  }
7210
7556
  // Check if value is valid
7211
7557
  const dateObj = dayjs(value).tz(timezone);
7212
7558
  if (!dateObj.isValid()) {
7213
- console.log('[DateTimePicker] Invalid value, clearing all fields');
7559
+ console.log('[DateTimePicker] Invalid value, clearing date but keeping default time');
7214
7560
  setSelectedDate('');
7215
- setHour12(null);
7216
- setMinute(null);
7217
- setMeridiem(null);
7218
- setHour24(null);
7219
- 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
+ }
7220
7576
  return;
7221
7577
  }
7222
7578
  const dateString = getDateString(value);
@@ -7272,16 +7628,76 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7272
7628
  onChange?.(undefined);
7273
7629
  return;
7274
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
+ }
7275
7691
  // When showSeconds is false, ignore seconds from the date
7276
7692
  if (!showSeconds) {
7277
7693
  const dateWithoutSeconds = dateObj.second(0).millisecond(0).toISOString();
7278
7694
  console.log('[DateTimePicker] Updating date without seconds:', dateWithoutSeconds);
7279
- updateDateTime(dateWithoutSeconds);
7695
+ updateDateTime(dateWithoutSeconds, timeDataToUse);
7280
7696
  }
7281
7697
  else {
7282
7698
  const dateWithSeconds = dateObj.toISOString();
7283
7699
  console.log('[DateTimePicker] Updating date with seconds:', dateWithSeconds);
7284
- updateDateTime(dateWithSeconds);
7700
+ updateDateTime(dateWithSeconds, timeDataToUse);
7285
7701
  }
7286
7702
  };
7287
7703
  const handleTimeChange = (timeData) => {
@@ -7311,17 +7727,36 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7311
7727
  setMinute(data.minute);
7312
7728
  setMeridiem(data.meridiem);
7313
7729
  }
7314
- // Use selectedDate if valid, otherwise clear all fields
7730
+ // Use selectedDate if valid, otherwise use effectiveDefaultDate or clear all fields
7315
7731
  if (!selectedDate || !dayjs(selectedDate).isValid()) {
7316
- console.log('[DateTimePicker] No valid selectedDate, clearing all fields');
7317
- setSelectedDate('');
7318
- setHour12(null);
7319
- setMinute(null);
7320
- setMeridiem(null);
7321
- setHour24(null);
7322
- setSecond(null);
7323
- onChange?.(undefined);
7324
- 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
+ }
7325
7760
  }
7326
7761
  const dateObj = dayjs(selectedDate).tz(timezone);
7327
7762
  if (dateObj.isValid()) {
@@ -7464,18 +7899,24 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7464
7899
  };
7465
7900
  const handleClear = () => {
7466
7901
  setSelectedDate('');
7467
- setHour12(null);
7468
- setHour24(null);
7469
- setMinute(null);
7470
- setSecond(null);
7471
- 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
+ }
7472
7917
  onChange?.(undefined);
7473
7918
  };
7474
7919
  const isISO = format === 'iso-date-time';
7475
- // Normalize startTime to ignore milliseconds
7476
- const normalizedStartTime = startTime
7477
- ? dayjs(startTime).tz(timezone).millisecond(0).toISOString()
7478
- : undefined;
7479
7920
  // Determine minDate: prioritize explicit minDate prop, then fall back to startTime
7480
7921
  const effectiveMinDate = minDate
7481
7922
  ? minDate
@@ -7553,7 +7994,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7553
7994
  const dateObj = dayjs.tz(selectedDate, timezone);
7554
7995
  return dateObj.isValid() ? dateObj.format('Z') : null;
7555
7996
  }, [selectedDate, timezone]);
7556
- 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) => {
7557
7998
  if (date) {
7558
7999
  handleDateChange(date);
7559
8000
  }
@@ -7561,7 +8002,7 @@ function DateTimePicker$1({ value, onChange, format = 'date-time', showSeconds =
7561
8002
  setSelectedDate('');
7562
8003
  onChange?.(undefined);
7563
8004
  }
7564
- }, 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 })] }))] }));
7565
8006
  }
7566
8007
 
7567
8008
  dayjs.extend(utc);
@@ -7623,7 +8064,7 @@ const DateTimePicker = ({ column, schema, prefix, }) => {
7623
8064
  return (jsxRuntime.jsx(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
7624
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: () => {
7625
8066
  setOpen(true);
7626
- }, 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 }) }) }) }))] }) }));
7627
8068
  };
7628
8069
 
7629
8070
  const SchemaRenderer = ({ schema, prefix, column, }) => {
@@ -7776,15 +8217,15 @@ const DateViewer = ({ column, schema, prefix }) => {
7776
8217
 
7777
8218
  const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
7778
8219
  const { watch, formState: { errors }, } = reactHookForm.useFormContext();
7779
- const formI18n = useFormI18n(column, prefix);
8220
+ const formI18n = useFormI18n(column, prefix, schema);
7780
8221
  const { required } = schema;
7781
8222
  const isRequired = required?.some((columnId) => columnId === column);
7782
- const { gridColumn = "span 12", gridRow = "span 1", renderDisplay } = schema;
8223
+ const { gridColumn = 'span 12', gridRow = 'span 1', renderDisplay } = schema;
7783
8224
  const colLabel = formI18n.colLabel;
7784
8225
  const watchEnum = watch(colLabel);
7785
8226
  const watchEnums = (watch(colLabel) ?? []);
7786
- return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: "stretch", gridColumn,
7787
- gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: "wrap", gap: 1, children: watchEnums.map((enumValue) => {
8227
+ return (jsxRuntime.jsxs(Field, { label: formI18n.label(), required: isRequired, alignItems: 'stretch', gridColumn,
8228
+ gridRow, children: [isMultiple && (jsxRuntime.jsx(react.Flex, { flexFlow: 'wrap', gap: 1, children: watchEnums.map((enumValue) => {
7788
8229
  const item = enumValue;
7789
8230
  if (item === undefined) {
7790
8231
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: "undefined" });
@@ -7792,7 +8233,7 @@ const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
7792
8233
  return (jsxRuntime.jsx(Tag, { size: "lg", children: !!renderDisplay === true
7793
8234
  ? renderDisplay(item)
7794
8235
  : formI18n.t(item) }, item));
7795
- }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: formI18n.required() }))] }));
8236
+ }) })), !isMultiple && jsxRuntime.jsx(react.Text, { children: formI18n.t(watchEnum) }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: 'red.400', children: formI18n.required() }))] }));
7796
8237
  };
7797
8238
 
7798
8239
  const FileViewer = ({ column, schema, prefix }) => {
@@ -8205,6 +8646,17 @@ const FormBody = () => {
8205
8646
 
8206
8647
  const FormTitle = () => {
8207
8648
  const { schema } = useSchemaContext();
8649
+ // Debug log when form title is missing
8650
+ if (!schema.title) {
8651
+ console.debug('[Form Title] Missing title in root schema. Add title property to schema.', {
8652
+ schema: {
8653
+ type: schema.type,
8654
+ properties: schema.properties
8655
+ ? Object.keys(schema.properties)
8656
+ : undefined,
8657
+ },
8658
+ });
8659
+ }
8208
8660
  return jsxRuntime.jsx(react.Heading, { children: schema.title ?? 'Form' });
8209
8661
  };
8210
8662