@strapi/ui-primitives 2.0.0-rc.9 → 2.0.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.
|
@@ -35,6 +35,25 @@ interface RootProps {
|
|
|
35
35
|
filterValue?: string;
|
|
36
36
|
onFilterValueChange?(value: string): void;
|
|
37
37
|
isPrintableCharacter?: (str: string) => boolean;
|
|
38
|
+
visible?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Enable virtualization for large lists
|
|
41
|
+
* - true: always virtualize
|
|
42
|
+
* - false: never virtualize
|
|
43
|
+
* - 'auto': virtualize when item count > 100 (default)
|
|
44
|
+
* @default 'auto'
|
|
45
|
+
*/
|
|
46
|
+
virtualized?: boolean | 'auto';
|
|
47
|
+
/**
|
|
48
|
+
* Estimated size of each virtualized item in pixels
|
|
49
|
+
* @default 40
|
|
50
|
+
*/
|
|
51
|
+
estimatedItemSize?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Number of items to render outside visible area for smooth scrolling
|
|
54
|
+
* @default 5
|
|
55
|
+
*/
|
|
56
|
+
overscan?: number;
|
|
38
57
|
}
|
|
39
58
|
type TriggerProps = PrimitiveDivProps;
|
|
40
59
|
type TextInputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Primitive } from '@radix-ui/react-primitive';
|
|
3
|
+
import type { ComponentPropsWithoutRef } from '@radix-ui/react-primitive';
|
|
4
|
+
/**
|
|
5
|
+
* VirtualizedViewport - Renders only visible items for performance optimization
|
|
6
|
+
* Used when Combobox/Select has many items (>100)
|
|
7
|
+
*/
|
|
8
|
+
type VirtualizedViewportElement = React.ElementRef<typeof Primitive.div>;
|
|
9
|
+
type PrimitiveDivProps = ComponentPropsWithoutRef<typeof Primitive.div>;
|
|
10
|
+
export interface VirtualizedViewportProps extends PrimitiveDivProps {
|
|
11
|
+
/**
|
|
12
|
+
* Estimated size of each item in pixels
|
|
13
|
+
* @default 40
|
|
14
|
+
*/
|
|
15
|
+
estimatedItemSize?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Number of items to render outside the visible area
|
|
18
|
+
* @default 5
|
|
19
|
+
*/
|
|
20
|
+
overscan?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Callback to get the count of total items
|
|
23
|
+
*/
|
|
24
|
+
getItemCount: () => number;
|
|
25
|
+
/**
|
|
26
|
+
* Callback when viewport ref changes
|
|
27
|
+
*/
|
|
28
|
+
onViewportChange?: (node: VirtualizedViewportElement | null) => void;
|
|
29
|
+
}
|
|
30
|
+
export declare const VirtualizedViewport: React.ForwardRefExoticComponent<VirtualizedViewportProps & React.RefAttributes<HTMLDivElement>>;
|
|
31
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ const reactUseLayoutEffect = require("@radix-ui/react-use-layout-effect");
|
|
|
18
18
|
const ariaHidden = require("aria-hidden");
|
|
19
19
|
const ReactDOM = require("react-dom");
|
|
20
20
|
const reactRemoveScroll = require("react-remove-scroll");
|
|
21
|
+
const reactVirtual = require("@tanstack/react-virtual");
|
|
21
22
|
const number = require("@radix-ui/number");
|
|
22
23
|
const reactCollection = require("@radix-ui/react-collection");
|
|
23
24
|
const reactDirection = require("@radix-ui/react-direction");
|
|
@@ -173,6 +174,75 @@ const usePrev = (value) => {
|
|
|
173
174
|
});
|
|
174
175
|
return ref.current;
|
|
175
176
|
};
|
|
177
|
+
const VirtualizedViewport = React__namespace.forwardRef(
|
|
178
|
+
({ children, estimatedItemSize = 40, overscan = 5, getItemCount, onViewportChange, ...props }, forwardedRef) => {
|
|
179
|
+
const parentRef = React__namespace.useRef(null);
|
|
180
|
+
const composedRefs = reactComposeRefs.useComposedRefs(forwardedRef, parentRef, onViewportChange);
|
|
181
|
+
const childArray = React__namespace.useMemo(() => React__namespace.Children.toArray(children), [children]);
|
|
182
|
+
const virtualizer = reactVirtual.useVirtualizer({
|
|
183
|
+
count: getItemCount(),
|
|
184
|
+
getScrollElement: () => parentRef.current,
|
|
185
|
+
estimateSize: () => estimatedItemSize,
|
|
186
|
+
overscan
|
|
187
|
+
});
|
|
188
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
189
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
190
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
191
|
+
"style",
|
|
192
|
+
{
|
|
193
|
+
dangerouslySetInnerHTML: {
|
|
194
|
+
__html: `[data-radix-combobox-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-combobox-viewport]::-webkit-scrollbar{display:none}`
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
),
|
|
198
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
199
|
+
reactPrimitive.Primitive.div,
|
|
200
|
+
{
|
|
201
|
+
"data-radix-combobox-viewport": "",
|
|
202
|
+
role: "presentation",
|
|
203
|
+
...props,
|
|
204
|
+
ref: composedRefs,
|
|
205
|
+
style: {
|
|
206
|
+
position: "relative",
|
|
207
|
+
flex: 1,
|
|
208
|
+
overflow: "auto",
|
|
209
|
+
...props.style
|
|
210
|
+
},
|
|
211
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
212
|
+
"div",
|
|
213
|
+
{
|
|
214
|
+
style: {
|
|
215
|
+
height: `${virtualizer.getTotalSize()}px`,
|
|
216
|
+
width: "100%",
|
|
217
|
+
position: "relative"
|
|
218
|
+
},
|
|
219
|
+
children: virtualItems.map((virtualItem) => {
|
|
220
|
+
const child = childArray[virtualItem.index];
|
|
221
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
222
|
+
"div",
|
|
223
|
+
{
|
|
224
|
+
"data-index": virtualItem.index,
|
|
225
|
+
ref: virtualizer.measureElement,
|
|
226
|
+
style: {
|
|
227
|
+
position: "absolute",
|
|
228
|
+
top: 0,
|
|
229
|
+
left: 0,
|
|
230
|
+
width: "100%",
|
|
231
|
+
transform: `translateY(${virtualItem.start}px)`
|
|
232
|
+
},
|
|
233
|
+
children: child
|
|
234
|
+
},
|
|
235
|
+
virtualItem.key
|
|
236
|
+
);
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
] });
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
VirtualizedViewport.displayName = "VirtualizedViewport";
|
|
176
246
|
const OPEN_KEYS$1 = [" ", "Enter", "ArrowUp", "ArrowDown"];
|
|
177
247
|
const SELECTION_KEYS$1 = ["Enter"];
|
|
178
248
|
const defaultIsPrintableCharacter = (str) => {
|
|
@@ -217,7 +287,11 @@ const Combobox = (props) => {
|
|
|
217
287
|
filterValue: filterValueProp,
|
|
218
288
|
defaultFilterValue,
|
|
219
289
|
onFilterValueChange,
|
|
220
|
-
isPrintableCharacter = defaultIsPrintableCharacter
|
|
290
|
+
isPrintableCharacter = defaultIsPrintableCharacter,
|
|
291
|
+
visible = false,
|
|
292
|
+
virtualized = "auto",
|
|
293
|
+
estimatedItemSize = 40,
|
|
294
|
+
overscan = 5
|
|
221
295
|
} = props;
|
|
222
296
|
const [trigger, setTrigger] = React__namespace.useState(null);
|
|
223
297
|
const [viewport, setViewport] = React__namespace.useState(null);
|
|
@@ -306,6 +380,10 @@ const Combobox = (props) => {
|
|
|
306
380
|
onFilterValueChange: setFilterValue,
|
|
307
381
|
onVisuallyFocussedItemChange: setVisuallyFocussedItem,
|
|
308
382
|
isPrintableCharacter,
|
|
383
|
+
visible,
|
|
384
|
+
virtualized,
|
|
385
|
+
estimatedItemSize,
|
|
386
|
+
overscan,
|
|
309
387
|
children
|
|
310
388
|
}
|
|
311
389
|
) });
|
|
@@ -713,6 +791,22 @@ const VIEWPORT_NAME$1 = "ComboboxViewport";
|
|
|
713
791
|
const ComboboxViewport = React__namespace.forwardRef((props, forwardedRef) => {
|
|
714
792
|
const comboboxContext = useComboboxContext(VIEWPORT_NAME$1);
|
|
715
793
|
const composedRefs = reactComposeRefs.useComposedRefs(forwardedRef, comboboxContext.onViewportChange);
|
|
794
|
+
const childArray = React__namespace.useMemo(() => React__namespace.Children.toArray(props.children), [props.children]);
|
|
795
|
+
const itemCount = childArray.length;
|
|
796
|
+
const shouldVirtualize = comboboxContext.virtualized === true || comboboxContext.virtualized === "auto" && itemCount > 100;
|
|
797
|
+
if (shouldVirtualize) {
|
|
798
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Collection$1.Slot, { scope: void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
799
|
+
VirtualizedViewport,
|
|
800
|
+
{
|
|
801
|
+
...props,
|
|
802
|
+
ref: composedRefs,
|
|
803
|
+
getItemCount: () => itemCount,
|
|
804
|
+
estimatedItemSize: comboboxContext.estimatedItemSize,
|
|
805
|
+
overscan: comboboxContext.overscan,
|
|
806
|
+
onViewportChange: comboboxContext.onViewportChange
|
|
807
|
+
}
|
|
808
|
+
) });
|
|
809
|
+
}
|
|
716
810
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
717
811
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
718
812
|
"style",
|
|
@@ -873,18 +967,31 @@ const ComboboxItemIndicator = React__namespace.forwardRef((props, forwardedRef)
|
|
|
873
967
|
ComboboxItemIndicator.displayName = ITEM_INDICATOR_NAME$1;
|
|
874
968
|
const NO_VALUE_FOUND_NAME = "ComboboxNoValueFound";
|
|
875
969
|
const ComboboxNoValueFound = React__namespace.forwardRef((props, ref) => {
|
|
876
|
-
const {
|
|
970
|
+
const {
|
|
971
|
+
textValue = "",
|
|
972
|
+
filterValue = "",
|
|
973
|
+
visible = false,
|
|
974
|
+
locale,
|
|
975
|
+
autocomplete
|
|
976
|
+
} = useComboboxContext(NO_VALUE_FOUND_NAME);
|
|
877
977
|
const [items, setItems] = React__namespace.useState([]);
|
|
878
978
|
const { subscribe } = useCollection$1(void 0);
|
|
879
979
|
const { startsWith, contains } = useFilter(locale, { sensitivity: "base" });
|
|
880
980
|
React__namespace.useEffect(() => {
|
|
881
981
|
const unsub = subscribe((state) => {
|
|
882
|
-
|
|
982
|
+
if (visible) {
|
|
983
|
+
const filteredItems = state.filter((item) => item.type !== "create");
|
|
984
|
+
setItems(filteredItems);
|
|
985
|
+
} else {
|
|
986
|
+
setItems(state);
|
|
987
|
+
}
|
|
883
988
|
});
|
|
884
989
|
return () => {
|
|
885
990
|
unsub();
|
|
886
991
|
};
|
|
887
|
-
}, [subscribe]);
|
|
992
|
+
}, [visible, subscribe]);
|
|
993
|
+
if (autocomplete.type === "none" && items.length > 0)
|
|
994
|
+
return null;
|
|
888
995
|
if (autocomplete.type === "list" && autocomplete.filter === "startsWith" && items.some((item) => startsWith(item.textValue, textValue))) {
|
|
889
996
|
return null;
|
|
890
997
|
}
|
|
@@ -931,7 +1038,7 @@ const ComboboxCreateItem = React__namespace.forwardRef((props, ref) => {
|
|
|
931
1038
|
unsub();
|
|
932
1039
|
};
|
|
933
1040
|
}, [textValue, subscribe, getItems]);
|
|
934
|
-
if (!textValue || !show) {
|
|
1041
|
+
if ((!textValue || !show) && !context.visible) {
|
|
935
1042
|
return null;
|
|
936
1043
|
}
|
|
937
1044
|
return /* @__PURE__ */ jsxRuntime.jsx(
|