react-lookup-select 1.0.4 → 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 CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Onur Altuntaş
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Onur Altuntaş
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs CHANGED
@@ -210,13 +210,18 @@ function useLookupSelectState(props) {
210
210
  },
211
211
  [open, onOpenChange]
212
212
  );
213
- const selectionManager = (0, import_react.useMemo)(() => {
214
- return new SelectionManager(mode, mapper);
215
- }, [mode, mapper]);
216
- const queryManager = (0, import_react.useMemo)(() => {
217
- return new QueryManager({ pageSize });
218
- }, [pageSize]);
213
+ const selectionManagerRef = (0, import_react.useRef)(null);
214
+ if (!selectionManagerRef.current) {
215
+ selectionManagerRef.current = new SelectionManager(mode, mapper);
216
+ }
217
+ const selectionManager = selectionManagerRef.current;
218
+ const queryManagerRef = (0, import_react.useRef)(null);
219
+ if (!queryManagerRef.current) {
220
+ queryManagerRef.current = new QueryManager({ pageSize });
221
+ }
222
+ const queryManager = queryManagerRef.current;
219
223
  const [currentSelections, setCurrentSelections] = (0, import_react.useState)([]);
224
+ const [backupSelections, setBackupSelections] = (0, import_react.useState)([]);
220
225
  const resolveValueToRows = (0, import_react.useCallback)(
221
226
  (valueToResolve) => {
222
227
  if (!valueToResolve || !data) return [];
@@ -232,6 +237,10 @@ function useLookupSelectState(props) {
232
237
  );
233
238
  if (matchingRow) {
234
239
  resolvedRows.push(matchingRow);
240
+ } else if (typeof console !== "undefined") {
241
+ console.warn(
242
+ `[react-lookup-select] Could not resolve value with id "${searchId}" from data. Ensure the value matches an item in the data array.`
243
+ );
235
244
  }
236
245
  }
237
246
  }
@@ -253,18 +262,22 @@ function useLookupSelectState(props) {
253
262
  }, [value, defaultValue, data, resolveValueToRows, selectionManager]);
254
263
  const toggleRowSelection = (0, import_react.useCallback)(
255
264
  (row) => {
256
- const newState = selectionManager.toggleRow(row);
265
+ selectionManager.toggleRow(row);
257
266
  const selectedRows = selectionManager.getSelectedRows();
258
267
  setCurrentSelections(selectedRows);
259
- onSelectionChange?.(selectedRows);
268
+ if (!modalOpen) {
269
+ onSelectionChange?.(selectedRows);
270
+ }
260
271
  },
261
- [selectionManager, onSelectionChange]
272
+ [selectionManager, onSelectionChange, modalOpen]
262
273
  );
