) {
width: '100%',
height: `${virtualizer.getTotalSize()}px`,
}}
+ ref={(el) => {
+ if (!el) {
+ return
+ }
+
+ // Scroll to the active index
+ {
+ // Ignore this when we are in a test environment
+ if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID !== undefined) {
+ return
+ }
+
+ // Do not scroll when the mouse/pointer is being used
+ if (data.activationTrigger === ActivationTrigger.Pointer) {
+ return
+ }
+
+ if (
+ data.activeOptionIndex !== null &&
+ data.virtual!.options.length > data.activeOptionIndex
+ ) {
+ virtualizer.scrollToIndex(data.activeOptionIndex)
+ }
+ }
+ }}
>
- {props.children}
+ {virtualizer.getVirtualItems().map((item) => {
+ return (
+
+ {React.cloneElement(
+ props.children?.({
+ option: data.virtual!.options[item.index],
+ open: data.comboboxState === ComboboxState.Open,
+ }),
+ {
+ key: `${baseKey}-${item.key}`,
+ 'data-index': item.index,
+ 'aria-setsize': data.virtual!.options.length,
+ 'aria-posinset': item.index + 1,
+ style: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ transform: `translateY(${item.start}px)`,
+ overflowAnchor: 'none',
+ },
+ }
+ )}
+
+ )
+ })}
)
@@ -375,11 +503,14 @@ let ComboboxDataContext = createContext<
activeOptionIndex: number | null
nullable: boolean
immediate: boolean
+
+ virtual: { options: unknown[]; disabled: (value: unknown) => boolean } | null
+ calculateIndex(value: unknown): number
compare(a: unknown, z: unknown): boolean
isSelected(value: unknown): boolean
- __demoMode: boolean
+ isActive(value: unknown): boolean
- virtual: boolean
+ __demoMode: boolean
optionsPropsRef: MutableRefObject<{
static: boolean
@@ -475,7 +606,10 @@ export type ComboboxProps<
form?: string
name?: string
immediate?: boolean
- virtual?: boolean
+ virtual?: {
+ options: TValue[]
+ disabled?: (value: TValue) => boolean
+ } | null
}
function ComboboxFn