@bsol-oss/react-datatable5 12.0.0-beta.37 → 12.0.0-beta.39

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
@@ -3904,15 +3904,18 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
3904
3904
  setOpenSearchResult(true);
3905
3905
  }, justifyContent: "start", children: watchEnum === undefined
3906
3906
  ? ""
3907
- : translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
3907
+ : translate.t(removeIndex(`${colLabel}.${watchEnum ?? "null"}`)) })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
3908
3908
  onSearchChange(event);
3909
3909
  setOpenSearchResult(true);
3910
- }, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), showTotalAndLimit && (jsxRuntime.jsx(react.Text, { children: `${translate.t(`${colLabel}.total`)}: ${count}, ${translate.t(`${colLabel}.showing`)} ${limit}` })), jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", children: dataList.filter((item) => {
3910
+ }, autoComplete: "off", ref: ref }), jsxRuntime.jsx(PopoverTitle, {}), showTotalAndLimit && (jsxRuntime.jsx(react.Text, { children: `${translate.t(`${colLabel}.total`)}: ${count}, ${translate.t(`${colLabel}.showing`)} ${limit}` })), jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", children: dataList
3911
+ .filter((item) => {
3911
3912
  const searchTerm = (searchText || "").toLowerCase();
3912
3913
  if (!searchTerm)
3913
3914
  return true;
3914
3915
  // Check if the original enum value contains the search text
3915
- const enumValueMatch = item.toLowerCase().includes(searchTerm);
3916
+ const enumValueMatch = item
3917
+ .toLowerCase()
3918
+ .includes(searchTerm);
3916
3919
  // Check if the display value (translation) contains the search text
3917
3920
  const displayValue = !!renderDisplay === true
3918
3921
  ? renderDisplay(item)
@@ -3921,7 +3924,8 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
3921
3924
  const displayValueString = String(displayValue).toLowerCase();
3922
3925
  const displayValueMatch = displayValueString.includes(searchTerm);
3923
3926
  return enumValueMatch || displayValueMatch;
3924
- }).map((item) => {
3927
+ })
3928
+ .map((item) => {
3925
3929
  const selected = isMultiple
3926
3930
  ? watchEnums.some((enumValue) => item === enumValue)
3927
3931
  : watchEnum == item;
@@ -4359,6 +4363,9 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4359
4363
  const [page, setPage] = React.useState(0);
4360
4364
  const ref = React.useRef(null);
4361
4365
  const colLabel = `${prefix}${column}`;
4366
+ const watchId = watch(colLabel);
4367
+ const watchIds = isMultiple ? (watch(colLabel) ?? []) : [];
4368
+ // Query for search results
4362
4369
  const query = reactQuery.useQuery({
4363
4370
  queryKey: [`idpicker`, { column, searchText, limit, page }],
4364
4371
  queryFn: async () => {
@@ -4385,11 +4392,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4385
4392
  enabled: openSearchResult === true,
4386
4393
  staleTime: 300000,
4387
4394
  });
4388
- const { isLoading, isFetching, data, isPending, isError } = query;
4389
- const dataList = data?.data ?? [];
4390
- const count = data?.count ?? 0;
4391
- const watchId = watch(colLabel);
4392
- const watchIds = (watch(colLabel) ?? []);
4395
+ // Query for currently selected items (to display them properly)
4393
4396
  const queryDefault = reactQuery.useQuery({
4394
4397
  queryKey: [
4395
4398
  `idpicker-default`,
@@ -4425,7 +4428,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4425
4428
  ? Array.isArray(watchIds) && watchIds.length > 0
4426
4429
  : !!watchId,
4427
4430
  });
4428
- // Effect to trigger the default query when the component mounts
4431
+ // Effect to load selected values when component mounts
4429
4432
  React.useEffect(() => {
4430
4433
  if (isMultiple ? watchIds.length > 0 : !!watchId) {
4431
4434
  queryDefault.refetch();
@@ -4435,6 +4438,11 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4435
4438
  // Effect to trigger initial data fetch when popover opens
4436
4439
  React.useEffect(() => {
4437
4440
  if (openSearchResult) {
4441
+ // Reset search text when opening the popover
4442
+ setSearchText("");
4443
+ // Reset page to first page
4444
+ setPage(0);
4445
+ // Fetch initial data
4438
4446
  query.refetch();
4439
4447
  }
4440
4448
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -4442,7 +4450,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4442
4450
  const onSearchChange = async (event) => {
4443
4451
  setSearchText(event.target.value);
4444
4452
  setPage(0);
4445
- setLimit(10);
4453
+ query.refetch();
4446
4454
  };
4447
4455
  const handleLimitChange = (event) => {
4448
4456
  const newLimit = Number(event.target.value);
@@ -4452,6 +4460,9 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4452
4460
  // Trigger a new search with the updated limit
4453
4461
  query.refetch();
4454
4462
  };
4463
+ const { isLoading, isFetching, data, isPending, isError } = query;
4464
+ const dataList = data?.data ?? [];
4465
+ const count = data?.count ?? 0;
4455
4466
  const getPickedValue = () => {
4456
4467
  if (Object.keys(idMap).length <= 0) {
4457
4468
  return "";
@@ -4480,37 +4491,37 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4480
4491
  setOpenSearchResult(true);
4481
4492
  }, children: translate.t(removeIndex(`${colLabel}.add_more`)) })] })), !isMultiple && (jsxRuntime.jsx(Button, { variant: "outline", onClick: () => {
4482
4493
  setOpenSearchResult(true);
4483
- }, justifyContent: "start", children: queryDefault.isLoading ? jsxRuntime.jsx(react.Spinner, { size: "sm" }) : getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: translate.t(removeIndex(`${colLabel}.type_to_search`)), onChange: (event) => {
4484
- onSearchChange(event);
4485
- setOpenSearchResult(true);
4486
- }, autoComplete: "off", ref: ref, value: searchText }), jsxRuntime.jsx(PopoverTitle, {}), openSearchResult && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isFetching && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isFetching" }), isLoading && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isLoading" }), isPending && jsxRuntime.jsx(jsxRuntime.Fragment, { children: "isPending" }), (isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: "red.400", children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", children: [jsxRuntime.jsx(InfoTip, { children: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit} ${translate.t(removeIndex(`${colLabel}.per_page`), "per page")}` }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/ ", count > 0 ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}` : '0'] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4494
+ }, justifyContent: "start", children: queryDefault.isLoading ? jsxRuntime.jsx(react.Spinner, { size: "sm" }) : getPickedValue() })), jsxRuntime.jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsxRuntime.jsx(PopoverTrigger, {}), jsxRuntime.jsx(PopoverContent, { children: jsxRuntime.jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsxRuntime.jsx(react.Input, { placeholder: translate.t(removeIndex(`${colLabel}.type_to_search`)), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsxRuntime.jsx(PopoverTitle, {}), openSearchResult && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(isFetching || isLoading || isPending) && jsxRuntime.jsx(react.Spinner, {}), isError && (jsxRuntime.jsx(react.Icon, { color: "red.400", children: jsxRuntime.jsx(bi.BiError, {}) })), jsxRuntime.jsxs(react.Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxRuntime.jsxs(react.Flex, { alignItems: "center", gap: "2", children: [jsxRuntime.jsx(InfoTip, { children: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit} ${translate.t(removeIndex(`${colLabel}.per_page`), "per page")}` }), jsxRuntime.jsxs(react.Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/ ", count > 0 ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}` : '0'] })] })] }), jsxRuntime.jsx(react.Box, { children: jsxRuntime.jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4487
4495
  padding: "4px 8px",
4488
4496
  borderRadius: "4px",
4489
4497
  border: "1px solid #ccc",
4490
4498
  fontSize: "14px",
4491
- }, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "50", children: "50" })] }) })] }), jsxRuntime.jsxs(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", children: dataList.map((item) => {
4492
- const selected = isMultiple
4493
- ? watchIds.some((id) => item[column_ref] === id)
4494
- : watchId === item[column_ref];
4495
- return (jsxRuntime.jsx(react.Box, { cursor: "pointer", onClick: () => {
4496
- if (!isMultiple) {
4497
- setOpenSearchResult(false);
4498
- setValue(colLabel, item[column_ref]);
4499
- return;
4500
- }
4501
- const newSet = new Set([
4502
- ...(watchIds ?? []),
4503
- item[column_ref],
4504
- ]);
4505
- setValue(colLabel, [...newSet]);
4506
- }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
4507
- ? { color: "colorPalette.400/50" }
4508
- : {}), children: !!renderDisplay === true
4509
- ? renderDisplay(item)
4510
- : item[display_column] }, item[column_ref]));
4511
- }) }), dataList.length <= 0 && (jsxRuntime.jsx(react.Text, { children: searchText
4512
- ? translate.t(removeIndex(`${colLabel}.empty_search_result`))
4513
- : translate.t(removeIndex(`${colLabel}.initial_results`)) }))] }), jsxRuntime.jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4499
+ }, children: [jsxRuntime.jsx("option", { value: "5", children: "5" }), jsxRuntime.jsx("option", { value: "10", children: "10" }), jsxRuntime.jsx("option", { value: "20", children: "20" }), jsxRuntime.jsx("option", { value: "50", children: "50" })] }) })] }), jsxRuntime.jsx(react.Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: dataList.length > 0 ? (jsxRuntime.jsx(react.Flex, { flexFlow: "column wrap", children: dataList.map((item) => {
4500
+ const selected = isMultiple
4501
+ ? watchIds.some((id) => item[column_ref] === id)
4502
+ : watchId === item[column_ref];
4503
+ return (jsxRuntime.jsx(react.Box, { cursor: "pointer", onClick: () => {
4504
+ if (!isMultiple) {
4505
+ setOpenSearchResult(false);
4506
+ setValue(colLabel, item[column_ref]);
4507
+ return;
4508
+ }
4509
+ // For multiple selection, don't add if already selected
4510
+ if (selected)
4511
+ return;
4512
+ const newSet = new Set([
4513
+ ...(watchIds ?? []),
4514
+ item[column_ref],
4515
+ ]);
4516
+ setValue(colLabel, [...newSet]);
4517
+ }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
4518
+ ? { color: "colorPalette.400/50", fontWeight: "bold" }
4519
+ : {}), children: !!renderDisplay === true
4520
+ ? renderDisplay(item)
4521
+ : item[display_column] }, item[column_ref]));
4522
+ }) })) : (jsxRuntime.jsx(react.Text, { children: searchText
4523
+ ? translate.t(removeIndex(`${colLabel}.empty_search_result`))
4524
+ : translate.t(removeIndex(`${colLabel}.initial_results`)) })) }), jsxRuntime.jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxRuntime.jsxs(react.HStack, { gap: "4", children: [jsxRuntime.jsx(PaginationPrevTrigger, {}), count > 0 && jsxRuntime.jsx(PaginationPageText, {}), jsxRuntime.jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4514
4525
  };
4515
4526
 
4516
4527
  const NumberInputRoot = React__namespace.forwardRef(function NumberInput(props, ref) {
@@ -4719,42 +4730,180 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
4719
4730
  function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
4720
4731
  am: "am",
4721
4732
  pm: "pm",
4722
- }, onChange = () => { }, }) {
4723
- const hours = Array.from({ length: 12 }, (_, i) => {
4724
- const hour = i + 1;
4725
- return hour.toString().padStart(2, "0");
4726
- });
4727
- const minutes = Array.from({ length: 60 }, (_, i) => {
4728
- return i.toString().padStart(2, "0");
4729
- });
4730
- const hoursCollection = react.createListCollection({
4731
- items: hours.map((hour) => ({
4732
- value: hour,
4733
- label: hour,
4734
- })),
4735
- });
4736
- const minutesCollection = react.createListCollection({
4737
- items: minutes.map((hour) => ({
4738
- value: hour,
4739
- label: hour,
4740
- })),
4741
- });
4742
- const meridiemsCollection = react.createListCollection({
4743
- items: ["am", "pm"].map((hour) => ({
4744
- value: hour,
4745
- label: meridiemLabel[hour] ?? hour,
4746
- })),
4747
- });
4748
- return (jsxRuntime.jsxs(react.Grid, { justifyContent: "center", alignItems: "center", templateColumns: "auto auto auto auto", gap: "4", children: [jsxRuntime.jsxs(react.Select.Root, { width: "4rem", value: [`${hour.toString().padStart(2, "0")}`], onValueChange: (e) => {
4749
- setHour(parseInt(e.value[0]));
4750
- onChange({ hour: parseInt(e.value[0]), minute, meridiem });
4751
- }, collection: hoursCollection, children: [jsxRuntime.jsx(react.Select.HiddenSelect, {}), jsxRuntime.jsx(react.Select.Control, { children: jsxRuntime.jsx(react.Select.Trigger, { children: jsxRuntime.jsx(react.Select.ValueText, { placeholder: "Hour" }) }) }), jsxRuntime.jsx(react.Select.Positioner, { children: jsxRuntime.jsx(react.Select.Content, { children: hoursCollection.items.map(({ value: hour }) => (jsxRuntime.jsxs(react.Select.Item, { item: hour, children: [hour, jsxRuntime.jsx(react.Select.ItemIndicator, {})] }, hour))) }) })] }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsxs(react.Select.Root, { width: "4rem", value: [`${minute.toString().padStart(2, "0")}`], onValueChange: (e) => {
4752
- setMinute(parseInt(e.value[0]));
4753
- onChange({ hour, minute: parseInt(e.value[0]), meridiem });
4754
- }, collection: minutesCollection, children: [jsxRuntime.jsx(react.Select.HiddenSelect, {}), jsxRuntime.jsx(react.Select.Control, { children: jsxRuntime.jsx(react.Select.Trigger, { children: jsxRuntime.jsx(react.Select.ValueText, { placeholder: "Minute" }) }) }), jsxRuntime.jsx(react.Select.Positioner, { children: jsxRuntime.jsx(react.Select.Content, { children: minutes.map((minute) => (jsxRuntime.jsxs(react.Select.Item, { item: minute, children: [minute, jsxRuntime.jsx(react.Select.ItemIndicator, {})] }, minute))) }) })] }), jsxRuntime.jsxs(react.Select.Root, { width: "8rem", value: [meridiem], onValueChange: (e) => {
4755
- setMeridiem(e.value[0]);
4756
- onChange({ hour, minute, meridiem: e.value[0] });
4757
- }, collection: meridiemsCollection, children: [jsxRuntime.jsx(react.Select.HiddenSelect, {}), jsxRuntime.jsx(react.Select.Control, { children: jsxRuntime.jsx(react.Select.Trigger, { children: jsxRuntime.jsx(react.Select.ValueText, { placeholder: "am/pm" }) }) }), jsxRuntime.jsx(react.Select.Positioner, { children: jsxRuntime.jsx(react.Select.Content, { children: meridiemsCollection.items.map(({ value: hour, label }) => (jsxRuntime.jsxs(react.Select.Item, { item: hour, children: [label, jsxRuntime.jsx(react.Select.ItemIndicator, {})] }, hour))) }) })] })] }));
4733
+ }, onChange = (_newValue) => { }, }) {
4734
+ // Refs for focus management
4735
+ const hourInputRef = React.useRef(null);
4736
+ const minuteInputRef = React.useRef(null);
4737
+ const meridiemInputRef = React.useRef(null);
4738
+ // Centralized handler for key events, value changes, and focus management
4739
+ const handleKeyDown = (e, field) => {
4740
+ const input = e.target;
4741
+ const value = input.value;
4742
+ // Handle navigation between fields
4743
+ if (e.key === "Tab") {
4744
+ // Tab is handled by the browser, no need to override
4745
+ return;
4746
+ }
4747
+ if (e.key === ":" && field === "hour") {
4748
+ e.preventDefault();
4749
+ minuteInputRef.current?.focus();
4750
+ return;
4751
+ }
4752
+ if (e.key === "Backspace" && value === "") {
4753
+ e.preventDefault();
4754
+ if (field === "minute") {
4755
+ hourInputRef.current?.focus();
4756
+ }
4757
+ else if (field === "meridiem") {
4758
+ minuteInputRef.current?.focus();
4759
+ }
4760
+ return;
4761
+ }
4762
+ // Handle number inputs
4763
+ if (field === "hour") {
4764
+ if (e.key.match(/^[0-9]$/)) {
4765
+ const newValue = value + e.key;
4766
+ const numValue = parseInt(newValue, 10);
4767
+ console.log("newValue", newValue, numValue);
4768
+ if (numValue > 12) {
4769
+ const digitValue = parseInt(e.key, 10);
4770
+ setHour(digitValue);
4771
+ onChange({ hour: digitValue, minute, meridiem });
4772
+ return;
4773
+ }
4774
+ // Auto-advance to minutes if we have a valid hour (1-12)
4775
+ if (numValue >= 1 && numValue <= 12) {
4776
+ // Set the hour value
4777
+ setHour(numValue);
4778
+ onChange({ hour: numValue, minute, meridiem });
4779
+ // Move to minute input
4780
+ e.preventDefault();
4781
+ minuteInputRef.current?.focus();
4782
+ }
4783
+ }
4784
+ }
4785
+ else if (field === "minute") {
4786
+ if (e.key.match(/^[0-9]$/)) {
4787
+ const newValue = value + e.key;
4788
+ const numValue = parseInt(newValue, 10);
4789
+ if (numValue > 60) {
4790
+ const digitValue = parseInt(e.key, 10);
4791
+ setHour(digitValue);
4792
+ onChange({ hour, minute: digitValue, meridiem });
4793
+ return;
4794
+ }
4795
+ // Auto-advance to meridiem if we have a valid minute (0-59)
4796
+ if (numValue >= 0 && numValue <= 59) {
4797
+ // Set the minute value
4798
+ setMinute(numValue);
4799
+ onChange({ hour, minute: numValue, meridiem });
4800
+ // Move to meridiem input
4801
+ e.preventDefault();
4802
+ meridiemInputRef.current?.focus();
4803
+ }
4804
+ }
4805
+ }
4806
+ else if (field === "meridiem") {
4807
+ const key = e.key.toLowerCase();
4808
+ if (key === "a") {
4809
+ e.preventDefault();
4810
+ setMeridiem("am");
4811
+ onChange({ hour, minute, meridiem: "am" });
4812
+ input.value = "am";
4813
+ }
4814
+ else if (key === "p") {
4815
+ e.preventDefault();
4816
+ setMeridiem("pm");
4817
+ onChange({ hour, minute, meridiem: "pm" });
4818
+ input.value = "pm";
4819
+ }
4820
+ }
4821
+ };
4822
+ // Handle input blur events to validate and format values
4823
+ const handleBlur = (e, field) => {
4824
+ const value = e.target.value;
4825
+ if (field === "hour") {
4826
+ if (value === "") {
4827
+ if (hour !== null) {
4828
+ setHour(null);
4829
+ onChange({ hour: null, minute, meridiem });
4830
+ }
4831
+ return;
4832
+ }
4833
+ const numValue = parseInt(value, 10);
4834
+ if (isNaN(numValue) || numValue < 1 || numValue > 12) {
4835
+ setHour(null);
4836
+ onChange({ hour: null, minute, meridiem });
4837
+ }
4838
+ else if (hour !== numValue) {
4839
+ setHour(numValue);
4840
+ onChange({ hour: numValue, minute, meridiem });
4841
+ }
4842
+ }
4843
+ else if (field === "minute") {
4844
+ if (value === "") {
4845
+ if (minute !== null) {
4846
+ setMinute(null);
4847
+ onChange({ hour, minute: null, meridiem });
4848
+ }
4849
+ return;
4850
+ }
4851
+ const numValue = parseInt(value, 10);
4852
+ if (isNaN(numValue) || numValue < 0 || numValue > 59) {
4853
+ setMinute(null);
4854
+ onChange({ hour, minute: null, meridiem });
4855
+ }
4856
+ else if (minute !== numValue) {
4857
+ setMinute(numValue);
4858
+ onChange({ hour, minute: numValue, meridiem });
4859
+ }
4860
+ }
4861
+ else if (field === "meridiem") {
4862
+ if (value === "") {
4863
+ if (meridiem !== null) {
4864
+ setMeridiem(null);
4865
+ onChange({ hour, minute, meridiem: null });
4866
+ }
4867
+ return;
4868
+ }
4869
+ const lowerValue = value.toLowerCase();
4870
+ if (lowerValue !== "am" && lowerValue !== "pm") {
4871
+ if (lowerValue === "a") {
4872
+ setMeridiem("am");
4873
+ onChange({ hour, minute, meridiem: "am" });
4874
+ }
4875
+ else if (lowerValue === "p") {
4876
+ setMeridiem("pm");
4877
+ onChange({ hour, minute, meridiem: "pm" });
4878
+ }
4879
+ else {
4880
+ setMeridiem(null);
4881
+ onChange({ hour, minute, meridiem: null });
4882
+ }
4883
+ }
4884
+ else if (meridiem !== lowerValue) {
4885
+ setMeridiem(lowerValue);
4886
+ onChange({ hour, minute, meridiem: lowerValue });
4887
+ }
4888
+ }
4889
+ };
4890
+ // Handle meridiem button click
4891
+ const handleMeridiemClick = (newMeridiem) => {
4892
+ setMeridiem(newMeridiem);
4893
+ onChange({ hour, minute, meridiem: newMeridiem });
4894
+ };
4895
+ const handleClear = () => {
4896
+ setHour(null);
4897
+ setMinute(null);
4898
+ setMeridiem(null);
4899
+ onChange({ hour: null, minute: null, meridiem: null });
4900
+ // Focus the hour field after clearing
4901
+ hourInputRef.current?.focus();
4902
+ };
4903
+ function handleFocus(event) {
4904
+ event.target.select();
4905
+ }
4906
+ return (jsxRuntime.jsx(react.Flex, { direction: "column", gap: 3, children: jsxRuntime.jsxs(react.Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 90px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsxRuntime.jsx(react.Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), onBlur: (e) => handleBlur(e, "hour"), onFocus: handleFocus, placeholder: "HH", maxLength: 2, textAlign: "center" }), jsxRuntime.jsx(react.Text, { children: ":" }), jsxRuntime.jsx(react.Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), onBlur: (e) => handleBlur(e, "minute"), onFocus: handleFocus, placeholder: "MM", maxLength: 2, textAlign: "center" }), jsxRuntime.jsxs(react.Flex, { gap: "1", children: [jsxRuntime.jsx(react.Button, { size: "sm", colorScheme: meridiem === "am" ? "blue" : "gray", variant: meridiem === "am" ? "solid" : "outline", onClick: () => handleMeridiemClick("am"), width: "40px", children: meridiemLabel.am }), jsxRuntime.jsx(react.Button, { size: "sm", colorScheme: meridiem === "pm" ? "blue" : "gray", variant: meridiem === "pm" ? "solid" : "outline", onClick: () => handleMeridiemClick("pm"), width: "40px", children: meridiemLabel.pm })] }), jsxRuntime.jsx(react.Button, { onClick: handleClear, size: "sm", variant: "ghost", children: jsxRuntime.jsx(md.MdCancel, {}) })] }) }));
4758
4907
  }
