@tamagui/select 1.0.1-beta.99 → 1.0.1-rc.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/dist/cjs/BubbleSelect.js +25 -33
- package/dist/cjs/BubbleSelect.js.map +1 -1
- package/dist/cjs/Select.js +391 -789
- package/dist/cjs/Select.js.map +3 -3
- package/dist/cjs/SelectContent.js +72 -0
- package/dist/cjs/SelectContent.js.map +7 -0
- package/dist/cjs/SelectContent.native.js +31 -0
- package/dist/cjs/SelectContent.native.js.map +7 -0
- package/dist/cjs/SelectImpl.js +288 -0
- package/dist/cjs/SelectImpl.js.map +7 -0
- package/dist/cjs/SelectScrollButton.js +157 -0
- package/dist/cjs/SelectScrollButton.js.map +7 -0
- package/dist/cjs/SelectScrollButton.native.js +32 -0
- package/dist/cjs/SelectScrollButton.native.js.map +7 -0
- package/dist/cjs/SelectViewport.js +125 -0
- package/dist/cjs/SelectViewport.js.map +7 -0
- package/dist/cjs/SelectViewport.native.js +41 -0
- package/dist/cjs/SelectViewport.native.js.map +7 -0
- package/dist/cjs/constants.js +47 -0
- package/dist/cjs/constants.js.map +7 -0
- package/dist/cjs/context.js +49 -0
- package/dist/cjs/context.js.map +7 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/types.js +17 -0
- package/dist/cjs/types.js.map +7 -0
- package/dist/cjs/useSelectBreakpointActive.js +39 -0
- package/dist/cjs/useSelectBreakpointActive.js.map +7 -0
- package/dist/esm/BubbleSelect.js +20 -33
- package/dist/esm/BubbleSelect.js.map +1 -1
- package/dist/esm/Select.js +379 -803
- package/dist/esm/Select.js.map +3 -3
- package/dist/esm/SelectContent.js +48 -0
- package/dist/esm/SelectContent.js.map +7 -0
- package/dist/esm/SelectContent.native.js +7 -0
- package/dist/esm/SelectContent.native.js.map +7 -0
- package/dist/esm/SelectImpl.js +273 -0
- package/dist/esm/SelectImpl.js.map +7 -0
- package/dist/esm/SelectScrollButton.js +126 -0
- package/dist/esm/SelectScrollButton.js.map +7 -0
- package/dist/esm/SelectScrollButton.native.js +7 -0
- package/dist/esm/SelectScrollButton.native.js.map +7 -0
- package/dist/esm/SelectViewport.js +94 -0
- package/dist/esm/SelectViewport.js.map +7 -0
- package/dist/esm/SelectViewport.native.js +17 -0
- package/dist/esm/SelectViewport.native.js.map +7 -0
- package/dist/esm/constants.js +17 -0
- package/dist/esm/constants.js.map +7 -0
- package/dist/esm/context.js +21 -0
- package/dist/esm/context.js.map +7 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/types.js +1 -0
- package/dist/esm/types.js.map +7 -0
- package/dist/esm/useSelectBreakpointActive.js +14 -0
- package/dist/esm/useSelectBreakpointActive.js.map +7 -0
- package/dist/jsx/BubbleSelect.js +20 -18
- package/dist/jsx/BubbleSelect.js.map +1 -1
- package/dist/jsx/Select.js +259 -656
- package/dist/jsx/Select.js.map +3 -3
- package/dist/jsx/SelectContent.js +27 -0
- package/dist/jsx/SelectContent.js.map +7 -0
- package/dist/jsx/SelectContent.native.js +7 -0
- package/dist/jsx/SelectContent.native.js.map +7 -0
- package/dist/jsx/SelectImpl.js +246 -0
- package/dist/jsx/SelectImpl.js.map +7 -0
- package/dist/jsx/SelectScrollButton.js +99 -0
- package/dist/jsx/SelectScrollButton.js.map +7 -0
- package/dist/jsx/SelectScrollButton.native.js +7 -0
- package/dist/jsx/SelectScrollButton.native.js.map +7 -0
- package/dist/jsx/SelectViewport.js +72 -0
- package/dist/jsx/SelectViewport.js.map +7 -0
- package/dist/jsx/SelectViewport.native.js +13 -0
- package/dist/jsx/SelectViewport.native.js.map +7 -0
- package/dist/jsx/constants.js +17 -0
- package/dist/jsx/constants.js.map +7 -0
- package/dist/jsx/context.js +15 -0
- package/dist/jsx/context.js.map +7 -0
- package/dist/jsx/index.js +1 -0
- package/dist/jsx/index.js.map +2 -2
- package/dist/jsx/types.js +1 -0
- package/dist/jsx/types.js.map +7 -0
- package/dist/jsx/useSelectBreakpointActive.js +14 -0
- package/dist/jsx/useSelectBreakpointActive.js.map +7 -0
- package/package.json +26 -20
- package/src/Select.tsx +210 -906
- package/src/SelectContent.native.tsx +5 -0
- package/src/SelectContent.tsx +45 -0
- package/src/SelectImpl.tsx +344 -0
- package/src/SelectScrollButton.native.tsx +7 -0
- package/src/SelectScrollButton.tsx +168 -0
- package/src/SelectViewport.native.tsx +14 -0
- package/src/SelectViewport.tsx +104 -0
- package/src/constants.tsx +7 -0
- package/src/context.tsx +19 -0
- package/src/index.tsx +7 -0
- package/src/types.tsx +91 -0
- package/src/useSelectBreakpointActive.tsx +15 -0
- package/types/BubbleSelect.d.ts +2 -0
- package/types/Select.d.ts +449 -599
- package/types/SelectContent.d.ts +5 -0
- package/types/SelectContent.native.d.ts +4 -0
- package/types/SelectImpl.d.ts +9 -0
- package/types/SelectScrollButton.d.ts +6 -0
- package/types/SelectScrollButton.native.d.ts +4 -0
- package/types/SelectViewport.d.ts +127 -0
- package/types/SelectViewport.native.d.ts +7 -0
- package/types/constants.d.ts +8 -0
- package/types/context.d.ts +21 -0
- package/types/index.d.ts +2 -0
- package/types/types.d.ts +81 -0
- package/types/useSelectBreakpointActive.d.ts +4 -0
- package/types/Select.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
package/src/Select.tsx
CHANGED
|
@@ -1,111 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ContextData,
|
|
3
|
-
FloatingContext,
|
|
4
|
-
FloatingFocusManager,
|
|
5
|
-
FloatingOverlay,
|
|
6
|
-
FloatingPortal,
|
|
7
|
-
ReferenceType,
|
|
8
|
-
autoUpdate,
|
|
9
|
-
detectOverflow,
|
|
10
|
-
flip,
|
|
11
|
-
offset,
|
|
12
|
-
size,
|
|
13
|
-
useClick,
|
|
14
|
-
useDismiss,
|
|
15
|
-
useFloating,
|
|
16
|
-
useInteractions,
|
|
17
|
-
useListNavigation,
|
|
18
|
-
useRole,
|
|
19
|
-
useTypeahead,
|
|
20
|
-
} from '@floating-ui/react-dom-interactions'
|
|
21
|
-
import { usePrevious } from '@radix-ui/react-use-previous'
|
|
1
|
+
import { Adapt, useAdaptParent } from '@tamagui/adapt'
|
|
22
2
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
SizeTokens,
|
|
26
|
-
Theme,
|
|
27
|
-
styled,
|
|
28
|
-
useIsomorphicLayoutEffect,
|
|
29
|
-
useThemeName,
|
|
30
|
-
withStaticProperties,
|
|
31
|
-
} from '@tamagui/core'
|
|
3
|
+
import { GetProps, TamaguiElement, isClient, isWeb } from '@tamagui/core'
|
|
4
|
+
import { styled, useGet, useIsomorphicLayoutEffect, withStaticProperties } from '@tamagui/core'
|
|
32
5
|
import { useId } from '@tamagui/core'
|
|
33
|
-
import { createContextScope } from '@tamagui/create-context'
|
|
34
|
-
import type { Scope } from '@tamagui/create-context'
|
|
35
6
|
import { ListItem, ListItemProps } from '@tamagui/list-item'
|
|
7
|
+
import { PortalHost } from '@tamagui/portal'
|
|
36
8
|
import { Separator } from '@tamagui/separator'
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
9
|
+
import { ControlledSheet, SheetController } from '@tamagui/sheet'
|
|
10
|
+
import { XStack, YStack, YStackProps } from '@tamagui/stacks'
|
|
11
|
+
import { Paragraph, SizableText } from '@tamagui/text'
|
|
39
12
|
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
40
13
|
import * as React from 'react'
|
|
41
|
-
import * as ReactDOM from 'react-dom'
|
|
42
|
-
import { View } from 'react-native'
|
|
43
14
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
function getVisualOffsetTop() {
|
|
53
|
-
return !/^((?!chrome|android).)*safari/i.test(userAgent) ? visualViewport?.offsetTop ?? 0 : 0
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/* -------------------------------------------------------------------------------------------------
|
|
57
|
-
* SelectContext
|
|
58
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
59
|
-
|
|
60
|
-
const SELECT_NAME = 'Select'
|
|
61
|
-
const WINDOW_PADDING = 8
|
|
62
|
-
const SCROLL_ARROW_VELOCITY = 8
|
|
63
|
-
const SCROLL_ARROW_THRESHOLD = 8
|
|
64
|
-
const MIN_HEIGHT = 80
|
|
65
|
-
const FALLBACK_THRESHOLD = 16
|
|
66
|
-
|
|
67
|
-
interface SelectContextValue {
|
|
68
|
-
size?: SizeTokens
|
|
69
|
-
value: any
|
|
70
|
-
selectedIndex: number
|
|
71
|
-
setSelectedIndex: (index: number) => void
|
|
72
|
-
activeIndex: number | null
|
|
73
|
-
setActiveIndex: (index: number | null) => void
|
|
74
|
-
setValueAtIndex: (index: number, value: string) => void
|
|
75
|
-
listRef: React.MutableRefObject<Array<HTMLElement | null>>
|
|
76
|
-
floatingRef: React.MutableRefObject<HTMLElement | null>
|
|
77
|
-
open: boolean
|
|
78
|
-
setOpen: (open: boolean) => void
|
|
79
|
-
onChange: (value: string) => void
|
|
80
|
-
dataRef: React.MutableRefObject<ContextData>
|
|
81
|
-
controlledScrolling: boolean
|
|
82
|
-
valueNode: Element | null
|
|
83
|
-
onValueNodeChange(node: HTMLElement): void
|
|
84
|
-
valueNodeHasChildren: boolean
|
|
85
|
-
onValueNodeHasChildrenChange(hasChildren: boolean): void
|
|
86
|
-
canScrollUp: boolean
|
|
87
|
-
canScrollDown: boolean
|
|
88
|
-
floatingContext: FloatingContext<ReferenceType>
|
|
89
|
-
increaseHeight: (floating: HTMLElement, amount?: any) => number | undefined
|
|
90
|
-
forceUpdate: React.DispatchWithoutAction
|
|
91
|
-
interactions: {
|
|
92
|
-
getReferenceProps: (userProps?: React.HTMLProps<Element> | undefined) => any
|
|
93
|
-
getFloatingProps: (userProps?: React.HTMLProps<HTMLElement> | undefined) => any
|
|
94
|
-
getItemProps: (userProps?: React.HTMLProps<HTMLElement> | undefined) => any
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
type ScopedProps<P> = P & { __scopeSelect?: Scope }
|
|
99
|
-
|
|
100
|
-
const [createSelectContext, createSelectScope] = createContextScope(SELECT_NAME)
|
|
101
|
-
const [SelectProvider, useSelectContext] = createSelectContext<SelectContextValue>(SELECT_NAME)
|
|
102
|
-
|
|
103
|
-
// const [SelectContentContextProvider, useSelectContentContext] =
|
|
104
|
-
// createSelectContext<SelectContentContextValue>(CONTENT_NAME);
|
|
105
|
-
|
|
106
|
-
type GenericElement = HTMLElement | View
|
|
107
|
-
|
|
108
|
-
type Direction = 'ltr' | 'rtl'
|
|
15
|
+
import { SELECT_NAME } from './constants'
|
|
16
|
+
import { SelectProvider, createSelectContext, useSelectContext } from './context'
|
|
17
|
+
import { SelectContent } from './SelectContent'
|
|
18
|
+
import { SelectImplProps, SelectInlineImpl } from './SelectImpl'
|
|
19
|
+
import { SelectScrollDownButton, SelectScrollUpButton } from './SelectScrollButton'
|
|
20
|
+
import { SelectViewport } from './SelectViewport'
|
|
21
|
+
import { ScopedProps, SelectProps } from './types'
|
|
22
|
+
import { useSelectBreakpointActive, useShowSelectSheet } from './useSelectBreakpointActive'
|
|
109
23
|
|
|
110
24
|
/* -------------------------------------------------------------------------------------------------
|
|
111
25
|
* SelectTrigger
|
|
@@ -115,7 +29,7 @@ const TRIGGER_NAME = 'SelectTrigger'
|
|
|
115
29
|
|
|
116
30
|
export type SelectTriggerProps = ListItemProps
|
|
117
31
|
|
|
118
|
-
export const SelectTrigger = React.forwardRef<
|
|
32
|
+
export const SelectTrigger = React.forwardRef<TamaguiElement, SelectTriggerProps>(
|
|
119
33
|
(props: ScopedProps<SelectTriggerProps>, forwardedRef) => {
|
|
120
34
|
const {
|
|
121
35
|
__scopeSelect,
|
|
@@ -128,29 +42,35 @@ export const SelectTrigger = React.forwardRef<GenericElement, SelectTriggerProps
|
|
|
128
42
|
// const composedRefs = useComposedRefs(forwardedRef, context.onTriggerChange)
|
|
129
43
|
// const getItems = useCollection(__scopeSelect)
|
|
130
44
|
// const labelId = useLabelContext(context.trigger)
|
|
131
|
-
|
|
45
|
+
const labelledBy = ariaLabelledby // || labelId
|
|
132
46
|
|
|
133
47
|
return (
|
|
134
48
|
<ListItem
|
|
49
|
+
componentName={TRIGGER_NAME}
|
|
135
50
|
backgrounded
|
|
136
51
|
radiused
|
|
137
52
|
hoverTheme
|
|
138
53
|
pressTheme
|
|
139
54
|
focusTheme
|
|
140
|
-
focusable
|
|
55
|
+
focusable
|
|
141
56
|
borderWidth={1}
|
|
142
|
-
componentName={TRIGGER_NAME}
|
|
143
57
|
size={context.size}
|
|
144
58
|
// aria-controls={context.contentId}
|
|
145
59
|
aria-expanded={context.open}
|
|
146
60
|
aria-autocomplete="none"
|
|
147
|
-
|
|
148
|
-
|
|
61
|
+
aria-labelledby={labelledBy}
|
|
62
|
+
dir={context.dir}
|
|
149
63
|
disabled={disabled}
|
|
150
64
|
data-disabled={disabled ? '' : undefined}
|
|
151
65
|
{...triggerProps}
|
|
152
66
|
ref={forwardedRef}
|
|
153
|
-
{...context.interactions
|
|
67
|
+
{...(process.env.TAMAGUI_TARGET === 'web' && context.interactions
|
|
68
|
+
? context.interactions.getReferenceProps()
|
|
69
|
+
: {
|
|
70
|
+
onPress() {
|
|
71
|
+
context.setOpen(!context.open)
|
|
72
|
+
},
|
|
73
|
+
})}
|
|
154
74
|
/>
|
|
155
75
|
)
|
|
156
76
|
}
|
|
@@ -175,14 +95,21 @@ type SelectValueProps = GetProps<typeof SelectValueFrame> & {
|
|
|
175
95
|
|
|
176
96
|
const SelectValue = SelectValueFrame.extractable(
|
|
177
97
|
React.forwardRef<TamaguiElement, SelectValueProps>(
|
|
178
|
-
(
|
|
98
|
+
(
|
|
99
|
+
{ __scopeSelect, children: childrenProp, placeholder }: ScopedProps<SelectValueProps>,
|
|
100
|
+
forwardedRef
|
|
101
|
+
) => {
|
|
179
102
|
// We ignore `className` and `style` as this part shouldn't be styled.
|
|
180
103
|
const context = useSelectContext(VALUE_NAME, __scopeSelect)
|
|
181
104
|
const { onValueNodeHasChildrenChange } = context
|
|
182
|
-
const hasChildren = children !== undefined
|
|
183
105
|
const composedRefs = useComposedRefs(forwardedRef, context.onValueNodeChange)
|
|
184
106
|
|
|
185
|
-
|
|
107
|
+
const children = childrenProp ?? context.selectedItem
|
|
108
|
+
const hasChildren = !!children
|
|
109
|
+
const selectValueChildren =
|
|
110
|
+
context.value === undefined && placeholder !== undefined ? placeholder : children
|
|
111
|
+
|
|
112
|
+
useIsomorphicLayoutEffect(() => {
|
|
186
113
|
onValueNodeHasChildrenChange(hasChildren)
|
|
187
114
|
}, [onValueNodeHasChildrenChange, hasChildren])
|
|
188
115
|
|
|
@@ -194,7 +121,7 @@ const SelectValue = SelectValueFrame.extractable(
|
|
|
194
121
|
// through the item they came from
|
|
195
122
|
pointerEvents="none"
|
|
196
123
|
>
|
|
197
|
-
{
|
|
124
|
+
{selectValueChildren}
|
|
198
125
|
</SelectValueFrame>
|
|
199
126
|
)
|
|
200
127
|
}
|
|
@@ -214,98 +141,6 @@ export const SelectIcon = styled(XStack, {
|
|
|
214
141
|
children: <Paragraph>▼</Paragraph>,
|
|
215
142
|
})
|
|
216
143
|
|
|
217
|
-
/* -------------------------------------------------------------------------------------------------
|
|
218
|
-
* SelectContent
|
|
219
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
220
|
-
|
|
221
|
-
const CONTENT_NAME = 'SelectContent'
|
|
222
|
-
|
|
223
|
-
export type SelectContentProps = { children?: React.ReactNode }
|
|
224
|
-
|
|
225
|
-
const SelectContent = ({ children, __scopeSelect }: ScopedProps<SelectContentProps>) => {
|
|
226
|
-
const context = useSelectContext(CONTENT_NAME, __scopeSelect)
|
|
227
|
-
const themeName = useThemeName()
|
|
228
|
-
|
|
229
|
-
const contents = <Theme name={themeName}>{children}</Theme>
|
|
230
|
-
|
|
231
|
-
return (
|
|
232
|
-
<FloatingPortal>
|
|
233
|
-
{context.open ? (
|
|
234
|
-
<FloatingOverlay lockScroll>{contents}</FloatingOverlay>
|
|
235
|
-
) : (
|
|
236
|
-
<div style={{ display: 'none' }}>{contents}</div>
|
|
237
|
-
)}
|
|
238
|
-
</FloatingPortal>
|
|
239
|
-
)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/* -------------------------------------------------------------------------------------------------
|
|
243
|
-
* SelectViewport
|
|
244
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
245
|
-
|
|
246
|
-
const VIEWPORT_NAME = 'SelectViewport'
|
|
247
|
-
|
|
248
|
-
export const SelectViewportFrame = styled(ThemeableStack, {
|
|
249
|
-
name: VIEWPORT_NAME,
|
|
250
|
-
backgroundColor: '$background',
|
|
251
|
-
elevate: true,
|
|
252
|
-
bordered: true,
|
|
253
|
-
overflow: 'scroll',
|
|
254
|
-
userSelect: 'none',
|
|
255
|
-
|
|
256
|
-
variants: {
|
|
257
|
-
size: {
|
|
258
|
-
'...size': (val, { tokens }) => {
|
|
259
|
-
return {
|
|
260
|
-
borderRadius: tokens.radius[val] ?? val,
|
|
261
|
-
}
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
},
|
|
265
|
-
|
|
266
|
-
defaultVariants: {
|
|
267
|
-
size: '$2',
|
|
268
|
-
},
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
export type SelectViewportProps = GetProps<typeof SelectViewportFrame>
|
|
272
|
-
|
|
273
|
-
export const SelectViewport = React.forwardRef<TamaguiElement, SelectViewportProps>(
|
|
274
|
-
(props: ScopedProps<SelectViewportProps>, forwardedRef) => {
|
|
275
|
-
const { __scopeSelect, children, ...viewportProps } = props
|
|
276
|
-
const context = useSelectContext(VIEWPORT_NAME, __scopeSelect)
|
|
277
|
-
const { style, ...floatingProps } = context.interactions.getFloatingProps()
|
|
278
|
-
delete style['scrollbarWidth']
|
|
279
|
-
delete style['listStyleType']
|
|
280
|
-
return (
|
|
281
|
-
<>
|
|
282
|
-
{/* Hide scrollbars cross-browser and enable momentum scroll for touch devices */}
|
|
283
|
-
<style
|
|
284
|
-
dangerouslySetInnerHTML={{
|
|
285
|
-
__html: `[data-tamagui-select-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-tamagui-select-viewport]::-webkit-scrollbar{display:none}`,
|
|
286
|
-
}}
|
|
287
|
-
/>
|
|
288
|
-
<FloatingFocusManager context={context.floatingContext} preventTabbing>
|
|
289
|
-
<SelectViewportFrame
|
|
290
|
-
size={context.size}
|
|
291
|
-
data-tamagui-select-viewport=""
|
|
292
|
-
// @ts-ignore
|
|
293
|
-
role="presentation"
|
|
294
|
-
{...viewportProps}
|
|
295
|
-
ref={forwardedRef}
|
|
296
|
-
{...floatingProps}
|
|
297
|
-
{...style}
|
|
298
|
-
>
|
|
299
|
-
{children}
|
|
300
|
-
</SelectViewportFrame>
|
|
301
|
-
</FloatingFocusManager>
|
|
302
|
-
</>
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
SelectViewport.displayName = VIEWPORT_NAME
|
|
308
|
-
|
|
309
144
|
/* -------------------------------------------------------------------------------------------------
|
|
310
145
|
* SelectItem
|
|
311
146
|
* -----------------------------------------------------------------------------------------------*/
|
|
@@ -316,7 +151,6 @@ type SelectItemContextValue = {
|
|
|
316
151
|
value: string
|
|
317
152
|
textId: string
|
|
318
153
|
isSelected: boolean
|
|
319
|
-
onItemTextChange(node: TamaguiElement | null): void
|
|
320
154
|
}
|
|
321
155
|
|
|
322
156
|
const [SelectItemContextProvider, useSelectItemContext] =
|
|
@@ -329,8 +163,6 @@ export interface SelectItemProps extends YStackProps {
|
|
|
329
163
|
textValue?: string
|
|
330
164
|
}
|
|
331
165
|
|
|
332
|
-
// TODO styled(ListItem, { name: 'SelectItem' })
|
|
333
|
-
|
|
334
166
|
export const SelectItem = React.forwardRef<TamaguiElement, SelectItemProps>(
|
|
335
167
|
(props: ScopedProps<SelectItemProps>, forwardedRef) => {
|
|
336
168
|
const {
|
|
@@ -343,8 +175,6 @@ export const SelectItem = React.forwardRef<TamaguiElement, SelectItemProps>(
|
|
|
343
175
|
} = props
|
|
344
176
|
const context = useSelectContext(ITEM_NAME, __scopeSelect)
|
|
345
177
|
const isSelected = context.value === value
|
|
346
|
-
const [textValue, setTextValue] = React.useState(textValueProp ?? '')
|
|
347
|
-
const [isFocused, setIsFocused] = React.useState(false)
|
|
348
178
|
const textId = useId()
|
|
349
179
|
|
|
350
180
|
const {
|
|
@@ -354,28 +184,26 @@ export const SelectItem = React.forwardRef<TamaguiElement, SelectItemProps>(
|
|
|
354
184
|
open,
|
|
355
185
|
setOpen,
|
|
356
186
|
onChange,
|
|
357
|
-
activeIndex,
|
|
358
187
|
setActiveIndex,
|
|
188
|
+
allowMouseUpRef,
|
|
189
|
+
allowSelectRef,
|
|
359
190
|
setValueAtIndex,
|
|
191
|
+
selectTimeoutRef,
|
|
360
192
|
dataRef,
|
|
361
193
|
} = context
|
|
362
194
|
|
|
363
|
-
const composedRefs = useComposedRefs(
|
|
364
|
-
|
|
365
|
-
(node)
|
|
366
|
-
if (
|
|
195
|
+
const composedRefs = useComposedRefs(forwardedRef, (node) => {
|
|
196
|
+
if (!isWeb) return
|
|
197
|
+
if (node instanceof HTMLElement) {
|
|
198
|
+
if (listRef) {
|
|
367
199
|
listRef.current[index] = node
|
|
368
200
|
}
|
|
369
201
|
}
|
|
370
|
-
|
|
371
|
-
)
|
|
202
|
+
})
|
|
372
203
|
|
|
373
204
|
React.useEffect(() => {
|
|
374
205
|
setValueAtIndex(index, value)
|
|
375
|
-
}, [index])
|
|
376
|
-
|
|
377
|
-
const timeoutRef = React.useRef<any>()
|
|
378
|
-
const [allowMouseUp, setAllowMouseUp] = React.useState(false)
|
|
206
|
+
}, [index, setValueAtIndex, value])
|
|
379
207
|
|
|
380
208
|
function handleSelect() {
|
|
381
209
|
setSelectedIndex(index)
|
|
@@ -383,33 +211,46 @@ export const SelectItem = React.forwardRef<TamaguiElement, SelectItemProps>(
|
|
|
383
211
|
setOpen(false)
|
|
384
212
|
}
|
|
385
213
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
214
|
+
const selectItemProps = context.interactions
|
|
215
|
+
? context.interactions.getItemProps({
|
|
216
|
+
onTouchStart() {
|
|
217
|
+
allowSelectRef!.current = true
|
|
218
|
+
allowMouseUpRef!.current = false
|
|
219
|
+
},
|
|
220
|
+
onKeyDown(event) {
|
|
221
|
+
if (event.key === 'Enter' || (event.key === ' ' && !dataRef?.current.typing)) {
|
|
222
|
+
event.preventDefault()
|
|
223
|
+
handleSelect()
|
|
224
|
+
} else {
|
|
225
|
+
allowSelectRef!.current = true
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
onClick() {
|
|
229
|
+
if (allowSelectRef!.current) {
|
|
230
|
+
setSelectedIndex(index)
|
|
231
|
+
setOpen(false)
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
onMouseUp() {
|
|
235
|
+
if (!allowMouseUpRef!.current) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
400
238
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
handleSelect()
|
|
405
|
-
}
|
|
406
|
-
}
|
|
239
|
+
if (allowSelectRef!.current) {
|
|
240
|
+
handleSelect()
|
|
241
|
+
}
|
|
407
242
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
243
|
+
// On touch devices, prevent the element from
|
|
244
|
+
// immediately closing `onClick` by deferring it
|
|
245
|
+
clearTimeout(selectTimeoutRef!.current)
|
|
246
|
+
selectTimeoutRef!.current = setTimeout(() => {
|
|
247
|
+
allowSelectRef!.current = true
|
|
248
|
+
})
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
: {
|
|
252
|
+
onPress: handleSelect,
|
|
253
|
+
}
|
|
413
254
|
|
|
414
255
|
return (
|
|
415
256
|
<SelectItemContextProvider
|
|
@@ -417,20 +258,16 @@ export const SelectItem = React.forwardRef<TamaguiElement, SelectItemProps>(
|
|
|
417
258
|
value={value}
|
|
418
259
|
textId={textId || ''}
|
|
419
260
|
isSelected={isSelected}
|
|
420
|
-
onItemTextChange={React.useCallback((node) => {
|
|
421
|
-
// @ts-ignore
|
|
422
|
-
setTextValue((prevTextValue) => prevTextValue || (node?.textContent ?? '').trim())
|
|
423
|
-
}, [])}
|
|
424
261
|
>
|
|
425
262
|
<ListItem
|
|
426
263
|
backgrounded
|
|
427
264
|
pressTheme
|
|
265
|
+
cursor=""
|
|
428
266
|
focusTheme
|
|
429
267
|
componentName={ITEM_NAME}
|
|
430
268
|
ref={composedRefs}
|
|
431
269
|
aria-labelledby={textId}
|
|
432
|
-
|
|
433
|
-
aria-selected={isSelected && isFocused}
|
|
270
|
+
aria-selected={isSelected}
|
|
434
271
|
data-state={isSelected ? 'active' : 'inactive'}
|
|
435
272
|
aria-disabled={disabled || undefined}
|
|
436
273
|
data-disabled={disabled ? '' : undefined}
|
|
@@ -452,7 +289,7 @@ SelectItem.displayName = ITEM_NAME
|
|
|
452
289
|
|
|
453
290
|
const ITEM_TEXT_NAME = 'SelectItemText'
|
|
454
291
|
|
|
455
|
-
export const SelectItemTextFrame = styled(
|
|
292
|
+
export const SelectItemTextFrame = styled(SizableText, {
|
|
456
293
|
name: ITEM_TEXT_NAME,
|
|
457
294
|
selectable: false,
|
|
458
295
|
})
|
|
@@ -461,26 +298,44 @@ type SelectItemTextProps = GetProps<typeof SelectItemTextFrame>
|
|
|
461
298
|
|
|
462
299
|
const SelectItemText = React.forwardRef<TamaguiElement, SelectItemTextProps>(
|
|
463
300
|
(props: ScopedProps<SelectItemTextProps>, forwardedRef) => {
|
|
464
|
-
|
|
465
|
-
const { __scopeSelect, className, style, ...itemTextProps } = props
|
|
301
|
+
const { __scopeSelect, className, ...itemTextProps } = props
|
|
466
302
|
const context = useSelectContext(ITEM_TEXT_NAME, __scopeSelect)
|
|
467
303
|
const itemContext = useSelectItemContext(ITEM_TEXT_NAME, __scopeSelect)
|
|
468
304
|
const ref = React.useRef<TamaguiElement | null>(null)
|
|
469
|
-
const composedRefs = useComposedRefs(forwardedRef, ref
|
|
305
|
+
const composedRefs = useComposedRefs(forwardedRef, ref)
|
|
306
|
+
const isSelected = Boolean(itemContext.isSelected && context.valueNode)
|
|
470
307
|
|
|
471
|
-
|
|
472
|
-
|
|
308
|
+
const contents = React.useMemo(
|
|
309
|
+
() => (
|
|
473
310
|
<SelectItemTextFrame
|
|
311
|
+
className={className}
|
|
474
312
|
size={context.size}
|
|
475
313
|
id={itemContext.textId}
|
|
476
314
|
{...itemTextProps}
|
|
477
315
|
ref={composedRefs}
|
|
478
316
|
/>
|
|
317
|
+
),
|
|
318
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
319
|
+
[props, context.size, className, itemContext.textId]
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
// until portals work in sub-trees on RN, use this just for native:
|
|
323
|
+
React.useEffect(() => {
|
|
324
|
+
if (isSelected) {
|
|
325
|
+
context.setSelectedItem(contents)
|
|
326
|
+
}
|
|
327
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
328
|
+
}, [isSelected, contents])
|
|
329
|
+
|
|
330
|
+
return (
|
|
331
|
+
<>
|
|
332
|
+
{contents}
|
|
479
333
|
|
|
480
334
|
{/* Portal the select item text into the trigger value node */}
|
|
481
|
-
{
|
|
482
|
-
|
|
483
|
-
|
|
335
|
+
{/* this needs some extra stability between renders */}
|
|
336
|
+
{/* {isWeb && isSelected
|
|
337
|
+
? ReactDOM.createPortal(itemTextProps.children, context.valueNode!)
|
|
338
|
+
: null} */}
|
|
484
339
|
|
|
485
340
|
{/* Portal an option in the bubble select */}
|
|
486
341
|
{/* {context.bubbleSelect
|
|
@@ -579,7 +434,6 @@ const SelectLabel = React.forwardRef<TamaguiElement, SelectLabelProps>(
|
|
|
579
434
|
id={groupContext.id}
|
|
580
435
|
size={context.size}
|
|
581
436
|
{...labelProps}
|
|
582
|
-
// @ts-expect-error
|
|
583
437
|
ref={forwardedRef}
|
|
584
438
|
/>
|
|
585
439
|
)
|
|
@@ -589,182 +443,63 @@ const SelectLabel = React.forwardRef<TamaguiElement, SelectLabelProps>(
|
|
|
589
443
|
SelectLabel.displayName = LABEL_NAME
|
|
590
444
|
|
|
591
445
|
/* -------------------------------------------------------------------------------------------------
|
|
592
|
-
*
|
|
593
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
594
|
-
|
|
595
|
-
const SCROLL_UP_BUTTON_NAME = 'SelectScrollUpButton'
|
|
596
|
-
|
|
597
|
-
interface SelectScrollButtonProps
|
|
598
|
-
extends Omit<SelectScrollButtonImplProps, 'dir' | 'componentName'> {}
|
|
599
|
-
|
|
600
|
-
const SelectScrollUpButton = React.forwardRef<TamaguiElement, SelectScrollButtonProps>(
|
|
601
|
-
(props: ScopedProps<SelectScrollButtonProps>, forwardedRef) => {
|
|
602
|
-
return (
|
|
603
|
-
<SelectScrollButtonImpl
|
|
604
|
-
componentName={SCROLL_UP_BUTTON_NAME}
|
|
605
|
-
{...props}
|
|
606
|
-
dir="up"
|
|
607
|
-
ref={forwardedRef}
|
|
608
|
-
/>
|
|
609
|
-
)
|
|
610
|
-
}
|
|
611
|
-
)
|
|
612
|
-
|
|
613
|
-
SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME
|
|
614
|
-
|
|
615
|
-
/* -------------------------------------------------------------------------------------------------
|
|
616
|
-
* SelectScrollDownButton
|
|
446
|
+
* SelectSeparator
|
|
617
447
|
* -----------------------------------------------------------------------------------------------*/
|
|
618
448
|
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
(props: ScopedProps<SelectScrollButtonProps>, forwardedRef) => {
|
|
623
|
-
return (
|
|
624
|
-
<SelectScrollButtonImpl
|
|
625
|
-
componentName={SCROLL_DOWN_BUTTON_NAME}
|
|
626
|
-
{...props}
|
|
627
|
-
dir="down"
|
|
628
|
-
ref={forwardedRef}
|
|
629
|
-
/>
|
|
630
|
-
)
|
|
631
|
-
}
|
|
632
|
-
)
|
|
633
|
-
|
|
634
|
-
SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME
|
|
635
|
-
|
|
636
|
-
type SelectScrollButtonImplElement = TamaguiElement
|
|
637
|
-
interface SelectScrollButtonImplProps extends YStackProps {
|
|
638
|
-
dir: 'up' | 'down'
|
|
639
|
-
componentName: string
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
const SelectScrollButtonImpl = React.forwardRef<
|
|
643
|
-
SelectScrollButtonImplElement,
|
|
644
|
-
SelectScrollButtonImplProps
|
|
645
|
-
>((props: ScopedProps<SelectScrollButtonImplProps>, forwardedRef) => {
|
|
646
|
-
const { __scopeSelect, dir, componentName, ...scrollIndicatorProps } = props
|
|
647
|
-
const { floatingRef, increaseHeight, forceUpdate, ...context } = useSelectContext(
|
|
648
|
-
componentName,
|
|
649
|
-
__scopeSelect
|
|
650
|
-
)
|
|
651
|
-
const intervalRef = React.useRef<any>()
|
|
652
|
-
const loopingRef = React.useRef(false)
|
|
653
|
-
const isVisible = context[dir === 'down' ? 'canScrollDown' : 'canScrollUp']
|
|
654
|
-
|
|
655
|
-
const { x, y, reference, floating, strategy, update, refs } = useFloating({
|
|
656
|
-
strategy: 'fixed',
|
|
657
|
-
placement: dir === 'up' ? 'top' : 'bottom',
|
|
658
|
-
middleware: [offset(({ rects }) => -rects.floating.height)],
|
|
659
|
-
})
|
|
660
|
-
|
|
661
|
-
const composedRefs = useComposedRefs(forwardedRef, floating)
|
|
662
|
-
|
|
663
|
-
React.useLayoutEffect(() => {
|
|
664
|
-
reference(floatingRef.current)
|
|
665
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
666
|
-
}, [reference, floatingRef.current])
|
|
667
|
-
|
|
668
|
-
React.useEffect(() => {
|
|
669
|
-
if (!refs.reference.current || !refs.floating.current || !isVisible) {
|
|
670
|
-
return
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
const cleanup = autoUpdate(refs.reference.current, refs.floating.current, update, {
|
|
674
|
-
animationFrame: true,
|
|
675
|
-
})
|
|
676
|
-
|
|
677
|
-
return () => {
|
|
678
|
-
clearInterval(intervalRef.current)
|
|
679
|
-
loopingRef.current = false
|
|
680
|
-
cleanup()
|
|
681
|
-
}
|
|
682
|
-
}, [isVisible, update, refs.floating, refs.reference])
|
|
683
|
-
|
|
684
|
-
if (!isVisible) {
|
|
685
|
-
return null
|
|
686
|
-
}
|
|
449
|
+
export const SelectSeparator = styled(Separator, {
|
|
450
|
+
name: 'SelectSeparator',
|
|
451
|
+
})
|
|
687
452
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (floating) {
|
|
693
|
-
const value = isUp ? -SCROLL_ARROW_VELOCITY : SCROLL_ARROW_VELOCITY
|
|
694
|
-
const multi =
|
|
695
|
-
(isUp && floating.scrollTop <= SCROLL_ARROW_THRESHOLD * 2) ||
|
|
696
|
-
(!isUp &&
|
|
697
|
-
floating.scrollTop >=
|
|
698
|
-
floating.scrollHeight - floating.clientHeight - SCROLL_ARROW_THRESHOLD * 2)
|
|
699
|
-
? 2
|
|
700
|
-
: 1
|
|
701
|
-
|
|
702
|
-
floating.scrollTop += multi * (isUp ? -SCROLL_ARROW_VELOCITY : SCROLL_ARROW_VELOCITY)
|
|
703
|
-
|
|
704
|
-
increaseHeight(floating, multi === 2 ? value * 2 : value)
|
|
705
|
-
// Ensure derived data (scroll arrows) is fresh
|
|
706
|
-
forceUpdate()
|
|
707
|
-
}
|
|
453
|
+
const SelectSheetController = (
|
|
454
|
+
props: ScopedProps<{}> & {
|
|
455
|
+
children: React.ReactNode
|
|
456
|
+
onOpenChange: React.Dispatch<React.SetStateAction<boolean>>
|
|
708
457
|
}
|
|
458
|
+
) => {
|
|
459
|
+
const context = useSelectContext('SelectSheetController', props.__scopeSelect)
|
|
460
|
+
const showSheet = useShowSelectSheet(context)
|
|
461
|
+
const breakpointActive = useSelectBreakpointActive(context.sheetBreakpoint)
|
|
462
|
+
const getShowSheet = useGet(showSheet)
|
|
709
463
|
|
|
710
464
|
return (
|
|
711
|
-
<
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
{...scrollIndicatorProps}
|
|
716
|
-
zIndex={1000}
|
|
717
|
-
// @ts-expect-error
|
|
718
|
-
position={strategy}
|
|
719
|
-
left={x || 0}
|
|
720
|
-
top={y || 0}
|
|
721
|
-
width={`calc(${(floatingRef.current?.offsetWidth ?? 0) - 2}px)`}
|
|
722
|
-
onPointerMove={() => {
|
|
723
|
-
if (!loopingRef.current) {
|
|
724
|
-
intervalRef.current = setInterval(handleScrollArrowChange, 1000 / 60)
|
|
725
|
-
loopingRef.current = true
|
|
465
|
+
<SheetController
|
|
466
|
+
onOpenChange={(val) => {
|
|
467
|
+
if (getShowSheet()) {
|
|
468
|
+
props.onOpenChange(val)
|
|
726
469
|
}
|
|
727
470
|
}}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
|
|
471
|
+
open={context.open}
|
|
472
|
+
hidden={breakpointActive === false}
|
|
473
|
+
>
|
|
474
|
+
{props.children}
|
|
475
|
+
</SheetController>
|
|
733
476
|
)
|
|
734
|
-
}
|
|
477
|
+
}
|
|
735
478
|
|
|
736
479
|
/* -------------------------------------------------------------------------------------------------
|
|
737
|
-
*
|
|
480
|
+
* SelectSheetContents
|
|
738
481
|
* -----------------------------------------------------------------------------------------------*/
|
|
739
482
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
})
|
|
483
|
+
const SHEET_CONTENTS_NAME = 'SelectSheetContents'
|
|
484
|
+
|
|
485
|
+
export const SelectSheetContents = ({ __scopeSelect }: ScopedProps<{}>) => {
|
|
486
|
+
const context = useSelectContext(SHEET_CONTENTS_NAME, __scopeSelect)
|
|
487
|
+
return <PortalHost name={`${context.scopeKey}SheetContents`} />
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
SelectSheetContents.displayName = SHEET_CONTENTS_NAME
|
|
491
|
+
|
|
492
|
+
const SelectSheetImpl = (props: SelectImplProps) => {
|
|
493
|
+
return <>{props.children}</>
|
|
494
|
+
}
|
|
743
495
|
|
|
744
496
|
/* -------------------------------------------------------------------------------------------------
|
|
745
497
|
* Select
|
|
746
498
|
* -----------------------------------------------------------------------------------------------*/
|
|
747
499
|
|
|
748
|
-
export interface SelectProps {
|
|
749
|
-
id?: string
|
|
750
|
-
children?: React.ReactNode
|
|
751
|
-
value?: string
|
|
752
|
-
defaultValue?: string
|
|
753
|
-
onValueChange?(value: string): void
|
|
754
|
-
open?: boolean
|
|
755
|
-
defaultOpen?: boolean
|
|
756
|
-
onOpenChange?(open: boolean): void
|
|
757
|
-
dir?: Direction
|
|
758
|
-
name?: string
|
|
759
|
-
autoComplete?: string
|
|
760
|
-
size?: SizeTokens
|
|
761
|
-
}
|
|
762
|
-
|
|
763
500
|
export const Select = withStaticProperties(
|
|
764
501
|
(props: ScopedProps<SelectProps>) => {
|
|
765
502
|
const {
|
|
766
|
-
// TODO use id for focusing from label
|
|
767
|
-
id,
|
|
768
503
|
__scopeSelect,
|
|
769
504
|
children,
|
|
770
505
|
open: openProp,
|
|
@@ -773,532 +508,101 @@ export const Select = withStaticProperties(
|
|
|
773
508
|
value: valueProp,
|
|
774
509
|
defaultValue,
|
|
775
510
|
onValueChange,
|
|
776
|
-
size: sizeProp,
|
|
511
|
+
size: sizeProp = '$4',
|
|
777
512
|
dir,
|
|
778
|
-
name,
|
|
779
|
-
autoComplete,
|
|
780
513
|
} = props
|
|
781
514
|
|
|
782
|
-
|
|
515
|
+
const { when, AdaptProvider } = useAdaptParent({
|
|
516
|
+
Contents: SelectSheetContents,
|
|
517
|
+
})
|
|
518
|
+
const sheetBreakpoint = when || false
|
|
519
|
+
const isSheet = useSelectBreakpointActive(sheetBreakpoint)
|
|
520
|
+
const SelectImpl = isSheet ? SelectSheetImpl : SelectInlineImpl
|
|
521
|
+
const forceUpdate = React.useReducer(() => ({}), {})[1]
|
|
522
|
+
const [selectedItem, setSelectedItem] = React.useState<React.ReactNode>(null)
|
|
783
523
|
|
|
784
524
|
const [open, setOpen] = useControllableState({
|
|
785
525
|
prop: openProp,
|
|
786
526
|
defaultProp: defaultOpen || false,
|
|
787
527
|
onChange: onOpenChange,
|
|
528
|
+
strategy: 'most-recent-wins',
|
|
788
529
|
})
|
|
789
530
|
|
|
790
531
|
const [value, setValue] = useControllableState({
|
|
791
532
|
prop: valueProp,
|
|
792
533
|
defaultProp: defaultValue || '',
|
|
793
534
|
onChange: onValueChange,
|
|
535
|
+
strategy: 'most-recent-wins',
|
|
794
536
|
})
|
|
795
537
|
|
|
796
538
|
const [activeIndex, setActiveIndex] = React.useState<number | null>(null)
|
|
797
539
|
const selectedIndexRef = React.useRef<number | null>(null)
|
|
798
540
|
const activeIndexRef = React.useRef<number | null>(null)
|
|
799
|
-
const prevActiveIndex = usePrevious<number | null>(activeIndex)
|
|
800
541
|
|
|
801
|
-
const [showArrows, setShowArrows] = React.useState(false)
|
|
802
|
-
const [scrollTop, setScrollTop] = React.useState(0)
|
|
803
|
-
const listItemsRef = React.useRef<Array<HTMLElement | null>>([])
|
|
804
542
|
const listContentRef = React.useRef<string[]>([])
|
|
805
543
|
|
|
806
544
|
const [selectedIndex, setSelectedIndex] = React.useState(
|
|
807
545
|
Math.max(0, listContentRef.current.indexOf(value))
|
|
808
546
|
)
|
|
809
547
|
|
|
810
|
-
const [
|
|
811
|
-
const [
|
|
548
|
+
const [valueNode, setValueNode] = React.useState<HTMLElement | null>(null)
|
|
549
|
+
const [valueNodeHasChildren, setValueNodeHasChildren] = React.useState(false)
|
|
812
550
|
|
|
813
551
|
useIsomorphicLayoutEffect(() => {
|
|
814
552
|
selectedIndexRef.current = selectedIndex
|
|
815
553
|
activeIndexRef.current = activeIndex
|
|
816
554
|
})
|
|
817
555
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
React.useEffect(() => {
|
|
821
|
-
const frame = requestAnimationFrame(() => {
|
|
822
|
-
setShowArrows(open)
|
|
823
|
-
|
|
824
|
-
if (!open) {
|
|
825
|
-
setScrollTop(0)
|
|
826
|
-
setMiddlewareType('align')
|
|
827
|
-
setActiveIndex(null)
|
|
828
|
-
setControlledScrolling(false)
|
|
829
|
-
}
|
|
830
|
-
})
|
|
831
|
-
return () => {
|
|
832
|
-
cancelAnimationFrame(frame)
|
|
833
|
-
}
|
|
834
|
-
}, [open])
|
|
835
|
-
|
|
836
|
-
function getFloatingPadding(floating: HTMLElement | null) {
|
|
837
|
-
if (!floating) {
|
|
838
|
-
return 0
|
|
839
|
-
}
|
|
840
|
-
return Number(getComputedStyle(floating).paddingLeft?.replace('px', ''))
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
const { x, y, reference, floating, strategy, context, refs, middlewareData, update } =
|
|
844
|
-
useFloating({
|
|
845
|
-
open,
|
|
846
|
-
onOpenChange: setOpen,
|
|
847
|
-
placement: 'bottom',
|
|
848
|
-
middleware:
|
|
849
|
-
middlewareType === 'align'
|
|
850
|
-
? [
|
|
851
|
-
offset(({ rects }) => {
|
|
852
|
-
const index = activeIndexRef.current ?? selectedIndexRef.current
|
|
853
|
-
|
|
854
|
-
if (index == null) {
|
|
855
|
-
return 0
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
const item = listItemsRef.current[index]
|
|
859
|
-
|
|
860
|
-
if (item == null) {
|
|
861
|
-
return 0
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
const offsetTop = item.offsetTop
|
|
865
|
-
const itemHeight = item.offsetHeight
|
|
866
|
-
const height = rects.reference.height
|
|
867
|
-
|
|
868
|
-
return -offsetTop - height - (itemHeight - height) / 2
|
|
869
|
-
}),
|
|
870
|
-
// Custom `size` that can handle the opposite direction of the placement
|
|
871
|
-
{
|
|
872
|
-
name: 'size',
|
|
873
|
-
async fn(args) {
|
|
874
|
-
const {
|
|
875
|
-
elements: { floating },
|
|
876
|
-
rects: { reference },
|
|
877
|
-
middlewareData,
|
|
878
|
-
} = args
|
|
879
|
-
|
|
880
|
-
const overflow = await detectOverflow(args, {
|
|
881
|
-
padding: WINDOW_PADDING,
|
|
882
|
-
})
|
|
883
|
-
|
|
884
|
-
const top = Math.max(0, overflow.top)
|
|
885
|
-
const bottom = Math.max(0, overflow.bottom)
|
|
886
|
-
const nextY = args.y + top
|
|
887
|
-
|
|
888
|
-
if (middlewareData.size?.skip) {
|
|
889
|
-
return {
|
|
890
|
-
y: nextY,
|
|
891
|
-
data: {
|
|
892
|
-
y: middlewareData.size.y,
|
|
893
|
-
},
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
Object.assign(floating.style, {
|
|
898
|
-
maxHeight: `${floating.scrollHeight - Math.abs(top + bottom)}px`,
|
|
899
|
-
minWidth: `${reference.width + getFloatingPadding(floating) * 2}px`,
|
|
900
|
-
})
|
|
901
|
-
|
|
902
|
-
return {
|
|
903
|
-
y: nextY,
|
|
904
|
-
data: {
|
|
905
|
-
y: top,
|
|
906
|
-
skip: true,
|
|
907
|
-
},
|
|
908
|
-
reset: {
|
|
909
|
-
rects: true,
|
|
910
|
-
},
|
|
911
|
-
}
|
|
912
|
-
},
|
|
913
|
-
},
|
|
914
|
-
]
|
|
915
|
-
: [
|
|
916
|
-
offset(5),
|
|
917
|
-
flip(),
|
|
918
|
-
size({
|
|
919
|
-
apply({ rects, availableHeight, elements }) {
|
|
920
|
-
Object.assign(elements.floating.style, {
|
|
921
|
-
width: `${rects.reference.width}px`,
|
|
922
|
-
maxHeight: `${availableHeight}px`,
|
|
923
|
-
})
|
|
924
|
-
},
|
|
925
|
-
padding: WINDOW_PADDING,
|
|
926
|
-
}),
|
|
927
|
-
],
|
|
928
|
-
})
|
|
929
|
-
|
|
930
|
-
const floatingRef = refs.floating
|
|
931
|
-
const forceUpdate = React.useReducer(() => ({}), {})[1]
|
|
932
|
-
|
|
933
|
-
const showUpArrow = showArrows && scrollTop > SCROLL_ARROW_THRESHOLD
|
|
934
|
-
const showDownArrow =
|
|
935
|
-
showArrows &&
|
|
936
|
-
floatingRef.current &&
|
|
937
|
-
scrollTop <
|
|
938
|
-
floatingRef.current.scrollHeight - floatingRef.current.clientHeight - SCROLL_ARROW_THRESHOLD
|
|
939
|
-
|
|
940
|
-
const interactions = useInteractions([
|
|
941
|
-
useClick(context, { pointerDown: true }),
|
|
942
|
-
useRole(context, { role: 'listbox' }),
|
|
943
|
-
useDismiss(context),
|
|
944
|
-
useListNavigation(context, {
|
|
945
|
-
listRef: listItemsRef,
|
|
946
|
-
activeIndex,
|
|
947
|
-
selectedIndex,
|
|
948
|
-
onNavigate: setActiveIndex,
|
|
949
|
-
}),
|
|
950
|
-
useTypeahead(context, {
|
|
951
|
-
listRef: listContentRef,
|
|
952
|
-
onMatch: open ? setActiveIndex : setSelectedIndex,
|
|
953
|
-
selectedIndex,
|
|
954
|
-
activeIndex,
|
|
955
|
-
}),
|
|
956
|
-
])
|
|
957
|
-
|
|
958
|
-
const increaseHeight = React.useCallback(
|
|
959
|
-
(floating: HTMLElement, amount = 0) => {
|
|
960
|
-
if (middlewareType === 'fallback') {
|
|
961
|
-
return
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
const currentMaxHeight = Number(floating.style.maxHeight.replace('px', ''))
|
|
965
|
-
const currentTop = Number(floating.style.top.replace('px', ''))
|
|
966
|
-
const rect = floating.getBoundingClientRect()
|
|
967
|
-
const rectTop = rect.top
|
|
968
|
-
const rectBottom = rect.bottom
|
|
969
|
-
const viewportHeight = visualViewport?.height ?? 0
|
|
970
|
-
const visualMaxHeight = viewportHeight - WINDOW_PADDING * 2
|
|
971
|
-
|
|
972
|
-
if (
|
|
973
|
-
amount < 0 &&
|
|
974
|
-
selectedIndexRef.current != null &&
|
|
975
|
-
Math.round(rectBottom) <
|
|
976
|
-
Math.round(viewportHeight + getVisualOffsetTop() - WINDOW_PADDING)
|
|
977
|
-
) {
|
|
978
|
-
floating.style.maxHeight = `${Math.min(visualMaxHeight, currentMaxHeight - amount)}px`
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
if (
|
|
982
|
-
amount > 0 &&
|
|
983
|
-
Math.round(rectTop) > Math.round(WINDOW_PADDING - getVisualOffsetTop()) &&
|
|
984
|
-
floating.scrollHeight > floating.offsetHeight
|
|
985
|
-
) {
|
|
986
|
-
const nextTop = Math.max(WINDOW_PADDING + getVisualOffsetTop(), currentTop - amount)
|
|
987
|
-
|
|
988
|
-
const nextMaxHeight = Math.min(visualMaxHeight, currentMaxHeight + amount)
|
|
989
|
-
|
|
990
|
-
Object.assign(floating.style, {
|
|
991
|
-
maxHeight: `${nextMaxHeight}px`,
|
|
992
|
-
top: `${nextTop}px`,
|
|
993
|
-
})
|
|
994
|
-
|
|
995
|
-
if (nextTop - WINDOW_PADDING > getVisualOffsetTop()) {
|
|
996
|
-
floating.scrollTop -= nextMaxHeight - currentMaxHeight + getFloatingPadding(floating)
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
return currentTop - nextTop
|
|
1000
|
-
}
|
|
1001
|
-
},
|
|
1002
|
-
[middlewareType]
|
|
1003
|
-
)
|
|
1004
|
-
|
|
1005
|
-
const touchPageYRef = React.useRef<number | null>(null)
|
|
1006
|
-
|
|
1007
|
-
const handleWheel = React.useCallback(
|
|
1008
|
-
(event: WheelEvent | TouchEvent) => {
|
|
1009
|
-
const pinching = event.ctrlKey
|
|
1010
|
-
|
|
1011
|
-
const currentTarget = event.currentTarget as HTMLElement
|
|
1012
|
-
|
|
1013
|
-
function isWheelEvent(event: any): event is WheelEvent {
|
|
1014
|
-
return typeof event.deltaY === 'number'
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
function isTouchEvent(event: any): event is TouchEvent {
|
|
1018
|
-
return event.touches != null
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
if (
|
|
1022
|
-
Math.abs(
|
|
1023
|
-
(currentTarget?.offsetHeight ?? 0) -
|
|
1024
|
-
((visualViewport?.height ?? 0) - WINDOW_PADDING * 2)
|
|
1025
|
-
) > 1 &&
|
|
1026
|
-
!pinching
|
|
1027
|
-
) {
|
|
1028
|
-
event.preventDefault()
|
|
1029
|
-
} else if (isWheelEvent(event) && isFirefox) {
|
|
1030
|
-
// Firefox needs this to propagate scrolling
|
|
1031
|
-
// during momentum scrolling phase if the
|
|
1032
|
-
// height reached its maximum (at boundaries)
|
|
1033
|
-
currentTarget.scrollTop += event.deltaY
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
if (!pinching) {
|
|
1037
|
-
let delta = 5
|
|
1038
|
-
|
|
1039
|
-
if (isTouchEvent(event)) {
|
|
1040
|
-
const currentPageY = touchPageYRef.current
|
|
1041
|
-
const pageY = event.touches[0]?.pageY
|
|
1042
|
-
|
|
1043
|
-
if (pageY != null) {
|
|
1044
|
-
touchPageYRef.current = pageY
|
|
1045
|
-
|
|
1046
|
-
if (currentPageY != null) {
|
|
1047
|
-
delta = currentPageY - pageY
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
increaseHeight(currentTarget, isWheelEvent(event) ? event.deltaY : delta)
|
|
1053
|
-
setScrollTop(currentTarget.scrollTop)
|
|
1054
|
-
// Ensure derived data (scroll arrows) is fresh
|
|
1055
|
-
forceUpdate()
|
|
1056
|
-
}
|
|
1057
|
-
},
|
|
1058
|
-
[increaseHeight, forceUpdate]
|
|
1059
|
-
)
|
|
1060
|
-
|
|
1061
|
-
// Handle `onWheel` event in an effect to remove the `passive` option so we
|
|
1062
|
-
// can .preventDefault() it
|
|
1063
|
-
React.useEffect(() => {
|
|
1064
|
-
function onTouchEnd() {
|
|
1065
|
-
touchPageYRef.current = null
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
const floating = floatingRef.current
|
|
1069
|
-
if (open && floating && middlewareType === 'align') {
|
|
1070
|
-
floating.addEventListener('wheel', handleWheel)
|
|
1071
|
-
floating.addEventListener('touchmove', handleWheel)
|
|
1072
|
-
floating.addEventListener('touchend', onTouchEnd, { passive: true })
|
|
1073
|
-
return () => {
|
|
1074
|
-
floating.removeEventListener('wheel', handleWheel)
|
|
1075
|
-
floating.removeEventListener('touchmove', handleWheel)
|
|
1076
|
-
floating.removeEventListener('touchend', onTouchEnd)
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
}, [open, floatingRef, handleWheel, middlewareType])
|
|
1080
|
-
|
|
1081
|
-
// Ensure the menu remains attached to the reference element when resizing.
|
|
1082
|
-
React.useEffect(() => {
|
|
1083
|
-
window.addEventListener('resize', update)
|
|
1084
|
-
return () => {
|
|
1085
|
-
window.removeEventListener('resize', update)
|
|
1086
|
-
}
|
|
1087
|
-
}, [update])
|
|
1088
|
-
|
|
1089
|
-
// Scroll the active or selected item into view when in `controlledScrolling`
|
|
1090
|
-
// mode (i.e. arrow key nav).
|
|
1091
|
-
React.useLayoutEffect(() => {
|
|
1092
|
-
const floating = floatingRef.current
|
|
1093
|
-
|
|
1094
|
-
if (open && controlledScrolling && floating) {
|
|
1095
|
-
const item =
|
|
1096
|
-
activeIndex != null
|
|
1097
|
-
? listItemsRef.current[activeIndex]
|
|
1098
|
-
: selectedIndex != null
|
|
1099
|
-
? listItemsRef.current[selectedIndex]
|
|
1100
|
-
: null
|
|
1101
|
-
|
|
1102
|
-
if (item && prevActiveIndex != null) {
|
|
1103
|
-
const itemHeight = listItemsRef.current[prevActiveIndex]?.offsetHeight ?? 0
|
|
1104
|
-
|
|
1105
|
-
const floatingHeight = floating.offsetHeight
|
|
1106
|
-
const top = item.offsetTop
|
|
1107
|
-
const bottom = top + itemHeight
|
|
1108
|
-
|
|
1109
|
-
if (top < floating.scrollTop + 20) {
|
|
1110
|
-
const diff = floating.scrollTop - top + 20
|
|
1111
|
-
floating.scrollTop -= diff
|
|
1112
|
-
|
|
1113
|
-
if (activeIndex != selectedIndex && activeIndex != null) {
|
|
1114
|
-
increaseHeight(floating, -diff)
|
|
1115
|
-
}
|
|
1116
|
-
} else if (bottom > floatingHeight + floating.scrollTop - 20) {
|
|
1117
|
-
const diff = bottom - floatingHeight - floating.scrollTop + 20
|
|
1118
|
-
|
|
1119
|
-
floating.scrollTop += diff
|
|
1120
|
-
|
|
1121
|
-
if (activeIndex != selectedIndex && activeIndex != null) {
|
|
1122
|
-
floating.scrollTop -= increaseHeight(floating, diff) ?? 0
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
}, [
|
|
1128
|
-
open,
|
|
1129
|
-
controlledScrolling,
|
|
1130
|
-
prevActiveIndex,
|
|
1131
|
-
activeIndex,
|
|
1132
|
-
selectedIndex,
|
|
1133
|
-
floatingRef,
|
|
1134
|
-
increaseHeight,
|
|
1135
|
-
])
|
|
1136
|
-
|
|
1137
|
-
// Sync the height and the scrollTop values and device whether to use fallback
|
|
1138
|
-
// positioning.
|
|
1139
|
-
React.useLayoutEffect(() => {
|
|
1140
|
-
const floating = refs.floating.current
|
|
1141
|
-
const reference = refs.reference.current
|
|
1142
|
-
|
|
1143
|
-
if (open && floating && reference && floating.offsetHeight < floating.scrollHeight) {
|
|
1144
|
-
const referenceRect = reference.getBoundingClientRect()
|
|
1145
|
-
|
|
1146
|
-
if (middlewareType === 'fallback') {
|
|
1147
|
-
const item = listItemsRef.current[selectedIndex]
|
|
1148
|
-
if (item) {
|
|
1149
|
-
floating.scrollTop = item.offsetTop - floating.clientHeight + referenceRect.height
|
|
1150
|
-
}
|
|
1151
|
-
return
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
floating.scrollTop = middlewareData.size?.y
|
|
1155
|
-
|
|
1156
|
-
const closeToBottom =
|
|
1157
|
-
(visualViewport?.height ?? 0) + getVisualOffsetTop() - referenceRect.bottom <
|
|
1158
|
-
FALLBACK_THRESHOLD
|
|
1159
|
-
const closeToTop = referenceRect.top < FALLBACK_THRESHOLD
|
|
1160
|
-
|
|
1161
|
-
if (floating.offsetHeight < MIN_HEIGHT || closeToTop || closeToBottom) {
|
|
1162
|
-
setMiddlewareType('fallback')
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
}, [
|
|
1166
|
-
open,
|
|
1167
|
-
increaseHeight,
|
|
1168
|
-
selectedIndex,
|
|
1169
|
-
middlewareType,
|
|
1170
|
-
refs.floating,
|
|
1171
|
-
refs.reference,
|
|
1172
|
-
// Always re-run this effect when the position has been computed so the
|
|
1173
|
-
// .scrollTop change works with fresh sizing.
|
|
1174
|
-
middlewareData,
|
|
1175
|
-
])
|
|
1176
|
-
|
|
1177
|
-
React.useLayoutEffect(() => {
|
|
1178
|
-
if (open && selectedIndex != null) {
|
|
1179
|
-
requestAnimationFrame(() => {
|
|
1180
|
-
listItemsRef.current[selectedIndex]?.focus({ preventScroll: true })
|
|
1181
|
-
})
|
|
1182
|
-
}
|
|
1183
|
-
}, [listItemsRef, selectedIndex, open])
|
|
1184
|
-
|
|
1185
|
-
// Wait for scroll position to settle before showing arrows to prevent
|
|
1186
|
-
// interference with pointer events.
|
|
1187
|
-
React.useEffect(() => {
|
|
1188
|
-
const frame = requestAnimationFrame(() => {
|
|
1189
|
-
setShowArrows(open)
|
|
1190
|
-
|
|
1191
|
-
if (!open) {
|
|
1192
|
-
setScrollTop(0)
|
|
1193
|
-
setMiddlewareType('align')
|
|
1194
|
-
setActiveIndex(null)
|
|
1195
|
-
setControlledScrolling(false)
|
|
1196
|
-
}
|
|
1197
|
-
})
|
|
1198
|
-
return () => cancelAnimationFrame(frame)
|
|
1199
|
-
}, [open])
|
|
1200
|
-
|
|
1201
|
-
// We set this to true by default so that events bubble to forms without JS (SSR)
|
|
1202
|
-
// const isFormControl = trigger ? Boolean(trigger.closest('form')) : true
|
|
1203
|
-
// const [bubbleSelect, setBubbleSelect] = React.useState<HTMLSelectElement | null>(null)
|
|
1204
|
-
// const triggerPointerDownPosRef = React.useRef<{ x: number; y: number } | null>(null)
|
|
1205
|
-
|
|
1206
|
-
const [valueNode, setValueNode] = React.useState<HTMLElement | null>(null)
|
|
1207
|
-
const [valueNodeHasChildren, setValueNodeHasChildren] = React.useState(false)
|
|
556
|
+
const id = useId()
|
|
557
|
+
const scopeKey = __scopeSelect ? Object.keys(__scopeSelect)[0] ?? id : id
|
|
1208
558
|
|
|
1209
559
|
return (
|
|
1210
|
-
<
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
setOpen(true)
|
|
1236
|
-
}
|
|
1237
|
-
},
|
|
1238
|
-
})
|
|
1239
|
-
},
|
|
1240
|
-
getFloatingProps(props) {
|
|
1241
|
-
return interactions.getFloatingProps({
|
|
1242
|
-
ref: floating,
|
|
1243
|
-
className: 'Select',
|
|
1244
|
-
...props,
|
|
1245
|
-
style: {
|
|
1246
|
-
position: strategy,
|
|
1247
|
-
top: y ?? '',
|
|
1248
|
-
left: x ?? '',
|
|
1249
|
-
outline: 0,
|
|
1250
|
-
listStyleType: 'none',
|
|
1251
|
-
scrollbarWidth: 'none',
|
|
1252
|
-
userSelect: 'none',
|
|
1253
|
-
...props?.style,
|
|
1254
|
-
},
|
|
1255
|
-
onPointerEnter() {
|
|
1256
|
-
setControlledScrolling(false)
|
|
1257
|
-
},
|
|
1258
|
-
onPointerMove() {
|
|
1259
|
-
setControlledScrolling(false)
|
|
1260
|
-
},
|
|
1261
|
-
onKeyDown() {
|
|
1262
|
-
setControlledScrolling(true)
|
|
1263
|
-
},
|
|
1264
|
-
onScroll(event) {
|
|
1265
|
-
setScrollTop(event.currentTarget.scrollTop)
|
|
1266
|
-
},
|
|
1267
|
-
})
|
|
1268
|
-
},
|
|
1269
|
-
}}
|
|
1270
|
-
floatingContext={context}
|
|
1271
|
-
activeIndex={activeIndex}
|
|
1272
|
-
canScrollDown={!!showDownArrow}
|
|
1273
|
-
canScrollUp={!!showUpArrow}
|
|
1274
|
-
controlledScrolling
|
|
1275
|
-
dataRef={context.dataRef}
|
|
1276
|
-
listRef={listItemsRef}
|
|
1277
|
-
onChange={setValue}
|
|
1278
|
-
selectedIndex={selectedIndex}
|
|
1279
|
-
setActiveIndex={setActiveIndex}
|
|
1280
|
-
setOpen={setOpen}
|
|
1281
|
-
setSelectedIndex={setSelectedIndex}
|
|
1282
|
-
value={value}
|
|
1283
|
-
open={open}
|
|
1284
|
-
>
|
|
1285
|
-
{children}
|
|
1286
|
-
{/* {isFormControl ? (
|
|
1287
|
-
<BubbleSelect
|
|
1288
|
-
ref={setBubbleSelect}
|
|
1289
|
-
aria-hidden
|
|
1290
|
-
tabIndex={-1}
|
|
1291
|
-
name={name}
|
|
1292
|
-
autoComplete={autoComplete}
|
|
560
|
+
<AdaptProvider>
|
|
561
|
+
<SelectProvider
|
|
562
|
+
dir={dir}
|
|
563
|
+
blockSelection={false}
|
|
564
|
+
size={sizeProp}
|
|
565
|
+
fallback={false}
|
|
566
|
+
selectedItem={selectedItem}
|
|
567
|
+
setSelectedItem={setSelectedItem}
|
|
568
|
+
forceUpdate={forceUpdate}
|
|
569
|
+
valueNode={valueNode}
|
|
570
|
+
onValueNodeChange={setValueNode}
|
|
571
|
+
onValueNodeHasChildrenChange={setValueNodeHasChildren}
|
|
572
|
+
valueNodeHasChildren={valueNodeHasChildren}
|
|
573
|
+
scopeKey={scopeKey}
|
|
574
|
+
sheetBreakpoint={sheetBreakpoint}
|
|
575
|
+
scope={__scopeSelect}
|
|
576
|
+
setValueAtIndex={(index, value) => {
|
|
577
|
+
listContentRef.current[index] = value
|
|
578
|
+
}}
|
|
579
|
+
activeIndex={activeIndex}
|
|
580
|
+
onChange={setValue}
|
|
581
|
+
selectedIndex={selectedIndex}
|
|
582
|
+
setActiveIndex={setActiveIndex}
|
|
583
|
+
setOpen={setOpen}
|
|
584
|
+
setSelectedIndex={setSelectedIndex}
|
|
1293
585
|
value={value}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
586
|
+
open={open}
|
|
587
|
+
>
|
|
588
|
+
<SelectSheetController onOpenChange={setOpen} __scopeSelect={__scopeSelect}>
|
|
589
|
+
<SelectImpl
|
|
590
|
+
activeIndexRef={activeIndexRef}
|
|
591
|
+
listContentRef={listContentRef}
|
|
592
|
+
selectedIndexRef={selectedIndexRef}
|
|
593
|
+
{...props}
|
|
594
|
+
open={open}
|
|
595
|
+
value={value}
|
|
596
|
+
>
|
|
597
|
+
{children}
|
|
598
|
+
</SelectImpl>
|
|
599
|
+
</SelectSheetController>
|
|
600
|
+
</SelectProvider>
|
|
601
|
+
</AdaptProvider>
|
|
1299
602
|
)
|
|
1300
603
|
},
|
|
1301
604
|
{
|
|
605
|
+
Adapt,
|
|
1302
606
|
Content: SelectContent,
|
|
1303
607
|
Group: SelectGroup,
|
|
1304
608
|
Icon: SelectIcon,
|
|
@@ -1311,10 +615,10 @@ export const Select = withStaticProperties(
|
|
|
1311
615
|
Trigger: SelectTrigger,
|
|
1312
616
|
Value: SelectValue,
|
|
1313
617
|
Viewport: SelectViewport,
|
|
618
|
+
SheetContents: SelectSheetContents,
|
|
619
|
+
Sheet: ControlledSheet,
|
|
1314
620
|
}
|
|
1315
621
|
)
|
|
1316
622
|
|
|
1317
623
|
// @ts-ignore
|
|
1318
624
|
Select.displayName = SELECT_NAME
|
|
1319
|
-
|
|
1320
|
-
export { createSelectScope }
|