263
274
  const clearSelections = (0, import_react.useCallback)(() => {
264
275
  selectionManager.clearSelection();
265
276
  setCurrentSelections([]);
266
- onSelectionChange?.([]);
267
- }, [selectionManager, onSelectionChange]);
277
+ if (!modalOpen) {
278
+ onSelectionChange?.([]);
279
+ }
280
+ }, [selectionManager, onSelectionChange, modalOpen]);
268
281
  const isRowSelected = (0, import_react.useCallback)(
269
282
  (row) => {
270
283
  return selectionManager.isRowSelected(row);
@@ -273,8 +286,6 @@ function useLookupSelectState(props) {
273
286
  );
274
287
  const updateQuery = (0, import_react.useCallback)(
275
288
  (updates) => {
276
- const currentState = queryManager.getState();
277
- const newState = { ...currentState, ...updates };
278
289
  if (updates.search !== void 0) {
279
290
  queryManager.updateSearch(updates.search);
280
291
  }
@@ -314,17 +325,24 @@ function useLookupSelectState(props) {
314
325
  ]);
315
326
  const cancelSelection = (0, import_react.useCallback)(() => {
316
327
  selectionManager.clearSelection();
317
- setCurrentSelections([]);
328
+ for (const row of backupSelections) {
329
+ selectionManager.toggleRow(row);
330
+ }
331
+ setCurrentSelections([...backupSelections]);
318
332
  onCancel?.();
319
333
  handleModalOpenChange(false);
320
- }, [selectionManager, onCancel, handleModalOpenChange]);
334
+ }, [selectionManager, backupSelections, onCancel, handleModalOpenChange]);
321
335
  const getCurrentQuery = (0, import_react.useCallback)(() => {
322
336
  return queryManager.getState();
323
337
  }, [queryManager]);
338
+ const openModal = (0, import_react.useCallback)(() => {
339
+ setBackupSelections([...currentSelections]);
340
+ handleModalOpenChange(true);
341
+ }, [currentSelections, handleModalOpenChange]);
324
342
  return {
325
343
  // Modal state
326
344
  modalOpen,
327
- openModal: () => handleModalOpenChange(true),
345
+ openModal,
328
346
  closeModal: () => handleModalOpenChange(false),
329
347
  // Selection state
330
348
  currentSelections,
@@ -344,21 +362,12 @@ function useLookupSelectState(props) {
344
362
  var import_react2 = require("react");
345
363
  function useKeyboardNavigation({
346
364
  isModalOpen,
347
- onClose,
348
- onConfirm,
349
- onRowSelect,
350
- currentData,
351
- selectedRows,
352
- mode
365
+ onConfirm
353
366
  }) {
354
367
  const handleKeyDown = (0, import_react2.useCallback)(
355
368
  (event) => {
356
369
  if (!isModalOpen) return;
357
370
  switch (event.key) {
358
- case "Escape":
359
- event.preventDefault();
360
- onClose();
361
- break;
362
371
  case "Enter":
363
372
  if (event.ctrlKey || event.metaKey) {
364
373
  event.preventDefault();
@@ -366,13 +375,62 @@ function useKeyboardNavigation({
366
375
  }
367
376
  break;
368
377
  case "ArrowDown":
369
- case "ArrowUp":
378
+ case "ArrowUp": {
379
+ const grid = document.querySelector(
380
+ ".lookup-select__grid tbody, .lookup-select__virtual-grid-body"
381
+ );
382
+ if (!grid) break;
383
+ const rows = grid.querySelectorAll(
384
+ 'tr[tabindex="0"], tr[role="row"]'
385
+ );
386
+ if (rows.length === 0) break;
387
+ const currentIndex = Array.from(rows).findIndex(
388
+ (row) => row === document.activeElement
389
+ );
390
+ let nextIndex;
391
+ if (event.key === "ArrowDown") {
392
+ nextIndex = currentIndex < 0 ? 0 : Math.min(currentIndex + 1, rows.length - 1);
393
+ } else {
394
+ nextIndex = currentIndex < 0 ? rows.length - 1 : Math.max(currentIndex - 1, 0);
395
+ }
396
+ event.preventDefault();
397
+ rows[nextIndex]?.focus();
398
+ break;
399
+ }
400
+ case "Home": {
401
+ const gridHome = document.querySelector(
402
+ ".lookup-select__grid tbody, .lookup-select__virtual-grid-body"
403
+ );
404
+ if (!gridHome) break;
405
+ const firstRow = gridHome.querySelector(
406
+ 'tr[tabindex="0"], tr[role="row"]'
407
+ );
408
+ if (firstRow) {
409
+ event.preventDefault();
410
+ firstRow.focus();
411
+ }
412
+ break;
413
+ }
414
+ case "End": {
415
+ const gridEnd = document.querySelector(
416
+ ".lookup-select__grid tbody, .lookup-select__virtual-grid-body"
417
+ );
418
+ if (!gridEnd) break;
419
+ const allRows = gridEnd.querySelectorAll(
420
+ 'tr[tabindex="0"], tr[role="row"]'
421
+ );
422
+ const lastRow = allRows[allRows.length - 1];
423
+ if (lastRow) {
424
+ event.preventDefault();
425
+ lastRow.focus();
426
+ }
370
427
  break;
428
+ }
371
429
  default:
372
430
  break;
373
431
  }
374
432
  },
375
- [isModalOpen, onClose, onConfirm]
433
+ [isModalOpen, onConfirm]
376
434
  );
377
435
  (0, import_react2.useEffect)(() => {
378
436
  if (isModalOpen) {
@@ -386,36 +444,7 @@ function useKeyboardNavigation({
386
444
  handleKeyDown
387
445
  };
388
446
  }
389
- function useFocusManagement(isOpen) {
390
- (0, import_react2.useEffect)(() => {
391
- if (!isOpen) return;
392
- const modal = document.querySelector('[role="dialog"]');
393
- if (!modal) return;
394
- const focusableElements = modal.querySelectorAll(
395
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
396
- );
397
- const firstFocusable = focusableElements[0];
398
- const lastFocusable = focusableElements[focusableElements.length - 1];
399
- firstFocusable?.focus();
400
- const handleTabKey = (e) => {
401
- if (e.key !== "Tab") return;
402
- if (e.shiftKey) {
403
- if (document.activeElement === firstFocusable) {
404
- e.preventDefault();
405
- lastFocusable?.focus();
406
- }
407
- } else {
408
- if (document.activeElement === lastFocusable) {
409
- e.preventDefault();
410
- firstFocusable?.focus();
411
- }
412
- }
413
- };
414
- document.addEventListener("keydown", handleTabKey);
415
- return () => {
416
- document.removeEventListener("keydown", handleTabKey);
417
- };
418
- }, [isOpen]);
447
+ function useFocusManagement(_isOpen) {
419
448
  }
420
449
  function useScreenReaderAnnouncements() {
421
450
  const announce = (0, import_react2.useCallback)(
@@ -574,11 +603,18 @@ function Modal({
574
603
  (0, import_react3.useEffect)(() => {
575
604
  if (!isOpen) return;
576
605
  previousFocusRef.current = document.activeElement;
577
- const focusableElements = modalRef.current?.querySelectorAll(
578
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
606
+ const autoFocusElement = modalRef.current?.querySelector(
607
+ "[data-autofocus]"
579
608
  );
580
- if (focusableElements && focusableElements.length > 0) {
581
- focusableElements[0].focus();
609
+ if (autoFocusElement) {
610
+ autoFocusElement.focus();
611
+ } else {
612
+ const focusableElements = modalRef.current?.querySelectorAll(
613
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
614
+ );
615
+ if (focusableElements && focusableElements.length > 0) {
616
+ focusableElements[0].focus();
617
+ }
582
618
  }
583
619
  const handleEscape = (e) => {
584
620
  if (e.key === "Escape") {
@@ -587,12 +623,12 @@ function Modal({
587
623
  };
588
624
  const handleTab = (e) => {
589
625
  if (e.key !== "Tab") return;
590
- const focusableElements2 = modalRef.current?.querySelectorAll(
626
+ const focusableElements = modalRef.current?.querySelectorAll(
591
627
  'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
592
628
  );
593
- if (!focusableElements2 || focusableElements2.length === 0) return;
594
- const firstElement = focusableElements2[0];
595
- const lastElement = focusableElements2[focusableElements2.length - 1];
629
+ if (!focusableElements || focusableElements.length === 0) return;
630
+ const firstElement = focusableElements[0];
631
+ const lastElement = focusableElements[focusableElements.length - 1];
596
632
  if (e.shiftKey) {
597
633
  if (document.activeElement === firstElement) {
598
634
  lastElement.focus();
@@ -683,23 +719,17 @@ function SearchInput({
683
719
  placeholder = "Search...",
684
720
  className
685
721
  }) {
686
- const inputRef = (0, import_react3.useRef)(null);
687
- (0, import_react3.useEffect)(() => {
688
- if (inputRef.current) {
689
- inputRef.current.focus();
690
- }
691
- }, []);
692
722
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `lookup-select__search ${className || ""}`, children: [
693
723
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
694
724
  "input",
695
725
  {
696
- ref: inputRef,
697
726
  type: "text",
698
727
  value,
699
728
  onChange: (e) => onChange(e.target.value),
700
729
  placeholder,
701
730
  className: "lookup-select__search-input",
702
- "aria-label": "Search records"
731
+ "aria-label": "Search records",
732
+ "data-autofocus": true
703
733
  }
704
734
  ),
705
735
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "lookup-select__search-icon", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }) }) })
@@ -756,6 +786,7 @@ function Grid({
756
786
  loading = false,
757
787
  error,
758
788
  emptyText = "No records found",
789
+ onRetry,
759
790
  className,
760
791
  style
761
792
  }) {
@@ -776,13 +807,33 @@ function Grid({
776
807
  return currentSort.sortDir === "asc" ? "\u2191" : "\u2193";
777
808
  };
778
809
  if (loading) {
779
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__loading", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "Loading..." }) }) });
810
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `lookup-select__grid ${className || ""}`, style, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { className: "lookup-select__table", children: [
811
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { children: [
812
+ mode === "multiple" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "lookup-select__header-cell lookup-select__header-cell--checkbox" }),
813
+ columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "lookup-select__header-cell", children: column.title }, String(column.key)))
814
+ ] }) }),
815
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("tbody", { children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { className: "lookup-select__grid-row lookup-select__grid-row--skeleton", children: [
816
+ mode === "multiple" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "lookup-select__cell" }),
817
+ columns.map((col, j) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "lookup-select__cell", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__skeleton-line" }) }, j))
818
+ ] }, i)) })
819
+ ] }) });
780
820
  }
781
821
  if (error) {
782
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__error", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
783
- "Error: ",
784
- error
785
- ] }) }) });
822
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "lookup-select__error", children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
824
+ "Error: ",
825
+ error
826
+ ] }),
827
+ onRetry && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
828
+ "button",
829
+ {
830
+ type: "button",
831
+ className: "lookup-select__button lookup-select__button--secondary",
832
+ onClick: onRetry,
833
+ children: "Retry"
834
+ }
835
+ )
836
+ ] }) });
786
837
  }