4759
4908
 
4760
4909
  const TimePicker = ({ column, schema, prefix }) => {
@@ -4765,7 +4914,7 @@ const TimePicker = ({ column, schema, prefix }) => {
4765
4914
  const colLabel = `${prefix}${column}`;
4766
4915
  const [open, setOpen] = React.useState(false);
4767
4916
  const value = watch(colLabel);
4768
- const formatedTime = dayjs(value).format("hh:mm A");
4917
+ const formatedTime = value ? dayjs(value).format("hh:mm A") : "";
4769
4918
  // Parse the initial time parts from the ISO time string (HH:mm:ss)
4770
4919
  const parseTime = (isoTime) => {
4771
4920
  if (!isoTime)
@@ -4794,6 +4943,8 @@ const TimePicker = ({ column, schema, prefix }) => {
4794
4943
  }, [value]);
4795
4944
  // Convert hour, minute, meridiem to 24-hour ISO time string
4796
4945
  const toIsoTime = (hour, minute, meridiem) => {
4946
+ if (hour === null || minute === null || meridiem === null)
4947
+ return null;
4797
4948
  let h = hour;
4798
4949
  if (meridiem === "am" && hour === 12)
4799
4950
  h = 0;
@@ -4814,8 +4965,8 @@ const TimePicker = ({ column, schema, prefix }) => {
4814
4965
  gridRow, 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: () => {
4815
4966
  setOpen(true);
4816
4967
  }, justifyContent: "start", children: [jsxRuntime.jsx(io.IoMdClock, {}), value !== undefined ? `${formatedTime}` : ""] }) }), jsxRuntime.jsx(react.Portal, { children: jsxRuntime.jsx(react.Popover.Positioner, { children: jsxRuntime.jsx(react.Popover.Content, { ref: containerRef, 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, meridiemLabel: {
4817
- am: translate.t(removeIndex(`${colLabel}.am`)),
4818
- pm: translate.t(removeIndex(`${colLabel}.pm`)),
4968
+ am: translate.t(removeIndex(`common.am`)),
4969
+ pm: translate.t(removeIndex(`common.pm`)),
4819
4970
  } }) }) }) }) })] }), errors[`${column}`] && (jsxRuntime.jsx(react.Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4820
4971
  };
4821
4972
 
@@ -5011,7 +5162,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
5011
5162
  };
