@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 +230 -79
- package/dist/index.mjs +231 -80
- package/dist/types/components/TimePicker/TimePicker.d.ts +10 -9
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
})
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: (
|
|
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.
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
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
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
}
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
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(
|
|
4818
|
-
pm: translate.t(removeIndex(
|
|
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
|
|
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",
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
})
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: (
|
|
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" })] }) })] }),
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
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
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
}
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
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(
|
|
4798
|
-
pm: translate.t(removeIndex(
|
|
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
|
|
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",
|
|
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:
|
|
4
|
-
minute: number;
|
|
5
|
-
setMinute:
|
|
6
|
-
meridiem: "am" | "pm";
|
|
7
|
-
setMeridiem:
|
|
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;
|