787
838
  if (data.length === 0) {
788
839
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__grid-state", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "lookup-select__empty", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: emptyText }) }) });
@@ -854,7 +905,7 @@ function Grid({
854
905
  "aria-label": "Select all"
855
906
  }
856
907
  ) }) }),
857
- columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
908
+ columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
858
909
  "th",
859
910
  {
860
911
  className: "lookup-select__table-header",
@@ -910,7 +961,7 @@ function Grid({
910
961
  "aria-label": `Select ${mapper.getText(row)}`
911
962
  }
912
963
  ) }) }),
913
- columns.map((column, columnIndex) => {
964
+ columns.map((column) => {
914
965
  const cellKey = `${rowId}-${typeof column.key === "string" ? column.key : String(column.key)}`;
915
966
  let cellContent;
916
967
  if (column.render) {
@@ -972,13 +1023,16 @@ function VirtualGrid(props) {
972
1023
  return () => resizeObserver.disconnect();
973
1024
  }
974
1025
  }, []);
1026
+ const selectableCount = import_react4.default.useMemo(() => {
1027
+ return selectableRow ? data.filter(selectableRow).length : data.length;
1028
+ }, [data, selectableRow]);
975
1029
  import_react4.default.useEffect(() => {
976
1030
  if (headerCheckboxRef.current) {
977
1031
  const hasSelected = selectedRows.length > 0;
978
- const hasUnselected = selectedRows.length < data.length;
1032
+ const hasUnselected = selectedRows.length < selectableCount;
979
1033
  headerCheckboxRef.current.indeterminate = hasSelected && hasUnselected;
980
1034
  }
981
- }, [selectedRows.length, data.length]);
1035
+ }, [selectedRows.length, selectableCount]);
982
1036
  const itemCount = data.length;
983
1037
  const { rowHeight, overscan } = virtualization;
984
1038
  const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
@@ -1053,7 +1107,7 @@ function VirtualGrid(props) {
1053
1107
  ref: headerCheckboxRef,
1054
1108
  type: "checkbox",
1055
1109
  className: "lookup-select__checkbox",
1056
- checked: selectedRows.length === data.length && data.length > 0,
1110
+ checked: selectedRows.length === selectableCount && selectableCount > 0,
1057
1111
  onChange: (e) => {
1058
1112
  if (e.target.checked) {
1059
1113
  data.forEach((row) => {
@@ -1136,9 +1190,11 @@ function VirtualRowComponent({
1136
1190
  item,
1137
1191
  columns,
1138
1192
  mode,
1193
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1139
1194
  mapper,
1140
1195
  isSelected,
1141
1196
  isSelectable,
1197
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1142
1198
  onToggle,
1143
1199
  onCheckboxChange,
1144
1200
  onClick
@@ -1186,7 +1242,8 @@ function Pagination({
1186
1242
  totalCount,
1187
1243
  pageSize,
1188
1244
  onPageChange,
1189
- className
1245
+ className,
1246
+ i18n
1190
1247
  }) {
1191
1248
  const totalPages = Math.ceil(totalCount / pageSize);
1192
1249
  if (totalPages <= 1) {
@@ -1216,14 +1273,7 @@ function Pagination({
1216
1273
  const startRecord = (currentPage - 1) * pageSize + 1;
1217
1274
  const endRecord = Math.min(currentPage * pageSize, totalCount);
1218
1275
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `lookup-select__pagination ${className || ""}`, children: [
1219
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lookup-select__pagination-info", children: totalCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1220
- startRecord,
1221
- "-",
1222
- endRecord,
1223
- " / ",
1224
- totalCount,
1225
- " records"
1226
- ] }) : "0 records" }),
1276
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "lookup-select__pagination-info", children: totalCount > 0 ? i18n?.recordsInfo ? i18n.recordsInfo(startRecord, endRecord, totalCount) : `${startRecord}-${endRecord} / ${totalCount} records` : "0 records" }),
1227
1277
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "lookup-select__pagination-controls", children: [
1228
1278
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1229
1279
  "button",
@@ -1232,7 +1282,7 @@ function Pagination({
1232
1282
  className: "lookup-select__pagination-button",
1233
1283
  disabled: currentPage === 1,
1234
1284
  onClick: () => onPageChange(currentPage - 1),
1235
- "aria-label": "Previous page",
1285
+ "aria-label": i18n?.previousPage || "Previous page",
1236
1286
  children: "\u2039"
1237
1287
  }
1238
1288
  ),
@@ -1257,7 +1307,7 @@ function Pagination({
1257
1307
  ${currentPage === pageNum ? "lookup-select__pagination-button--active" : ""}
1258
1308
  `,
1259
1309
  onClick: () => onPageChange(pageNum),
1260
- "aria-label": `Sayfa ${pageNum}`,
1310
+ "aria-label": i18n?.pageLabel ? i18n.pageLabel(pageNum) : `Page ${pageNum}`,
1261
1311
  "aria-current": currentPage === pageNum ? "page" : void 0,
1262
1312
  children: pageNum
1263
1313
  },
@@ -1271,7 +1321,7 @@ function Pagination({
1271
1321
  className: "lookup-select__pagination-button",
1272
1322
  disabled: currentPage === totalPages,
1273
1323
  onClick: () => onPageChange(currentPage + 1),
1274
- "aria-label": "Next page",
1324
+ "aria-label": i18n?.nextPage || "Next page",
1275
1325
  children: "\u203A"
1276
1326
  }
1277
1327
  )
@@ -1294,7 +1344,6 @@ function LookupSelect(props) {
1294
1344
  renderTrigger,
1295
1345
  renderModal,
1296
1346
  renderGrid,
1297
- renderHeader,
1298
1347
  renderFooter,
1299
1348
  renderSearch,
1300
1349
  renderPagination,
@@ -1314,7 +1363,6 @@ function LookupSelect(props) {
1314
1363
  const {
1315
1364
  modalOpen,
1316
1365
  openModal,
1317
- closeModal,
1318
1366
  currentSelections,
1319
1367
  toggleRowSelection,
1320
1368
  clearSelections,
@@ -1359,11 +1407,10 @@ function LookupSelect(props) {
1359
1407
  virtualRowHeight,
1360
1408
  pageSize
1361
1409
  ]);
1362
- const { announce } = useScreenReaderAnnouncements();
1410
+ useScreenReaderAnnouncements();
1363
1411
  useFocusManagement(modalOpen);
1364
1412
  useKeyboardNavigation({
1365
1413
  isModalOpen: modalOpen,
1366
- onClose: closeModal,
1367
1414
  onConfirm: confirmSelection,
1368
1415
  currentData: [],
1369
1416
  selectedRows: currentSelections,
@@ -1375,13 +1422,34 @@ function LookupSelect(props) {
1375
1422
  const [serverData, setServerData] = import_react5.default.useState([]);
1376
1423
  const [totalCount, setTotalCount] = import_react5.default.useState(0);
1377
1424
  const [currentPage, setCurrentPage] = import_react5.default.useState(1);
1425
+ const [sortState, setSortState] = import_react5.default.useState({});
1426
+ const [debouncedSearch, setDebouncedSearch] = import_react5.default.useState("");
1427
+ const debounceTimerRef = import_react5.default.useRef(null);
1378
1428
  const handleSearchChange = import_react5.default.useCallback(
1379
1429
  (value) => {
1380
1430
  setSearchValue(value);
1381
- updateQuery({ search: value, page: 1 });
1431
+ if (dataSource) {
1432
+ if (debounceTimerRef.current) {
1433
+ clearTimeout(debounceTimerRef.current);
1434
+ }
1435
+ debounceTimerRef.current = setTimeout(() => {
1436
+ setDebouncedSearch(value);
1437
+ setCurrentPage(1);
1438
+ updateQuery({ search: value, page: 1 });
1439
+ }, 300);
1440
+ } else {
1441
+ updateQuery({ search: value, page: 1 });
1442
+ }
1382
1443
  },
1383
- [updateQuery]
1444
+ [updateQuery, dataSource]
1384
1445
  );
1446
+ import_react5.default.useEffect(() => {
1447
+ return () => {
1448
+ if (debounceTimerRef.current) {
1449
+ clearTimeout(debounceTimerRef.current);
1450
+ }
1451
+ };
1452
+ }, []);
1385
1453
  const filteredData = import_react5.default.useMemo(() => {
1386
1454
  if (!searchValue || dataSource) {
1387
1455
  return data;
@@ -1399,13 +1467,14 @@ function LookupSelect(props) {
1399
1467
  setLoading(true);
1400
1468
  setError(void 0);
1401
1469
  try {
1402
- const query = getCurrentQuery();
1403
- const result = await dataSource({
1404
- ...query,
1405
- search: searchValue,
1470
+ const query = {
1471
+ search: debouncedSearch,
1406
1472
  page: currentPage,
1407
- pageSize: optimizedPageSize
1408
- });
1473
+ pageSize: optimizedPageSize,
1474
+ sortBy: sortState.sortBy,
1475
+ sortDir: sortState.sortDir
1476
+ };
1477
+ const result = await dataSource(query);
1409
1478
  setServerData(result.rows);
1410
1479
  setTotalCount(result.total);
1411
1480
  setLoading(false);
@@ -1417,10 +1486,10 @@ function LookupSelect(props) {
1417
1486
  }
1418
1487
  }, [
1419
1488
  dataSource,
1420
- getCurrentQuery,
1421
- searchValue,
1489
+ debouncedSearch,
1422
1490
  currentPage,
1423
- optimizedPageSize
1491
+ optimizedPageSize,
1492
+ sortState
1424
1493
  ]);
1425
1494
  import_react5.default.useEffect(() => {
1426
1495
  if (dataSource && modalOpen) {
@@ -1436,8 +1505,9 @@ function LookupSelect(props) {
1436
1505
  );
1437
1506
  const handleSortChange = import_react5.default.useCallback(
1438
1507
  (sortBy, sortDir) => {
1439
- updateQuery({ sortBy, sortDir, page: 1 });
1508
+ setSortState({ sortBy, sortDir });
1440
1509
  setCurrentPage(1);
1510
+ updateQuery({ sortBy, sortDir, page: 1 });
1441
1511
  },
1442
1512
  [updateQuery]
1443
1513
  );
@@ -1474,11 +1544,12 @@ function LookupSelect(props) {
1474
1544
  loading,
1475
1545
  error,
1476
1546
  emptyText: texts.emptyText,
1547
+ onRetry: dataSource ? loadServerData : void 0,
1477
1548
  className: classNames?.grid,
1478
1549
  style: styles?.grid,
1479
1550
  currentSort: dataSource ? {
1480
- sortBy: getCurrentQuery().sortBy || "",
1481
- sortDir: getCurrentQuery().sortDir || "asc"
1551
+ sortBy: sortState.sortBy || "",
1552
+ sortDir: sortState.sortDir || "asc"
1482
1553
  } : void 0,
1483
1554
  onSort: dataSource ? handleSortChange : void 0
1484
1555
  };
@@ -1535,12 +1606,14 @@ function LookupSelect(props) {
1535
1606
  selectedIds: currentSelections.map(mapper.getId),
1536
1607
  onRowSelect: toggleRowSelection,
1537
1608
  onSelectAll: mode === "multiple" ? () => {
1538
- const allIds = currentData.map(mapper.getId);
1539
- const selectedIds = currentSelections.map(mapper.getId);
1540
- if (allIds.length === selectedIds.length) {
1609
+ const selectableData = selectableRow ? currentData.filter(selectableRow) : currentData;
1610
+ const allSelected = selectableData.every(
1611
+ (row) => isRowSelected(row)
1612
+ );
1613
+ if (allSelected) {
1541
1614
  clearSelections();
1542
1615
  } else {
1543
- currentData.forEach((row) => {
1616
+ selectableData.forEach((row) => {
1544
1617
  if (!isRowSelected(row)) {
1545
1618
  toggleRowSelection(row);
1546
1619
  }
@@ -1555,8 +1628,8 @@ function LookupSelect(props) {
1555
1628
  virtualization: shouldUseVirtualization ? virtualizationConfig : void 0,
1556
1629
  selectableRow,
1557
1630
  onSortChange: handleSortChange,
1558
- sortBy: getCurrentQuery().sortBy,
1559
- sortDir: getCurrentQuery().sortDir
1631
+ sortBy: sortState.sortBy,
1632
+ sortDir: sortState.sortDir
1560
1633
  }) : renderGridComponent(),
1561
1634
  dataSource && !renderPagination && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1562
1635
  Pagination,
@@ -1564,7 +1637,12 @@ function LookupSelect(props) {
1564
1637
  currentPage,
1565
1638
  totalCount,
1566
1639
  pageSize: optimizedPageSize,
1567
- onPageChange: handlePageChange
1640
+ onPageChange: handlePageChange,
1641
+ i18n: {
1642
+ previousPage: i18n?.previousPage,
1643
+ nextPage: i18n?.nextPage,
1644
+ pageLabel: i18n?.paginationInfo ? (pageNum) => i18n.paginationInfo(pageNum, Math.ceil(totalCount / optimizedPageSize)) : void 0
1645
+ }
1568
1646
  }
1569
1647
  ),
1570
1648
  dataSource && renderPagination && renderPagination({
@@ -1572,7 +1650,7 @@ function LookupSelect(props) {
1572
1650
  totalPages: Math.ceil(totalCount / optimizedPageSize),
1573
1651
  onPageChange: handlePageChange,
1574
1652
  pageSize: optimizedPageSize,
1575
- onPageSizeChange: (newSize) => {
1653
+ onPageSizeChange: (_newSize) => {
1576
1654
  },
1577
1655
  totalCount,
1578
1656
  loading