5012
5163
 
5013
5164
  const ObjectViewer = ({ schema, column, prefix }) => {
5014
- const { properties, gridColumn = "span 4", gridRow = "span 1", required, } = schema;
5165
+ const { properties, gridColumn = "span 12", gridRow = "span 1", required, } = schema;
5015
5166
  const { translate } = useSchemaContext();
5016
5167
  const colLabel = `${prefix}${column}`;
5017
5168
  const isRequired = required?.some((columnId) => columnId === column);
@@ -5019,7 +5170,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
5019
5170
  if (properties === undefined) {
5020
5171
  throw new Error(`properties is undefined when using ObjectInput`);
5021
5172
  }
5022
- return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: Object.keys(properties ?? {}).map((key) => {
5173
+ return (jsxRuntime.jsxs(react.Box, { gridRow, gridColumn, children: [jsxRuntime.jsxs(react.Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsxRuntime.jsx("span", { children: "*" })] }), jsxRuntime.jsx(react.Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
5023
5174
  return (
5024
5175
  // @ts-expect-error find suitable types
5025
5176
  jsxRuntime.jsx(ColumnViewer, { column: `${key}`,
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Tooltip as Tooltip$1, Group, InputElement, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Accordion, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Textarea, createListCollection, Select, Center, Heading } from '@chakra-ui/react';
2
+ import { Button as Button$1, AbsoluteCenter, Spinner, Span, IconButton, Portal, Dialog, Flex, Text, useDisclosure, DialogBackdrop, RadioGroup as RadioGroup$1, Grid, Box, Slider as Slider$1, HStack, For, Tag as Tag$1, Input, Menu, createRecipeContext, createContext as createContext$1, Pagination as Pagination$1, usePaginationContext, CheckboxCard as CheckboxCard$1, Image, EmptyState as EmptyState$2, VStack, Alert, Card, Tooltip as Tooltip$1, Group, InputElement, Icon, List, Table as Table$1, Checkbox as Checkbox$1, MenuRoot as MenuRoot$1, MenuTrigger as MenuTrigger$1, Accordion, Field as Field$1, Popover, NumberInput, Show, RadioCard, CheckboxGroup, Textarea, Center, Heading } from '@chakra-ui/react';
3
3
  import { AiOutlineColumnWidth } from 'react-icons/ai';
4
4
  import * as React from 'react';
5
5
  import React__default, { createContext, useContext, useState, useEffect, useRef } from 'react';
@@ -3884,15 +3884,18 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
3884
3884
  setOpenSearchResult(true);
3885
3885
  }, justifyContent: "start", children: watchEnum === undefined
3886
3886
  ? ""
3887
- : translate.t(removeIndex(`${colLabel}.${watchEnum}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
3887
+ : translate.t(removeIndex(`${colLabel}.${watchEnum ?? "null"}`)) })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(`${colLabel}.type_to_search`), onChange: (event) => {
3888
3888
  onSearchChange(event);
3889
3889
  setOpenSearchResult(true);
3890
- }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), showTotalAndLimit && (jsx(Text, { children: `${translate.t(`${colLabel}.total`)}: ${count}, ${translate.t(`${colLabel}.showing`)} ${limit}` })), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children: dataList.filter((item) => {
3890
+ }, autoComplete: "off", ref: ref }), jsx(PopoverTitle, {}), showTotalAndLimit && (jsx(Text, { children: `${translate.t(`${colLabel}.total`)}: ${count}, ${translate.t(`${colLabel}.showing`)} ${limit}` })), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children: dataList
3891
+ .filter((item) => {
3891
3892
  const searchTerm = (searchText || "").toLowerCase();
3892
3893
  if (!searchTerm)
3893
3894
  return true;
3894
3895
  // Check if the original enum value contains the search text
3895
- const enumValueMatch = item.toLowerCase().includes(searchTerm);
3896
+ const enumValueMatch = item
3897
+ .toLowerCase()
3898
+ .includes(searchTerm);
3896
3899
  // Check if the display value (translation) contains the search text
3897
3900
  const displayValue = !!renderDisplay === true
3898
3901
  ? renderDisplay(item)
@@ -3901,7 +3904,8 @@ const EnumPicker = ({ column, isMultiple = false, schema, prefix, showTotalAndLi
3901
3904
  const displayValueString = String(displayValue).toLowerCase();
3902
3905
  const displayValueMatch = displayValueString.includes(searchTerm);
3903
3906
  return enumValueMatch || displayValueMatch;
3904
- }).map((item) => {
3907
+ })
3908
+ .map((item) => {
3905
3909
  const selected = isMultiple
3906
3910
  ? watchEnums.some((enumValue) => item === enumValue)
3907
3911
  : watchEnum == item;
@@ -4339,6 +4343,9 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4339
4343
  const [page, setPage] = useState(0);
4340
4344
  const ref = useRef(null);
4341
4345
  const colLabel = `${prefix}${column}`;
4346
+ const watchId = watch(colLabel);
4347
+ const watchIds = isMultiple ? (watch(colLabel) ?? []) : [];
4348
+ // Query for search results
4342
4349
  const query = useQuery({
4343
4350
  queryKey: [`idpicker`, { column, searchText, limit, page }],
4344
4351
  queryFn: async () => {
@@ -4365,11 +4372,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4365
4372
  enabled: openSearchResult === true,
4366
4373
  staleTime: 300000,
4367
4374
  });
4368
- const { isLoading, isFetching, data, isPending, isError } = query;
4369
- const dataList = data?.data ?? [];
4370
- const count = data?.count ?? 0;
4371
- const watchId = watch(colLabel);
4372
- const watchIds = (watch(colLabel) ?? []);
4375
+ // Query for currently selected items (to display them properly)
4373
4376
  const queryDefault = useQuery({
4374
4377
  queryKey: [
4375
4378
  `idpicker-default`,
@@ -4405,7 +4408,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4405
4408
  ? Array.isArray(watchIds) && watchIds.length > 0
4406
4409
  : !!watchId,
4407
4410
  });
4408
- // Effect to trigger the default query when the component mounts
4411
+ // Effect to load selected values when component mounts
4409
4412
  useEffect(() => {
4410
4413
  if (isMultiple ? watchIds.length > 0 : !!watchId) {
4411
4414
  queryDefault.refetch();
@@ -4415,6 +4418,11 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4415
4418
  // Effect to trigger initial data fetch when popover opens
4416
4419
  useEffect(() => {
4417
4420
  if (openSearchResult) {
4421
+ // Reset search text when opening the popover
4422
+ setSearchText("");
4423
+ // Reset page to first page
4424
+ setPage(0);
4425
+ // Fetch initial data
4418
4426
  query.refetch();
4419
4427
  }
4420
4428
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -4422,7 +4430,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4422
4430
  const onSearchChange = async (event) => {
4423
4431
  setSearchText(event.target.value);
4424
4432
  setPage(0);
4425
- setLimit(10);
4433
+ query.refetch();
4426
4434
  };
4427
4435
  const handleLimitChange = (event) => {
4428
4436
  const newLimit = Number(event.target.value);
@@ -4432,6 +4440,9 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4432
4440
  // Trigger a new search with the updated limit
4433
4441
  query.refetch();
4434
4442
  };
4443
+ const { isLoading, isFetching, data, isPending, isError } = query;
4444
+ const dataList = data?.data ?? [];
4445
+ const count = data?.count ?? 0;
4435
4446
  const getPickedValue = () => {
4436
4447
  if (Object.keys(idMap).length <= 0) {
4437
4448
  return "";
@@ -4460,37 +4471,37 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
4460
4471
  setOpenSearchResult(true);
4461
4472
  }, children: translate.t(removeIndex(`${colLabel}.add_more`)) })] })), !isMultiple && (jsx(Button, { variant: "outline", onClick: () => {
4462
4473
  setOpenSearchResult(true);
4463
- }, justifyContent: "start", children: queryDefault.isLoading ? jsx(Spinner, { size: "sm" }) : getPickedValue() })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(removeIndex(`${colLabel}.type_to_search`)), onChange: (event) => {
4464
- onSearchChange(event);
4465
- setOpenSearchResult(true);
4466
- }, autoComplete: "off", ref: ref, value: searchText }), jsx(PopoverTitle, {}), openSearchResult && (jsxs(Fragment, { children: [isFetching && jsx(Fragment, { children: "isFetching" }), isLoading && jsx(Fragment, { children: "isLoading" }), isPending && jsx(Fragment, { children: "isPending" }), (isFetching || isLoading || isPending) && jsx(Spinner, {}), isError && (jsx(Icon, { color: "red.400", children: jsx(BiError, {}) })), jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxs(Flex, { alignItems: "center", gap: "2", children: [jsx(InfoTip, { children: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit} ${translate.t(removeIndex(`${colLabel}.per_page`), "per page")}` }), jsxs(Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxs(Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/ ", count > 0 ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}` : '0'] })] })] }), jsx(Box, { children: jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4474
+ }, justifyContent: "start", children: queryDefault.isLoading ? jsx(Spinner, { size: "sm" }) : getPickedValue() })), jsxs(PopoverRoot, { open: openSearchResult, onOpenChange: (e) => setOpenSearchResult(e.open), closeOnInteractOutside: true, initialFocusEl: () => ref.current, positioning: { placement: "bottom-start", strategy: "fixed" }, children: [jsx(PopoverTrigger, {}), jsx(PopoverContent, { children: jsxs(PopoverBody, { display: "grid", gap: 1, children: [jsx(Input, { placeholder: translate.t(removeIndex(`${colLabel}.type_to_search`)), onChange: onSearchChange, autoComplete: "off", ref: ref, value: searchText }), jsx(PopoverTitle, {}), openSearchResult && (jsxs(Fragment, { children: [(isFetching || isLoading || isPending) && jsx(Spinner, {}), isError && (jsx(Icon, { color: "red.400", children: jsx(BiError, {}) })), jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [jsxs(Flex, { alignItems: "center", gap: "2", children: [jsx(InfoTip, { children: `${translate.t(removeIndex(`${colLabel}.total`))} ${count}, ${translate.t(removeIndex(`${colLabel}.showing`))} ${limit} ${translate.t(removeIndex(`${colLabel}.per_page`), "per page")}` }), jsxs(Text, { fontSize: "sm", fontWeight: "bold", children: [count, jsxs(Text, { as: "span", fontSize: "xs", ml: "1", color: "gray.500", children: ["/ ", count > 0 ? `${page * limit + 1}-${Math.min((page + 1) * limit, count)}` : '0'] })] })] }), jsx(Box, { children: jsxs("select", { value: limit, onChange: handleLimitChange, style: {
4467
4475
  padding: "4px 8px",
4468
4476
  borderRadius: "4px",
4469
4477
  border: "1px solid #ccc",
4470
4478
  fontSize: "14px",
4471
- }, children: [jsx("option", { value: "5", children: "5" }), jsx("option", { value: "10", children: "10" }), jsx("option", { value: "20", children: "20" }), jsx("option", { value: "50", children: "50" })] }) })] }), jsxs(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: [jsx(Flex, { flexFlow: "column wrap", children: dataList.map((item) => {
4472
- const selected = isMultiple
4473
- ? watchIds.some((id) => item[column_ref] === id)
4474
- : watchId === item[column_ref];
4475
- return (jsx(Box, { cursor: "pointer", onClick: () => {
4476
- if (!isMultiple) {
4477
- setOpenSearchResult(false);
4478
- setValue(colLabel, item[column_ref]);
4479
- return;
4480
- }
4481
- const newSet = new Set([
4482
- ...(watchIds ?? []),
4483
- item[column_ref],
4484
- ]);
4485
- setValue(colLabel, [...newSet]);
4486
- }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
4487
- ? { color: "colorPalette.400/50" }
4488
- : {}), children: !!renderDisplay === true
4489
- ? renderDisplay(item)
4490
- : item[display_column] }, item[column_ref]));
4491
- }) }), dataList.length <= 0 && (jsx(Text, { children: searchText
4492
- ? translate.t(removeIndex(`${colLabel}.empty_search_result`))
4493
- : translate.t(removeIndex(`${colLabel}.initial_results`)) }))] }), jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4479
+ }, children: [jsx("option", { value: "5", children: "5" }), jsx("option", { value: "10", children: "10" }), jsx("option", { value: "20", children: "20" }), jsx("option", { value: "50", children: "50" })] }) })] }), jsx(Grid, { gridTemplateColumns: "repeat(auto-fit, minmax(15rem, 1fr))", overflow: "auto", maxHeight: "50vh", children: dataList.length > 0 ? (jsx(Flex, { flexFlow: "column wrap", children: dataList.map((item) => {
4480
+ const selected = isMultiple
4481
+ ? watchIds.some((id) => item[column_ref] === id)
4482
+ : watchId === item[column_ref];
4483
+ return (jsx(Box, { cursor: "pointer", onClick: () => {
4484
+ if (!isMultiple) {
4485
+ setOpenSearchResult(false);
4486
+ setValue(colLabel, item[column_ref]);
4487
+ return;
4488
+ }
4489
+ // For multiple selection, don't add if already selected
4490
+ if (selected)
4491
+ return;
4492
+ const newSet = new Set([
4493
+ ...(watchIds ?? []),
4494
+ item[column_ref],
4495
+ ]);
4496
+ setValue(colLabel, [...newSet]);
4497
+ }, opacity: 0.7, _hover: { opacity: 1 }, ...(selected
4498
+ ? { color: "colorPalette.400/50", fontWeight: "bold" }
4499
+ : {}), children: !!renderDisplay === true
4500
+ ? renderDisplay(item)
4501
+ : item[display_column] }, item[column_ref]));
4502
+ }) })) : (jsx(Text, { children: searchText
4503
+ ? translate.t(removeIndex(`${colLabel}.empty_search_result`))
4504
+ : translate.t(removeIndex(`${colLabel}.initial_results`)) })) }), jsx(PaginationRoot, { justifySelf: "center", count: count, pageSize: limit, defaultPage: 1, page: page + 1, onPageChange: (e) => setPage(e.page - 1), children: jsxs(HStack, { gap: "4", children: [jsx(PaginationPrevTrigger, {}), count > 0 && jsx(PaginationPageText, {}), jsx(PaginationNextTrigger, {})] }) })] }))] }) })] }), errors[`${colLabel}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4494
4505
  };
4495
4506
 
4496
4507
  const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
@@ -4699,42 +4710,180 @@ const TextAreaInput = ({ column, schema, prefix, }) => {
4699
4710
  function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem, meridiemLabel = {
4700
4711
  am: "am",
4701
4712
  pm: "pm",
4702
- }, onChange = () => { }, }) {
4703
- const hours = Array.from({ length: 12 }, (_, i) => {
4704
- const hour = i + 1;
4705
- return hour.toString().padStart(2, "0");
4706
- });
4707
- const minutes = Array.from({ length: 60 }, (_, i) => {
4708
- return i.toString().padStart(2, "0");
4709
- });
4710
- const hoursCollection = createListCollection({
4711
- items: hours.map((hour) => ({
4712
- value: hour,
4713
- label: hour,
4714
- })),
4715
- });
4716
- const minutesCollection = createListCollection({
4717
- items: minutes.map((hour) => ({
4718
- value: hour,
4719
- label: hour,
4720
- })),
4721
- });
4722
- const meridiemsCollection = createListCollection({
4723
- items: ["am", "pm"].map((hour) => ({
4724
- value: hour,
4725
- label: meridiemLabel[hour] ?? hour,
4726
- })),
4727
- });
4728
- return (jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "auto auto auto auto", gap: "4", children: [jsxs(Select.Root, { width: "4rem", value: [`${hour.toString().padStart(2, "0")}`], onValueChange: (e) => {
4729
- setHour(parseInt(e.value[0]));
4730
- onChange({ hour: parseInt(e.value[0]), minute, meridiem });
4731
- }, collection: hoursCollection, children: [jsx(Select.HiddenSelect, {}), jsx(Select.Control, { children: jsx(Select.Trigger, { children: jsx(Select.ValueText, { placeholder: "Hour" }) }) }), jsx(Select.Positioner, { children: jsx(Select.Content, { children: hoursCollection.items.map(({ value: hour }) => (jsxs(Select.Item, { item: hour, children: [hour, jsx(Select.ItemIndicator, {})] }, hour))) }) })] }), jsx(Text, { children: ":" }), jsxs(Select.Root, { width: "4rem", value: [`${minute.toString().padStart(2, "0")}`], onValueChange: (e) => {
4732
- setMinute(parseInt(e.value[0]));
4733
- onChange({ hour, minute: parseInt(e.value[0]), meridiem });
4734
- }, collection: minutesCollection, children: [jsx(Select.HiddenSelect, {}), jsx(Select.Control, { children: jsx(Select.Trigger, { children: jsx(Select.ValueText, { placeholder: "Minute" }) }) }), jsx(Select.Positioner, { children: jsx(Select.Content, { children: minutes.map((minute) => (jsxs(Select.Item, { item: minute, children: [minute, jsx(Select.ItemIndicator, {})] }, minute))) }) })] }), jsxs(Select.Root, { width: "8rem", value: [meridiem], onValueChange: (e) => {
4735
- setMeridiem(e.value[0]);
4736
- onChange({ hour, minute, meridiem: e.value[0] });
4737
- }, collection: meridiemsCollection, children: [jsx(Select.HiddenSelect, {}), jsx(Select.Control, { children: jsx(Select.Trigger, { children: jsx(Select.ValueText, { placeholder: "am/pm" }) }) }), jsx(Select.Positioner, { children: jsx(Select.Content, { children: meridiemsCollection.items.map(({ value: hour, label }) => (jsxs(Select.Item, { item: hour, children: [label, jsx(Select.ItemIndicator, {})] }, hour))) }) })] })] }));
4713
+ }, onChange = (_newValue) => { }, }) {
4714
+ // Refs for focus management
4715
+ const hourInputRef = useRef(null);
4716
+ const minuteInputRef = useRef(null);
4717
+ const meridiemInputRef = useRef(null);
4718
+ // Centralized handler for key events, value changes, and focus management
4719
+ const handleKeyDown = (e, field) => {
4720
+ const input = e.target;
4721
+ const value = input.value;
4722
+ // Handle navigation between fields
4723
+ if (e.key === "Tab") {
4724
+ // Tab is handled by the browser, no need to override
4725
+ return;
4726
+ }
4727
+ if (e.key === ":" && field === "hour") {
4728
+ e.preventDefault();
4729
+ minuteInputRef.current?.focus();
4730
+ return;
4731
+ }
4732
+ if (e.key === "Backspace" && value === "") {
4733
+ e.preventDefault();
4734
+ if (field === "minute") {
4735
+ hourInputRef.current?.focus();
4736
+ }
4737
+ else if (field === "meridiem") {
4738
+ minuteInputRef.current?.focus();
4739
+ }
4740
+ return;
4741
+ }
4742
+ // Handle number inputs
4743
+ if (field === "hour") {
4744
+ if (e.key.match(/^[0-9]$/)) {
4745
+ const newValue = value + e.key;
4746
+ const numValue = parseInt(newValue, 10);
4747
+ console.log("newValue", newValue, numValue);
4748
+ if (numValue > 12) {
4749
+ const digitValue = parseInt(e.key, 10);
4750
+ setHour(digitValue);
4751
+ onChange({ hour: digitValue, minute, meridiem });
4752
+ return;
4753
+ }
4754
+ // Auto-advance to minutes if we have a valid hour (1-12)
4755
+ if (numValue >= 1 && numValue <= 12) {
4756
+ // Set the hour value
4757
+ setHour(numValue);
4758
+ onChange({ hour: numValue, minute, meridiem });
4759
+ // Move to minute input
4760
+ e.preventDefault();
4761
+ minuteInputRef.current?.focus();
4762
+ }
4763
+ }
4764
+ }
4765
+ else if (field === "minute") {
4766
+ if (e.key.match(/^[0-9]$/)) {
4767
+ const newValue = value + e.key;
4768
+ const numValue = parseInt(newValue, 10);
4769
+ if (numValue > 60) {
4770
+ const digitValue = parseInt(e.key, 10);
4771
+ setHour(digitValue);
4772
+ onChange({ hour, minute: digitValue, meridiem });
4773
+ return;
4774
+ }
4775
+ // Auto-advance to meridiem if we have a valid minute (0-59)
4776
+ if (numValue >= 0 && numValue <= 59) {
4777
+ // Set the minute value
4778
+ setMinute(numValue);
4779
+ onChange({ hour, minute: numValue, meridiem });
4780
+ // Move to meridiem input
4781
+ e.preventDefault();
4782
+ meridiemInputRef.current?.focus();
4783
+ }
4784
+ }
4785
+ }
4786
+ else if (field === "meridiem") {
4787
+ const key = e.key.toLowerCase();
4788
+ if (key === "a") {
4789
+ e.preventDefault();
4790
+ setMeridiem("am");
4791
+ onChange({ hour, minute, meridiem: "am" });
4792
+ input.value = "am";
4793
+ }
4794
+ else if (key === "p") {
4795
+ e.preventDefault();
4796
+ setMeridiem("pm");
4797
+ onChange({ hour, minute, meridiem: "pm" });
4798
+ input.value = "pm";
4799
+ }
4800
+ }
4801
+ };
4802
+ // Handle input blur events to validate and format values
4803
+ const handleBlur = (e, field) => {
4804
+ const value = e.target.value;
4805
+ if (field === "hour") {
4806
+ if (value === "") {
4807
+ if (hour !== null) {
4808
+ setHour(null);
4809
+ onChange({ hour: null, minute, meridiem });
4810
+ }
4811
+ return;
4812
+ }
4813
+ const numValue = parseInt(value, 10);
4814
+ if (isNaN(numValue) || numValue < 1 || numValue > 12) {
4815
+ setHour(null);
4816
+ onChange({ hour: null, minute, meridiem });
4817
+ }
4818
+ else if (hour !== numValue) {
4819
+ setHour(numValue);
4820
+ onChange({ hour: numValue, minute, meridiem });
4821
+ }
4822
+ }
4823
+ else if (field === "minute") {
4824
+ if (value === "") {
4825
+ if (minute !== null) {
4826
+ setMinute(null);
4827
+ onChange({ hour, minute: null, meridiem });
4828
+ }
4829
+ return;
4830
+ }
4831
+ const numValue = parseInt(value, 10);
4832
+ if (isNaN(numValue) || numValue < 0 || numValue > 59) {
4833
+ setMinute(null);
4834
+ onChange({ hour, minute: null, meridiem });
4835
+ }
4836
+ else if (minute !== numValue) {
4837
+ setMinute(numValue);
4838
+ onChange({ hour, minute: numValue, meridiem });
4839
+ }
4840
+ }
4841
+ else if (field === "meridiem") {
4842
+ if (value === "") {
4843
+ if (meridiem !== null) {
4844
+ setMeridiem(null);
4845
+ onChange({ hour, minute, meridiem: null });
4846
+ }
4847
+ return;
4848
+ }
4849
+ const lowerValue = value.toLowerCase();
4850
+ if (lowerValue !== "am" && lowerValue !== "pm") {
4851
+ if (lowerValue === "a") {
4852
+ setMeridiem("am");
4853
+ onChange({ hour, minute, meridiem: "am" });
4854
+ }
4855
+ else if (lowerValue === "p") {
4856
+ setMeridiem("pm");
4857
+ onChange({ hour, minute, meridiem: "pm" });
4858
+ }
4859
+ else {
4860
+ setMeridiem(null);
4861
+ onChange({ hour, minute, meridiem: null });
4862
+ }
4863
+ }
4864
+ else if (meridiem !== lowerValue) {
4865
+ setMeridiem(lowerValue);
4866
+ onChange({ hour, minute, meridiem: lowerValue });
4867
+ }
4868
+ }
4869
+ };
4870
+ // Handle meridiem button click
4871
+ const handleMeridiemClick = (newMeridiem) => {
4872
+ setMeridiem(newMeridiem);
4873
+ onChange({ hour, minute, meridiem: newMeridiem });
4874
+ };
4875
+ const handleClear = () => {
4876
+ setHour(null);
4877
+ setMinute(null);
4878
+ setMeridiem(null);
4879
+ onChange({ hour: null, minute: null, meridiem: null });
4880
+ // Focus the hour field after clearing
4881
+ hourInputRef.current?.focus();
4882
+ };
4883
+ function handleFocus(event) {
4884
+ event.target.select();
4885
+ }
4886
+ return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 90px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsx(Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), onBlur: (e) => handleBlur(e, "hour"), onFocus: handleFocus, placeholder: "HH", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), onBlur: (e) => handleBlur(e, "minute"), onFocus: handleFocus, placeholder: "MM", maxLength: 2, textAlign: "center" }), jsxs(Flex, { gap: "1", children: [jsx(Button$1, { size: "sm", colorScheme: meridiem === "am" ? "blue" : "gray", variant: meridiem === "am" ? "solid" : "outline", onClick: () => handleMeridiemClick("am"), width: "40px", children: meridiemLabel.am }), jsx(Button$1, { size: "sm", colorScheme: meridiem === "pm" ? "blue" : "gray", variant: meridiem === "pm" ? "solid" : "outline", onClick: () => handleMeridiemClick("pm"), width: "40px", children: meridiemLabel.pm })] }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }) }));
4738
4887
  }
4739
4888
 
4740
4889
  const TimePicker = ({ column, schema, prefix }) => {
@@ -4745,7 +4894,7 @@ const TimePicker = ({ column, schema, prefix }) => {
4745
4894
  const colLabel = `${prefix}${column}`;
4746
4895
  const [open, setOpen] = useState(false);
4747
4896
  const value = watch(colLabel);
4748
- const formatedTime = dayjs(value).format("hh:mm A");
4897
+ const formatedTime = value ? dayjs(value).format("hh:mm A") : "";
4749
4898
  // Parse the initial time parts from the ISO time string (HH:mm:ss)
4750
4899
  const parseTime = (isoTime) => {
4751
4900
  if (!isoTime)
@@ -4774,6 +4923,8 @@ const TimePicker = ({ column, schema, prefix }) => {
4774
4923
  }, [value]);
4775
4924
  // Convert hour, minute, meridiem to 24-hour ISO time string
4776
4925
  const toIsoTime = (hour, minute, meridiem) => {
4926
+ if (hour === null || minute === null || meridiem === null)
4927
+ return null;
4777
4928
  let h = hour;
4778
4929
  if (meridiem === "am" && hour === 12)
4779
4930
  h = 0;
@@ -4794,8 +4945,8 @@ const TimePicker = ({ column, schema, prefix }) => {
4794
4945
  gridRow, children: [jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
4795
4946
  setOpen(true);
4796
4947
  }, justifyContent: "start", children: [jsx(IoMdClock, {}), value !== undefined ? `${formatedTime}` : ""] }) }), jsx(Portal, { children: jsx(Popover.Positioner, { children: jsx(Popover.Content, { ref: containerRef, children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
4797
- am: translate.t(removeIndex(`${colLabel}.am`)),
4798
- pm: translate.t(removeIndex(`${colLabel}.pm`)),
4948
+ am: translate.t(removeIndex(`common.am`)),
4949
+ pm: translate.t(removeIndex(`common.pm`)),
4799
4950
  } }) }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
4800
4951
  };
4801
4952
 
@@ -4991,7 +5142,7 @@ const NumberViewer = ({ schema, column, prefix, }) => {
4991
5142
  };
4992
5143
 
4993
5144
  const ObjectViewer = ({ schema, column, prefix }) => {
4994
- const { properties, gridColumn = "span 4", gridRow = "span 1", required, } = schema;
5145
+ const { properties, gridColumn = "span 12", gridRow = "span 1", required, } = schema;
4995
5146
  const { translate } = useSchemaContext();
4996
5147
  const colLabel = `${prefix}${column}`;
4997
5148
  const isRequired = required?.some((columnId) => columnId === column);
@@ -4999,7 +5150,7 @@ const ObjectViewer = ({ schema, column, prefix }) => {
4999
5150
  if (properties === undefined) {
5000
5151
  throw new Error(`properties is undefined when using ObjectInput`);
5001
5152
  }
5002
- return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", gridColumn: "1/span12", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", gridTemplateRows: `repeat("auto-fit", auto)`, children: Object.keys(properties ?? {}).map((key) => {
5153
+ return (jsxs(Box, { gridRow, gridColumn, children: [jsxs(Box, { as: "label", children: [`${translate.t(removeIndex(`${colLabel}.field_label`))}`, isRequired && jsx("span", { children: "*" })] }), jsx(Grid, { gap: "4", padding: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: Object.keys(properties ?? {}).map((key) => {
5003
5154
  return (
5004
5155
  // @ts-expect-error find suitable types
5005
5156
  jsx(ColumnViewer, { column: `${key}`,
@@ -1,14 +1,15 @@
1
+ import { Dispatch, SetStateAction } from "react";
1
2
  interface TimePickerProps {
2
- hour: number;
3
- setHour: (hour: number) => void;
4
- minute: number;
5
- setMinute: (minute: number) => void;
6
- meridiem: "am" | "pm";
7
- setMeridiem: (meridiem: "am" | "pm") => void;
3
+ hour: number | null;
4
+ setHour: Dispatch<SetStateAction<number | null>>;
5
+ minute: number | null;
6
+ setMinute: Dispatch<SetStateAction<number | null>>;
7
+ meridiem: "am" | "pm" | null;
8
+ setMeridiem: Dispatch<SetStateAction<"am" | "pm" | null>>;
8
9
  onChange?: (newValue: {
9
- hour: number;
10
- minute: number;
11
- meridiem: "am" | "pm";
10
+ hour: number | null;
11
+ minute: number | null;
12
+ meridiem: "am" | "pm" | null;
12
13
  }) => void;
13
14
  meridiemLabel?: {
14
15
  am: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsol-oss/react-datatable5",
3
- "version": "12.0.0-beta.37",
3
+ "version": "12.0.0-beta.39",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",