react-lookup-select 1.0.5 → 1.1.0
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/LICENSE +21 -21
- package/dist/index.cjs +181 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -16
- package/dist/index.d.ts +3 -16
- package/dist/index.js +188 -122
- package/dist/index.js.map +1 -1
- package/dist/styles.css +957 -862
- package/package.json +83 -79
- package/readme.md +440 -440
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import React3 from "react";
|
|
3
3
|
|
|
4
4
|
// src/internal/state.ts
|
|
5
|
-
import { useState, useCallback,
|
|
5
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
6
6
|
|
|
7
7
|
// src/internal/core.ts
|
|
8
8
|
function createSelectionState() {
|
|
@@ -174,12 +174,16 @@ function useLookupSelectState(props) {
|
|
|
174
174
|
},
|
|
175
175
|
[open, onOpenChange]
|
|
176
176
|
);
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
const selectionManagerRef = useRef(null);
|
|
178
|
+
if (!selectionManagerRef.current) {
|
|
179
|
+
selectionManagerRef.current = new SelectionManager(mode, mapper);
|
|
180
|
+
}
|
|
181
|
+
const selectionManager = selectionManagerRef.current;
|
|
182
|
+
const queryManagerRef = useRef(null);
|
|
183
|
+
if (!queryManagerRef.current) {
|
|
184
|
+
queryManagerRef.current = new QueryManager({ pageSize });
|
|
185
|
+
}
|
|
186
|
+
const queryManager = queryManagerRef.current;
|
|
183
187
|
const [currentSelections, setCurrentSelections] = useState([]);
|
|
184
188
|
const [backupSelections, setBackupSelections] = useState([]);
|
|
185
189
|
const resolveValueToRows = useCallback(
|
|
@@ -197,6 +201,10 @@ function useLookupSelectState(props) {
|
|
|
197
201
|
);
|
|
198
202
|
if (matchingRow) {
|
|
199
203
|
resolvedRows.push(matchingRow);
|
|
204
|
+
} else if (typeof console !== "undefined") {
|
|
205
|
+
console.warn(
|
|
206
|
+
`[react-lookup-select] Could not resolve value with id "${searchId}" from data. Ensure the value matches an item in the data array.`
|
|
207
|
+
);
|
|
200
208
|
}
|
|
201
209
|
}
|
|
202
210
|
}
|
|
@@ -218,7 +226,7 @@ function useLookupSelectState(props) {
|
|
|
218
226
|
}, [value, defaultValue, data, resolveValueToRows, selectionManager]);
|
|
219
227
|
const toggleRowSelection = useCallback(
|
|
220
228
|
(row) => {
|
|
221
|
-
|
|
229
|
+
selectionManager.toggleRow(row);
|
|
222
230
|
const selectedRows = selectionManager.getSelectedRows();
|
|
223
231
|
setCurrentSelections(selectedRows);
|
|
224
232
|
if (!modalOpen) {
|
|
@@ -242,8 +250,6 @@ function useLookupSelectState(props) {
|
|
|
242
250
|
);
|
|
243
251
|
const updateQuery = useCallback(
|
|
244
252
|
(updates) => {
|
|
245
|
-
const currentState = queryManager.getState();
|
|
246
|
-
const newState = { ...currentState, ...updates };
|
|
247
253
|
if (updates.search !== void 0) {
|
|
248
254
|
queryManager.updateSearch(updates.search);
|
|
249
255
|
}
|
|
@@ -320,21 +326,12 @@ function useLookupSelectState(props) {
|
|
|
320
326
|
import { useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
321
327
|
function useKeyboardNavigation({
|
|
322
328
|
isModalOpen,
|
|
323
|
-
|
|
324
|
-
onConfirm,
|
|
325
|
-
onRowSelect,
|
|
326
|
-
currentData,
|
|
327
|
-
selectedRows,
|
|
328
|
-
mode
|
|
329
|
+
onConfirm
|
|
329
330
|
}) {
|
|
330
331
|
const handleKeyDown = useCallback2(
|
|
331
332
|
(event) => {
|
|
332
333
|
if (!isModalOpen) return;
|
|
333
334
|
switch (event.key) {
|
|
334
|
-
case "Escape":
|
|
335
|
-
event.preventDefault();
|
|
336
|
-
onClose();
|
|
337
|
-
break;
|
|
338
335
|
case "Enter":
|
|
339
336
|
if (event.ctrlKey || event.metaKey) {
|
|
340
337
|
event.preventDefault();
|
|
@@ -342,13 +339,62 @@ function useKeyboardNavigation({
|
|
|
342
339
|
}
|
|
343
340
|
break;
|
|
344
341
|
case "ArrowDown":
|
|
345
|
-
case "ArrowUp":
|
|
342
|
+
case "ArrowUp": {
|
|
343
|
+
const grid = document.querySelector(
|
|
344
|
+
".lookup-select__grid tbody, .lookup-select__virtual-grid-body"
|
|
345
|
+
);
|
|
346
|
+
if (!grid) break;
|
|
347
|
+
const rows = grid.querySelectorAll(
|
|
348
|
+
'tr[tabindex="0"], tr[role="row"]'
|
|
349
|
+
);
|
|
350
|
+
if (rows.length === 0) break;
|
|
351
|
+
const currentIndex = Array.from(rows).findIndex(
|
|
352
|
+
(row) => row === document.activeElement
|
|
353
|
+
);
|
|
354
|
+
let nextIndex;
|
|
355
|
+
if (event.key === "ArrowDown") {
|
|
356
|
+
nextIndex = currentIndex < 0 ? 0 : Math.min(currentIndex + 1, rows.length - 1);
|
|
357
|
+
} else {
|
|
358
|
+
nextIndex = currentIndex < 0 ? rows.length - 1 : Math.max(currentIndex - 1, 0);
|
|
359
|
+
}
|
|
360
|
+
event.preventDefault();
|
|
361
|
+
rows[nextIndex]?.focus();
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
case "Home": {
|
|
365
|
+
const gridHome = document.querySelector(
|
|
366
|
+
".lookup-select__grid tbody, .lookup-select__virtual-grid-body"
|
|
367
|
+
);
|
|
368
|
+
if (!gridHome) break;
|
|
369
|
+
const firstRow = gridHome.querySelector(
|
|
370
|
+
'tr[tabindex="0"], tr[role="row"]'
|
|
371
|
+
);
|
|
372
|
+
if (firstRow) {
|
|
373
|
+
event.preventDefault();
|
|
374
|
+
firstRow.focus();
|
|
375
|
+
}
|
|
346
376
|
break;
|
|
377
|
+
}
|
|
378
|
+
case "End": {
|
|
379
|
+
const gridEnd = document.querySelector(
|
|
380
|
+
".lookup-select__grid tbody, .lookup-select__virtual-grid-body"
|
|
381
|
+
);
|
|
382
|
+
if (!gridEnd) break;
|
|
383
|
+
const allRows = gridEnd.querySelectorAll(
|
|
384
|
+
'tr[tabindex="0"], tr[role="row"]'
|
|
385
|
+
);
|
|
386
|
+
const lastRow = allRows[allRows.length - 1];
|
|
387
|
+
if (lastRow) {
|
|
388
|
+
event.preventDefault();
|
|
389
|
+
lastRow.focus();
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
347
393
|
default:
|
|
348
394
|
break;
|
|
349
395
|
}
|
|
350
396
|
},
|
|
351
|
-
[isModalOpen,
|
|
397
|
+
[isModalOpen, onConfirm]
|
|
352
398
|
);
|
|
353
399
|
useEffect2(() => {
|
|
354
400
|
if (isModalOpen) {
|
|
@@ -362,36 +408,7 @@ function useKeyboardNavigation({
|
|
|
362
408
|
handleKeyDown
|
|
363
409
|
};
|
|
364
410
|
}
|
|
365
|
-
function useFocusManagement(
|
|
366
|
-
useEffect2(() => {
|
|
367
|
-
if (!isOpen) return;
|
|
368
|
-
const modal = document.querySelector('[role="dialog"]');
|
|
369
|
-
if (!modal) return;
|
|
370
|
-
const focusableElements = modal.querySelectorAll(
|
|
371
|
-
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
372
|
-
);
|
|
373
|
-
const firstFocusable = focusableElements[0];
|
|
374
|
-
const lastFocusable = focusableElements[focusableElements.length - 1];
|
|
375
|
-
firstFocusable?.focus();
|
|
376
|
-
const handleTabKey = (e) => {
|
|
377
|
-
if (e.key !== "Tab") return;
|
|
378
|
-
if (e.shiftKey) {
|
|
379
|
-
if (document.activeElement === firstFocusable) {
|
|
380
|
-
e.preventDefault();
|
|
381
|
-
lastFocusable?.focus();
|
|
382
|
-
}
|
|
383
|
-
} else {
|
|
384
|
-
if (document.activeElement === lastFocusable) {
|
|
385
|
-
e.preventDefault();
|
|
386
|
-
firstFocusable?.focus();
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
document.addEventListener("keydown", handleTabKey);
|
|
391
|
-
return () => {
|
|
392
|
-
document.removeEventListener("keydown", handleTabKey);
|
|
393
|
-
};
|
|
394
|
-
}, [isOpen]);
|
|
411
|
+
function useFocusManagement(_isOpen) {
|
|
395
412
|
}
|
|
396
413
|
function useScreenReaderAnnouncements() {
|
|
397
414
|
const announce = useCallback2(
|
|
@@ -530,7 +547,7 @@ function Trigger({
|
|
|
530
547
|
}
|
|
531
548
|
|
|
532
549
|
// src/components/Modal.tsx
|
|
533
|
-
import { useEffect as useEffect3, useRef } from "react";
|
|
550
|
+
import { useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
534
551
|
import { createPortal } from "react-dom";
|
|
535
552
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
536
553
|
function Modal({
|
|
@@ -545,16 +562,23 @@ function Modal({
|
|
|
545
562
|
ariaDescribedBy,
|
|
546
563
|
closeButtonLabel = "Close modal"
|
|
547
564
|
}) {
|
|
548
|
-
const modalRef =
|
|
549
|
-
const previousFocusRef =
|
|
565
|
+
const modalRef = useRef2(null);
|
|
566
|
+
const previousFocusRef = useRef2(null);
|
|
550
567
|
useEffect3(() => {
|
|
551
568
|
if (!isOpen) return;
|
|
552
569
|
previousFocusRef.current = document.activeElement;
|
|
553
|
-
const
|
|
554
|
-
|
|
570
|
+
const autoFocusElement = modalRef.current?.querySelector(
|
|
571
|
+
"[data-autofocus]"
|
|
555
572
|
);
|
|
556
|
-
if (
|
|
557
|
-
|
|
573
|
+
if (autoFocusElement) {
|
|
574
|
+
autoFocusElement.focus();
|
|
575
|
+
} else {
|
|
576
|
+
const focusableElements = modalRef.current?.querySelectorAll(
|
|
577
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
578
|
+
);
|
|
579
|
+
if (focusableElements && focusableElements.length > 0) {
|
|
580
|
+
focusableElements[0].focus();
|
|
581
|
+
}
|
|
558
582
|
}
|
|
559
583
|
const handleEscape = (e) => {
|
|
560
584
|
if (e.key === "Escape") {
|
|
@@ -563,12 +587,12 @@ function Modal({
|
|
|
563
587
|
};
|
|
564
588
|
const handleTab = (e) => {
|
|
565
589
|
if (e.key !== "Tab") return;
|
|
566
|
-
const
|
|
590
|
+
const focusableElements = modalRef.current?.querySelectorAll(
|
|
567
591
|
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
568
592
|
);
|
|
569
|
-
if (!
|
|
570
|
-
const firstElement =
|
|
571
|
-
const lastElement =
|
|
593
|
+
if (!focusableElements || focusableElements.length === 0) return;
|
|
594
|
+
const firstElement = focusableElements[0];
|
|
595
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
572
596
|
if (e.shiftKey) {
|
|
573
597
|
if (document.activeElement === firstElement) {
|
|
574
598
|
lastElement.focus();
|
|
@@ -659,23 +683,17 @@ function SearchInput({
|
|
|
659
683
|
placeholder = "Search...",
|
|
660
684
|
className
|
|
661
685
|
}) {
|
|
662
|
-
const inputRef = useRef(null);
|
|
663
|
-
useEffect3(() => {
|
|
664
|
-
if (inputRef.current) {
|
|
665
|
-
inputRef.current.focus();
|
|
666
|
-
}
|
|
667
|
-
}, []);
|
|
668
686
|
return /* @__PURE__ */ jsxs2("div", { className: `lookup-select__search ${className || ""}`, children: [
|
|
669
687
|
/* @__PURE__ */ jsx2(
|
|
670
688
|
"input",
|
|
671
689
|
{
|
|
672
|
-
ref: inputRef,
|
|
673
690
|
type: "text",
|
|
674
691
|
value,
|
|
675
692
|
onChange: (e) => onChange(e.target.value),
|
|
676
693
|
placeholder,
|
|
677
694
|
className: "lookup-select__search-input",
|
|
678
|
-
"aria-label": "Search records"
|
|
695
|
+
"aria-label": "Search records",
|
|
696
|
+
"data-autofocus": true
|
|
679
697
|
}
|
|
680
698
|
),
|
|
681
699
|
/* @__PURE__ */ jsx2("div", { className: "lookup-select__search-icon", children: /* @__PURE__ */ jsx2("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsx2("path", { d: "M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z" }) }) })
|
|
@@ -732,6 +750,7 @@ function Grid({
|
|
|
732
750
|
loading = false,
|
|
733
751
|
error,
|
|
734
752
|
emptyText = "No records found",
|
|
753
|
+
onRetry,
|
|
735
754
|
className,
|
|
736
755
|
style
|
|
737
756
|
}) {
|
|
@@ -752,13 +771,33 @@ function Grid({
|
|
|
752
771
|
return currentSort.sortDir === "asc" ? "\u2191" : "\u2193";
|
|
753
772
|
};
|
|
754
773
|
if (loading) {
|
|
755
|
-
return /* @__PURE__ */ jsx3("div", { className:
|
|
774
|
+
return /* @__PURE__ */ jsx3("div", { className: `lookup-select__grid ${className || ""}`, style, children: /* @__PURE__ */ jsxs3("table", { className: "lookup-select__table", children: [
|
|
775
|
+
/* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs3("tr", { children: [
|
|
776
|
+
mode === "multiple" && /* @__PURE__ */ jsx3("th", { className: "lookup-select__header-cell lookup-select__header-cell--checkbox" }),
|
|
777
|
+
columns.map((column) => /* @__PURE__ */ jsx3("th", { className: "lookup-select__header-cell", children: column.title }, String(column.key)))
|
|
778
|
+
] }) }),
|
|
779
|
+
/* @__PURE__ */ jsx3("tbody", { children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs3("tr", { className: "lookup-select__grid-row lookup-select__grid-row--skeleton", children: [
|
|
780
|
+
mode === "multiple" && /* @__PURE__ */ jsx3("td", { className: "lookup-select__cell" }),
|
|
781
|
+
columns.map((col, j) => /* @__PURE__ */ jsx3("td", { className: "lookup-select__cell", children: /* @__PURE__ */ jsx3("div", { className: "lookup-select__skeleton-line" }) }, j))
|
|
782
|
+
] }, i)) })
|
|
783
|
+
] }) });
|
|
756
784
|
}
|
|
757
785
|
if (error) {
|
|
758
|
-
return /* @__PURE__ */ jsx3("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */
|
|
759
|
-
"
|
|
760
|
-
|
|
761
|
-
|
|
786
|
+
return /* @__PURE__ */ jsx3("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */ jsxs3("div", { className: "lookup-select__error", children: [
|
|
787
|
+
/* @__PURE__ */ jsxs3("p", { children: [
|
|
788
|
+
"Error: ",
|
|
789
|
+
error
|
|
790
|
+
] }),
|
|
791
|
+
onRetry && /* @__PURE__ */ jsx3(
|
|
792
|
+
"button",
|
|
793
|
+
{
|
|
794
|
+
type: "button",
|
|
795
|
+
className: "lookup-select__button lookup-select__button--secondary",
|
|
796
|
+
onClick: onRetry,
|
|
797
|
+
children: "Retry"
|
|
798
|
+
}
|
|
799
|
+
)
|
|
800
|
+
] }) });
|
|
762
801
|
}
|
|
763
802
|
if (data.length === 0) {
|
|
764
803
|
return /* @__PURE__ */ jsx3("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */ jsx3("div", { className: "lookup-select__empty", children: /* @__PURE__ */ jsx3("p", { children: emptyText }) }) });
|
|
@@ -830,7 +869,7 @@ function Grid({
|
|
|
830
869
|
"aria-label": "Select all"
|
|
831
870
|
}
|
|
832
871
|
) }) }),
|
|
833
|
-
columns.map((column
|
|
872
|
+
columns.map((column) => /* @__PURE__ */ jsx3(
|
|
834
873
|
"th",
|
|
835
874
|
{
|
|
836
875
|
className: "lookup-select__table-header",
|
|
@@ -886,7 +925,7 @@ function Grid({
|
|
|
886
925
|
"aria-label": `Select ${mapper.getText(row)}`
|
|
887
926
|
}
|
|
888
927
|
) }) }),
|
|
889
|
-
columns.map((column
|
|
928
|
+
columns.map((column) => {
|
|
890
929
|
const cellKey = `${rowId}-${typeof column.key === "string" ? column.key : String(column.key)}`;
|
|
891
930
|
let cellContent;
|
|
892
931
|
if (column.render) {
|
|
@@ -948,13 +987,16 @@ function VirtualGrid(props) {
|
|
|
948
987
|
return () => resizeObserver.disconnect();
|
|
949
988
|
}
|
|
950
989
|
}, []);
|
|
990
|
+
const selectableCount = React2.useMemo(() => {
|
|
991
|
+
return selectableRow ? data.filter(selectableRow).length : data.length;
|
|
992
|
+
}, [data, selectableRow]);
|
|
951
993
|
React2.useEffect(() => {
|
|
952
994
|
if (headerCheckboxRef.current) {
|
|
953
995
|
const hasSelected = selectedRows.length > 0;
|
|
954
|
-
const hasUnselected = selectedRows.length <
|
|
996
|
+
const hasUnselected = selectedRows.length < selectableCount;
|
|
955
997
|
headerCheckboxRef.current.indeterminate = hasSelected && hasUnselected;
|
|
956
998
|
}
|
|
957
|
-
}, [selectedRows.length,
|
|
999
|
+
}, [selectedRows.length, selectableCount]);
|
|
958
1000
|
const itemCount = data.length;
|
|
959
1001
|
const { rowHeight, overscan } = virtualization;
|
|
960
1002
|
const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
|
|
@@ -1029,7 +1071,7 @@ function VirtualGrid(props) {
|
|
|
1029
1071
|
ref: headerCheckboxRef,
|
|
1030
1072
|
type: "checkbox",
|
|
1031
1073
|
className: "lookup-select__checkbox",
|
|
1032
|
-
checked: selectedRows.length ===
|
|
1074
|
+
checked: selectedRows.length === selectableCount && selectableCount > 0,
|
|
1033
1075
|
onChange: (e) => {
|
|
1034
1076
|
if (e.target.checked) {
|
|
1035
1077
|
data.forEach((row) => {
|
|
@@ -1112,9 +1154,11 @@ function VirtualRowComponent({
|
|
|
1112
1154
|
item,
|
|
1113
1155
|
columns,
|
|
1114
1156
|
mode,
|
|
1157
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1115
1158
|
mapper,
|
|
1116
1159
|
isSelected,
|
|
1117
1160
|
isSelectable,
|
|
1161
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1118
1162
|
onToggle,
|
|
1119
1163
|
onCheckboxChange,
|
|
1120
1164
|
onClick
|
|
@@ -1156,13 +1200,14 @@ var VirtualRow = React2.memo(
|
|
|
1156
1200
|
);
|
|
1157
1201
|
|
|
1158
1202
|
// src/components/Pagination.tsx
|
|
1159
|
-
import {
|
|
1203
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1160
1204
|
function Pagination({
|
|
1161
1205
|
currentPage,
|
|
1162
1206
|
totalCount,
|
|
1163
1207
|
pageSize,
|
|
1164
1208
|
onPageChange,
|
|
1165
|
-
className
|
|
1209
|
+
className,
|
|
1210
|
+
i18n
|
|
1166
1211
|
}) {
|
|
1167
1212
|
const totalPages = Math.ceil(totalCount / pageSize);
|
|
1168
1213
|
if (totalPages <= 1) {
|
|
@@ -1192,14 +1237,7 @@ function Pagination({
|
|
|
1192
1237
|
const startRecord = (currentPage - 1) * pageSize + 1;
|
|
1193
1238
|
const endRecord = Math.min(currentPage * pageSize, totalCount);
|
|
1194
1239
|
return /* @__PURE__ */ jsxs5("div", { className: `lookup-select__pagination ${className || ""}`, children: [
|
|
1195
|
-
/* @__PURE__ */ jsx5("div", { className: "lookup-select__pagination-info", children: totalCount > 0 ?
|
|
1196
|
-
startRecord,
|
|
1197
|
-
"-",
|
|
1198
|
-
endRecord,
|
|
1199
|
-
" / ",
|
|
1200
|
-
totalCount,
|
|
1201
|
-
" records"
|
|
1202
|
-
] }) : "0 records" }),
|
|
1240
|
+
/* @__PURE__ */ jsx5("div", { className: "lookup-select__pagination-info", children: totalCount > 0 ? i18n?.recordsInfo ? i18n.recordsInfo(startRecord, endRecord, totalCount) : `${startRecord}-${endRecord} / ${totalCount} records` : "0 records" }),
|
|
1203
1241
|
/* @__PURE__ */ jsxs5("div", { className: "lookup-select__pagination-controls", children: [
|
|
1204
1242
|
/* @__PURE__ */ jsx5(
|
|
1205
1243
|
"button",
|
|
@@ -1208,7 +1246,7 @@ function Pagination({
|
|
|
1208
1246
|
className: "lookup-select__pagination-button",
|
|
1209
1247
|
disabled: currentPage === 1,
|
|
1210
1248
|
onClick: () => onPageChange(currentPage - 1),
|
|
1211
|
-
"aria-label": "Previous page",
|
|
1249
|
+
"aria-label": i18n?.previousPage || "Previous page",
|
|
1212
1250
|
children: "\u2039"
|
|
1213
1251
|
}
|
|
1214
1252
|
),
|
|
@@ -1233,7 +1271,7 @@ function Pagination({
|
|
|
1233
1271
|
${currentPage === pageNum ? "lookup-select__pagination-button--active" : ""}
|
|
1234
1272
|
`,
|
|
1235
1273
|
onClick: () => onPageChange(pageNum),
|
|
1236
|
-
"aria-label": `
|
|
1274
|
+
"aria-label": i18n?.pageLabel ? i18n.pageLabel(pageNum) : `Page ${pageNum}`,
|
|
1237
1275
|
"aria-current": currentPage === pageNum ? "page" : void 0,
|
|
1238
1276
|
children: pageNum
|
|
1239
1277
|
},
|
|
@@ -1247,7 +1285,7 @@ function Pagination({
|
|
|
1247
1285
|
className: "lookup-select__pagination-button",
|
|
1248
1286
|
disabled: currentPage === totalPages,
|
|
1249
1287
|
onClick: () => onPageChange(currentPage + 1),
|
|
1250
|
-
"aria-label": "Next page",
|
|
1288
|
+
"aria-label": i18n?.nextPage || "Next page",
|
|
1251
1289
|
children: "\u203A"
|
|
1252
1290
|
}
|
|
1253
1291
|
)
|
|
@@ -1256,7 +1294,7 @@ function Pagination({
|
|
|
1256
1294
|
}
|
|
1257
1295
|
|
|
1258
1296
|
// src/components/LookupSelect.tsx
|
|
1259
|
-
import { Fragment
|
|
1297
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1260
1298
|
function LookupSelect(props) {
|
|
1261
1299
|
const {
|
|
1262
1300
|
columns,
|
|
@@ -1270,7 +1308,6 @@ function LookupSelect(props) {
|
|
|
1270
1308
|
renderTrigger,
|
|
1271
1309
|
renderModal,
|
|
1272
1310
|
renderGrid,
|
|
1273
|
-
renderHeader,
|
|
1274
1311
|
renderFooter,
|
|
1275
1312
|
renderSearch,
|
|
1276
1313
|
renderPagination,
|
|
@@ -1290,7 +1327,6 @@ function LookupSelect(props) {
|
|
|
1290
1327
|
const {
|
|
1291
1328
|
modalOpen,
|
|
1292
1329
|
openModal,
|
|
1293
|
-
closeModal,
|
|
1294
1330
|
currentSelections,
|
|
1295
1331
|
toggleRowSelection,
|
|
1296
1332
|
clearSelections,
|
|
@@ -1335,11 +1371,10 @@ function LookupSelect(props) {
|
|
|
1335
1371
|
virtualRowHeight,
|
|
1336
1372
|
pageSize
|
|
1337
1373
|
]);
|
|
1338
|
-
|
|
1374
|
+
useScreenReaderAnnouncements();
|
|
1339
1375
|
useFocusManagement(modalOpen);
|
|
1340
1376
|
useKeyboardNavigation({
|
|
1341
1377
|
isModalOpen: modalOpen,
|
|
1342
|
-
onClose: closeModal,
|
|
1343
1378
|
onConfirm: confirmSelection,
|
|
1344
1379
|
currentData: [],
|
|
1345
1380
|
selectedRows: currentSelections,
|
|
@@ -1351,13 +1386,34 @@ function LookupSelect(props) {
|
|
|
1351
1386
|
const [serverData, setServerData] = React3.useState([]);
|
|
1352
1387
|
const [totalCount, setTotalCount] = React3.useState(0);
|
|
1353
1388
|
const [currentPage, setCurrentPage] = React3.useState(1);
|
|
1389
|
+
const [sortState, setSortState] = React3.useState({});
|
|
1390
|
+
const [debouncedSearch, setDebouncedSearch] = React3.useState("");
|
|
1391
|
+
const debounceTimerRef = React3.useRef(null);
|
|
1354
1392
|
const handleSearchChange = React3.useCallback(
|
|
1355
1393
|
(value) => {
|
|
1356
1394
|
setSearchValue(value);
|
|
1357
|
-
|
|
1395
|
+
if (dataSource) {
|
|
1396
|
+
if (debounceTimerRef.current) {
|
|
1397
|
+
clearTimeout(debounceTimerRef.current);
|
|
1398
|
+
}
|
|
1399
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
1400
|
+
setDebouncedSearch(value);
|
|
1401
|
+
setCurrentPage(1);
|
|
1402
|
+
updateQuery({ search: value, page: 1 });
|
|
1403
|
+
}, 300);
|
|
1404
|
+
} else {
|
|
1405
|
+
updateQuery({ search: value, page: 1 });
|
|
1406
|
+
}
|
|
1358
1407
|
},
|
|
1359
|
-
[updateQuery]
|
|
1408
|
+
[updateQuery, dataSource]
|
|
1360
1409
|
);
|
|
1410
|
+
React3.useEffect(() => {
|
|
1411
|
+
return () => {
|
|
1412
|
+
if (debounceTimerRef.current) {
|
|
1413
|
+
clearTimeout(debounceTimerRef.current);
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
}, []);
|
|
1361
1417
|
const filteredData = React3.useMemo(() => {
|
|
1362
1418
|
if (!searchValue || dataSource) {
|
|
1363
1419
|
return data;
|
|
@@ -1375,13 +1431,14 @@ function LookupSelect(props) {
|
|
|
1375
1431
|
setLoading(true);
|
|
1376
1432
|
setError(void 0);
|
|
1377
1433
|
try {
|
|
1378
|
-
const query =
|
|
1379
|
-
|
|
1380
|
-
...query,
|
|
1381
|
-
search: searchValue,
|
|
1434
|
+
const query = {
|
|
1435
|
+
search: debouncedSearch,
|
|
1382
1436
|
page: currentPage,
|
|
1383
|
-
pageSize: optimizedPageSize
|
|
1384
|
-
|
|
1437
|
+
pageSize: optimizedPageSize,
|
|
1438
|
+
sortBy: sortState.sortBy,
|
|
1439
|
+
sortDir: sortState.sortDir
|
|
1440
|
+
};
|
|
1441
|
+
const result = await dataSource(query);
|
|
1385
1442
|
setServerData(result.rows);
|
|
1386
1443
|
setTotalCount(result.total);
|
|
1387
1444
|
setLoading(false);
|
|
@@ -1393,10 +1450,10 @@ function LookupSelect(props) {
|
|
|
1393
1450
|
}
|
|
1394
1451
|
}, [
|
|
1395
1452
|
dataSource,
|
|
1396
|
-
|
|
1397
|
-
searchValue,
|
|
1453
|
+
debouncedSearch,
|
|
1398
1454
|
currentPage,
|
|
1399
|
-
optimizedPageSize
|
|
1455
|
+
optimizedPageSize,
|
|
1456
|
+
sortState
|
|
1400
1457
|
]);
|
|
1401
1458
|
React3.useEffect(() => {
|
|
1402
1459
|
if (dataSource && modalOpen) {
|
|
@@ -1412,8 +1469,9 @@ function LookupSelect(props) {
|
|
|
1412
1469
|
);
|
|
1413
1470
|
const handleSortChange = React3.useCallback(
|
|
1414
1471
|
(sortBy, sortDir) => {
|
|
1415
|
-
|
|
1472
|
+
setSortState({ sortBy, sortDir });
|
|
1416
1473
|
setCurrentPage(1);
|
|
1474
|
+
updateQuery({ sortBy, sortDir, page: 1 });
|
|
1417
1475
|
},
|
|
1418
1476
|
[updateQuery]
|
|
1419
1477
|
);
|
|
@@ -1450,11 +1508,12 @@ function LookupSelect(props) {
|
|
|
1450
1508
|
loading,
|
|
1451
1509
|
error,
|
|
1452
1510
|
emptyText: texts.emptyText,
|
|
1511
|
+
onRetry: dataSource ? loadServerData : void 0,
|
|
1453
1512
|
className: classNames?.grid,
|
|
1454
1513
|
style: styles?.grid,
|
|
1455
1514
|
currentSort: dataSource ? {
|
|
1456
|
-
sortBy:
|
|
1457
|
-
sortDir:
|
|
1515
|
+
sortBy: sortState.sortBy || "",
|
|
1516
|
+
sortDir: sortState.sortDir || "asc"
|
|
1458
1517
|
} : void 0,
|
|
1459
1518
|
onSort: dataSource ? handleSortChange : void 0
|
|
1460
1519
|
};
|
|
@@ -1489,7 +1548,7 @@ function LookupSelect(props) {
|
|
|
1489
1548
|
virtualizationConfig
|
|
1490
1549
|
]);
|
|
1491
1550
|
const renderModalContent = () => {
|
|
1492
|
-
const defaultContent = /* @__PURE__ */ jsxs6(
|
|
1551
|
+
const defaultContent = /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
1493
1552
|
renderSearch ? renderSearch({
|
|
1494
1553
|
value: searchValue,
|
|
1495
1554
|
onChange: handleSearchChange,
|
|
@@ -1511,12 +1570,14 @@ function LookupSelect(props) {
|
|
|
1511
1570
|
selectedIds: currentSelections.map(mapper.getId),
|
|
1512
1571
|
onRowSelect: toggleRowSelection,
|
|
1513
1572
|
onSelectAll: mode === "multiple" ? () => {
|
|
1514
|
-
const
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1573
|
+
const selectableData = selectableRow ? currentData.filter(selectableRow) : currentData;
|
|
1574
|
+
const allSelected = selectableData.every(
|
|
1575
|
+
(row) => isRowSelected(row)
|
|
1576
|
+
);
|
|
1577
|
+
if (allSelected) {
|
|
1517
1578
|
clearSelections();
|
|
1518
1579
|
} else {
|
|
1519
|
-
|
|
1580
|
+
selectableData.forEach((row) => {
|
|
1520
1581
|
if (!isRowSelected(row)) {
|
|
1521
1582
|
toggleRowSelection(row);
|
|
1522
1583
|
}
|
|
@@ -1531,8 +1592,8 @@ function LookupSelect(props) {
|
|
|
1531
1592
|
virtualization: shouldUseVirtualization ? virtualizationConfig : void 0,
|
|
1532
1593
|
selectableRow,
|
|
1533
1594
|
onSortChange: handleSortChange,
|
|
1534
|
-
sortBy:
|
|
1535
|
-
sortDir:
|
|
1595
|
+
sortBy: sortState.sortBy,
|
|
1596
|
+
sortDir: sortState.sortDir
|
|
1536
1597
|
}) : renderGridComponent(),
|
|
1537
1598
|
dataSource && !renderPagination && /* @__PURE__ */ jsx6(
|
|
1538
1599
|
Pagination,
|
|
@@ -1540,7 +1601,12 @@ function LookupSelect(props) {
|
|
|
1540
1601
|
currentPage,
|
|
1541
1602
|
totalCount,
|
|
1542
1603
|
pageSize: optimizedPageSize,
|
|
1543
|
-
onPageChange: handlePageChange
|
|
1604
|
+
onPageChange: handlePageChange,
|
|
1605
|
+
i18n: {
|
|
1606
|
+
previousPage: i18n?.previousPage,
|
|
1607
|
+
nextPage: i18n?.nextPage,
|
|
1608
|
+
pageLabel: i18n?.paginationInfo ? (pageNum) => i18n.paginationInfo(pageNum, Math.ceil(totalCount / optimizedPageSize)) : void 0
|
|
1609
|
+
}
|
|
1544
1610
|
}
|
|
1545
1611
|
),
|
|
1546
1612
|
dataSource && renderPagination && renderPagination({
|
|
@@ -1548,7 +1614,7 @@ function LookupSelect(props) {
|
|
|
1548
1614
|
totalPages: Math.ceil(totalCount / optimizedPageSize),
|
|
1549
1615
|
onPageChange: handlePageChange,
|
|
1550
1616
|
pageSize: optimizedPageSize,
|
|
1551
|
-
onPageSizeChange: (
|
|
1617
|
+
onPageSizeChange: (_newSize) => {
|
|
1552
1618
|
},
|
|
1553
1619
|
totalCount,
|
|
1554
1620
|
loading
|