kelt-ui-kit-react 2.1.2 → 2.1.3
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 +1991 -1970
- package/package.json +1 -1
- package/src/select/Select.tsx +40 -4
package/package.json
CHANGED
package/src/select/Select.tsx
CHANGED
|
@@ -5,6 +5,9 @@ import { OverlayPanel, PositionOverlay } from "../overlayPanel/OverlayPanel";
|
|
|
5
5
|
import "./select.css";
|
|
6
6
|
import { SelectOptionInterface } from "./selectOption.interface";
|
|
7
7
|
|
|
8
|
+
// Nombre d'options rendues à l'ouverture puis à chaque fin de scroll
|
|
9
|
+
const OPTIONS_PAGE_SIZE = 50;
|
|
10
|
+
|
|
8
11
|
export interface SelectProps {
|
|
9
12
|
id?: string;
|
|
10
13
|
label?: string;
|
|
@@ -55,6 +58,7 @@ export const Select = ({
|
|
|
55
58
|
const hasAutoOpened = useRef(false);
|
|
56
59
|
const optionsListRef = useRef<HTMLDivElement | null>(null);
|
|
57
60
|
const [search, setSearch] = useState("");
|
|
61
|
+
const [visibleCount, setVisibleCount] = useState(OPTIONS_PAGE_SIZE);
|
|
58
62
|
|
|
59
63
|
useEffect(() => {
|
|
60
64
|
if (!showOverlay) setSearch("");
|
|
@@ -68,6 +72,11 @@ export const Select = ({
|
|
|
68
72
|
return options.filter((option) => normalize(option.label).includes(term));
|
|
69
73
|
}, [options, search, searchable]);
|
|
70
74
|
|
|
75
|
+
const optionsByValue = useMemo(
|
|
76
|
+
() => new Map(options.map((option) => [option.value, option])),
|
|
77
|
+
[options],
|
|
78
|
+
);
|
|
79
|
+
|
|
71
80
|
useEffect(() => {
|
|
72
81
|
if (!showOverlay) return;
|
|
73
82
|
const timer = setTimeout(() => {
|
|
@@ -95,15 +104,38 @@ export const Select = ({
|
|
|
95
104
|
: [];
|
|
96
105
|
const hasSelection = selectedValues.some((v) => v !== "");
|
|
97
106
|
|
|
107
|
+
// Rendu progressif : on repart d'une page à chaque ouverture ou recherche,
|
|
108
|
+
// en allant au moins jusqu'à l'option sélectionnée en sélection simple
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
if (!showOverlay) return;
|
|
111
|
+
const selectedIndex = multiple
|
|
112
|
+
? -1
|
|
113
|
+
: filteredOptions.findIndex((option) => option.value === selectedValues[0]);
|
|
114
|
+
setVisibleCount(Math.max(OPTIONS_PAGE_SIZE, selectedIndex + 1));
|
|
115
|
+
optionsListRef.current?.scrollTo({ top: 0 });
|
|
116
|
+
}, [showOverlay, search]);
|
|
117
|
+
|
|
118
|
+
const visibleOptions = filteredOptions.slice(0, visibleCount);
|
|
119
|
+
|
|
120
|
+
const handleOptionsScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
|
121
|
+
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
|
122
|
+
if (
|
|
123
|
+
visibleCount < filteredOptions.length &&
|
|
124
|
+
scrollHeight - scrollTop - clientHeight < 100
|
|
125
|
+
) {
|
|
126
|
+
setVisibleCount((count) => count + OPTIONS_PAGE_SIZE);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
98
130
|
const getDisplayValue = () => {
|
|
99
131
|
if (selectedValues.length === 0) return placeholder || "";
|
|
100
132
|
if (multiple) {
|
|
101
133
|
const labels = selectedValues
|
|
102
|
-
.map((v) =>
|
|
134
|
+
.map((v) => optionsByValue.get(v)?.label)
|
|
103
135
|
.filter((l): l is string => !!l);
|
|
104
136
|
return labels.join(", ");
|
|
105
137
|
}
|
|
106
|
-
const selected =
|
|
138
|
+
const selected = optionsByValue.get(selectedValues[0]);
|
|
107
139
|
return selected?.label || "";
|
|
108
140
|
};
|
|
109
141
|
|
|
@@ -200,11 +232,15 @@ export const Select = ({
|
|
|
200
232
|
/>
|
|
201
233
|
</div>
|
|
202
234
|
)}
|
|
203
|
-
<div
|
|
235
|
+
<div
|
|
236
|
+
className="select-overlay-options"
|
|
237
|
+
ref={optionsListRef}
|
|
238
|
+
onScroll={handleOptionsScroll}
|
|
239
|
+
>
|
|
204
240
|
{searchable && filteredOptions.length === 0 && (
|
|
205
241
|
<div className="select-overlay-empty">Aucun résultat</div>
|
|
206
242
|
)}
|
|
207
|
-
{
|
|
243
|
+
{visibleOptions.map((option) => (
|
|
208
244
|
<div
|
|
209
245
|
key={option.value}
|
|
210
246
|
aria-valuetext={option.label}
|