@tamagui/select 2.7.7 → 3.0.0-beta.1093.1
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/Select.cjs +406 -467
- package/dist/cjs/Select.native.cjs +495 -0
- package/dist/cjs/Select.native.js +445 -492
- package/dist/cjs/Select.native.js.map +1 -1
- package/dist/cjs/SelectContent.cjs +79 -79
- package/dist/cjs/SelectContent.native.cjs +29 -0
- package/dist/cjs/SelectContent.native.js +17 -22
- package/dist/cjs/SelectContent.native.js.map +1 -1
- package/dist/cjs/SelectImpl.cjs +305 -320
- package/dist/cjs/SelectImpl.native.cjs +29 -0
- package/dist/cjs/SelectImpl.native.js +16 -24
- package/dist/cjs/SelectImpl.native.js.map +1 -1
- package/dist/cjs/SelectItem.cjs +256 -205
- package/dist/cjs/SelectItem.native.cjs +288 -0
- package/dist/cjs/SelectItem.native.js +264 -213
- package/dist/cjs/SelectItem.native.js.map +1 -1
- package/dist/cjs/SelectItemText.cjs +48 -79
- package/dist/cjs/SelectItemText.native.cjs +73 -0
- package/dist/cjs/SelectItemText.native.js +49 -79
- package/dist/cjs/SelectItemText.native.js.map +1 -1
- package/dist/cjs/SelectScrollButton.cjs +110 -130
- package/dist/cjs/SelectScrollButton.native.cjs +37 -0
- package/dist/cjs/SelectScrollButton.native.js +24 -22
- package/dist/cjs/SelectScrollButton.native.js.map +1 -1
- package/dist/cjs/SelectTrigger.cjs +68 -84
- package/dist/cjs/SelectTrigger.native.cjs +90 -0
- package/dist/cjs/SelectTrigger.native.js +70 -66
- package/dist/cjs/SelectTrigger.native.js.map +1 -1
- package/dist/cjs/SelectViewport.cjs +121 -142
- package/dist/cjs/SelectViewport.native.cjs +72 -0
- package/dist/cjs/SelectViewport.native.js +53 -50
- package/dist/cjs/SelectViewport.native.js.map +1 -1
- package/dist/cjs/constants.cjs +20 -22
- package/dist/cjs/constants.native.cjs +40 -0
- package/dist/cjs/constants.native.js +20 -21
- package/dist/cjs/constants.native.js.map +1 -1
- package/dist/cjs/context.cjs +37 -48
- package/dist/cjs/context.native.cjs +57 -0
- package/dist/cjs/context.native.js +39 -49
- package/dist/cjs/context.native.js.map +1 -1
- package/dist/cjs/index.cjs +14 -11
- package/dist/cjs/index.native.cjs +26 -0
- package/dist/cjs/index.native.js +14 -10
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/selectionController.cjs +343 -0
- package/dist/cjs/selectionController.native.cjs +407 -0
- package/dist/cjs/selectionController.native.js +409 -0
- package/dist/cjs/selectionController.native.js.map +1 -0
- package/dist/cjs/types.cjs +9 -11
- package/dist/cjs/types.native.cjs +18 -0
- package/dist/cjs/types.native.js +9 -10
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/esm/Select.mjs +381 -443
- package/dist/esm/Select.mjs.map +1 -1
- package/dist/esm/Select.native.js +420 -469
- package/dist/esm/Select.native.js.map +1 -1
- package/dist/esm/SelectContent.mjs +67 -61
- package/dist/esm/SelectContent.mjs.map +1 -1
- package/dist/esm/SelectContent.native.js +4 -5
- package/dist/esm/SelectContent.native.js.map +1 -1
- package/dist/esm/SelectImpl.mjs +291 -295
- package/dist/esm/SelectImpl.mjs.map +1 -1
- package/dist/esm/SelectImpl.native.js +5 -8
- package/dist/esm/SelectImpl.native.js.map +1 -1
- package/dist/esm/SelectItem.mjs +240 -181
- package/dist/esm/SelectItem.mjs.map +1 -1
- package/dist/esm/SelectItem.native.js +249 -191
- package/dist/esm/SelectItem.native.js.map +1 -1
- package/dist/esm/SelectItemText.mjs +33 -55
- package/dist/esm/SelectItemText.mjs.map +1 -1
- package/dist/esm/SelectItemText.native.js +34 -56
- package/dist/esm/SelectItemText.native.js.map +1 -1
- package/dist/esm/SelectScrollButton.mjs +95 -107
- package/dist/esm/SelectScrollButton.mjs.map +1 -1
- package/dist/esm/SelectScrollButton.native.js +11 -7
- package/dist/esm/SelectScrollButton.native.js.map +1 -1
- package/dist/esm/SelectTrigger.mjs +56 -58
- package/dist/esm/SelectTrigger.mjs.map +1 -1
- package/dist/esm/SelectTrigger.native.js +54 -44
- package/dist/esm/SelectTrigger.native.js.map +1 -1
- package/dist/esm/SelectViewport.mjs +107 -119
- package/dist/esm/SelectViewport.mjs.map +1 -1
- package/dist/esm/SelectViewport.native.js +44 -39
- package/dist/esm/SelectViewport.native.js.map +1 -1
- package/dist/esm/constants.mjs +1 -0
- package/dist/esm/constants.mjs.map +1 -1
- package/dist/esm/constants.native.js +1 -0
- package/dist/esm/constants.native.js.map +1 -1
- package/dist/esm/context.mjs +20 -28
- package/dist/esm/context.mjs.map +1 -1
- package/dist/esm/context.native.js +23 -31
- package/dist/esm/context.native.js.map +1 -1
- package/dist/esm/index.js +13 -3
- package/dist/esm/index.mjs +13 -3
- package/dist/esm/index.native.js +13 -3
- package/dist/esm/selectionController.mjs +315 -0
- package/dist/esm/selectionController.mjs.map +1 -0
- package/dist/esm/selectionController.native.js +377 -0
- package/dist/esm/selectionController.native.js.map +1 -0
- package/dist/esm/types.mjs +0 -2
- package/dist/esm/types.native.js +0 -2
- package/dist/jsx/Select.mjs +381 -443
- package/dist/jsx/Select.mjs.map +1 -1
- package/dist/jsx/Select.native.cjs +495 -0
- package/dist/jsx/Select.native.js +445 -492
- package/dist/jsx/Select.native.js.map +1 -1
- package/dist/jsx/SelectContent.mjs +67 -61
- package/dist/jsx/SelectContent.mjs.map +1 -1
- package/dist/jsx/SelectContent.native.cjs +29 -0
- package/dist/jsx/SelectContent.native.js +17 -22
- package/dist/jsx/SelectContent.native.js.map +1 -1
- package/dist/jsx/SelectImpl.mjs +291 -295
- package/dist/jsx/SelectImpl.mjs.map +1 -1
- package/dist/jsx/SelectImpl.native.cjs +29 -0
- package/dist/jsx/SelectImpl.native.js +16 -24
- package/dist/jsx/SelectImpl.native.js.map +1 -1
- package/dist/jsx/SelectItem.mjs +240 -181
- package/dist/jsx/SelectItem.mjs.map +1 -1
- package/dist/jsx/SelectItem.native.cjs +288 -0
- package/dist/jsx/SelectItem.native.js +264 -213
- package/dist/jsx/SelectItem.native.js.map +1 -1
- package/dist/jsx/SelectItemText.mjs +33 -55
- package/dist/jsx/SelectItemText.mjs.map +1 -1
- package/dist/jsx/SelectItemText.native.cjs +73 -0
- package/dist/jsx/SelectItemText.native.js +49 -79
- package/dist/jsx/SelectItemText.native.js.map +1 -1
- package/dist/jsx/SelectScrollButton.mjs +95 -107
- package/dist/jsx/SelectScrollButton.mjs.map +1 -1
- package/dist/jsx/SelectScrollButton.native.cjs +37 -0
- package/dist/jsx/SelectScrollButton.native.js +24 -22
- package/dist/jsx/SelectScrollButton.native.js.map +1 -1
- package/dist/jsx/SelectTrigger.mjs +56 -58
- package/dist/jsx/SelectTrigger.mjs.map +1 -1
- package/dist/jsx/SelectTrigger.native.cjs +90 -0
- package/dist/jsx/SelectTrigger.native.js +70 -66
- package/dist/jsx/SelectTrigger.native.js.map +1 -1
- package/dist/jsx/SelectViewport.mjs +107 -119
- package/dist/jsx/SelectViewport.mjs.map +1 -1
- package/dist/jsx/SelectViewport.native.cjs +72 -0
- package/dist/jsx/SelectViewport.native.js +53 -50
- package/dist/jsx/SelectViewport.native.js.map +1 -1
- package/dist/jsx/constants.mjs +1 -0
- package/dist/jsx/constants.mjs.map +1 -1
- package/dist/jsx/constants.native.cjs +40 -0
- package/dist/jsx/constants.native.js +20 -21
- package/dist/jsx/constants.native.js.map +1 -1
- package/dist/jsx/context.mjs +20 -28
- package/dist/jsx/context.mjs.map +1 -1
- package/dist/jsx/context.native.cjs +57 -0
- package/dist/jsx/context.native.js +39 -49
- package/dist/jsx/context.native.js.map +1 -1
- package/dist/jsx/index.js +13 -3
- package/dist/jsx/index.mjs +13 -3
- package/dist/jsx/index.native.cjs +26 -0
- package/dist/jsx/index.native.js +14 -10
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/selectionController.mjs +315 -0
- package/dist/jsx/selectionController.mjs.map +1 -0
- package/dist/jsx/selectionController.native.cjs +407 -0
- package/dist/jsx/selectionController.native.js +409 -0
- package/dist/jsx/selectionController.native.js.map +1 -0
- package/dist/jsx/types.mjs +0 -2
- package/dist/jsx/types.native.cjs +18 -0
- package/dist/jsx/types.native.js +9 -10
- package/dist/jsx/types.native.js.map +1 -1
- package/package.json +31 -30
- package/src/Select.tsx +478 -378
- package/src/SelectContent.tsx +46 -16
- package/src/SelectImpl.native.tsx +0 -8
- package/src/SelectImpl.tsx +149 -160
- package/src/SelectItem.tsx +280 -159
- package/src/SelectItemText.tsx +16 -33
- package/src/SelectScrollButton.native.tsx +13 -4
- package/src/SelectScrollButton.tsx +57 -42
- package/src/SelectTrigger.tsx +77 -53
- package/src/SelectViewport.native.tsx +42 -25
- package/src/SelectViewport.tsx +60 -60
- package/src/context.tsx +6 -2
- package/src/index.tsx +5 -2
- package/src/selectionController.ts +404 -0
- package/src/types.tsx +105 -59
- package/types/Select.d.ts +139 -201
- package/types/Select.d.ts.map +1 -1
- package/types/SelectContent.d.ts +1 -1
- package/types/SelectContent.d.ts.map +1 -1
- package/types/SelectContent.native.d.ts.map +1 -1
- package/types/SelectImpl.d.ts +2 -1
- package/types/SelectImpl.d.ts.map +1 -1
- package/types/SelectImpl.native.d.ts +1 -5
- package/types/SelectImpl.native.d.ts.map +1 -1
- package/types/SelectItem.d.ts +13 -16
- package/types/SelectItem.d.ts.map +1 -1
- package/types/SelectItemText.d.ts +9 -13
- package/types/SelectItemText.d.ts.map +1 -1
- package/types/SelectScrollButton.d.ts +15 -2
- package/types/SelectScrollButton.d.ts.map +1 -1
- package/types/SelectScrollButton.native.d.ts +16 -3
- package/types/SelectScrollButton.native.d.ts.map +1 -1
- package/types/SelectTrigger.d.ts +11 -23
- package/types/SelectTrigger.d.ts.map +1 -1
- package/types/SelectViewport.d.ts +11 -38
- package/types/SelectViewport.d.ts.map +1 -1
- package/types/SelectViewport.native.d.ts +15 -4
- package/types/SelectViewport.native.d.ts.map +1 -1
- package/types/context.d.ts +2 -0
- package/types/context.d.ts.map +1 -1
- package/types/index.d.ts +5 -2
- package/types/index.d.ts.map +1 -1
- package/types/selectionController.d.ts +90 -0
- package/types/selectionController.d.ts.map +1 -0
- package/types/types.d.ts +66 -50
- package/types/types.d.ts.map +1 -1
- package/dist/cjs/BubbleSelect.cjs +0 -50
- package/dist/cjs/BubbleSelect.native.js +0 -30
- package/dist/cjs/BubbleSelect.native.js.map +0 -1
- package/dist/cjs/useSelectBreakpointActive.cjs +0 -32
- package/dist/cjs/useSelectBreakpointActive.native.js +0 -35
- package/dist/cjs/useSelectBreakpointActive.native.js.map +0 -1
- package/dist/esm/BubbleSelect.mjs +0 -27
- package/dist/esm/BubbleSelect.mjs.map +0 -1
- package/dist/esm/BubbleSelect.native.js +0 -4
- package/dist/esm/BubbleSelect.native.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/index.mjs.map +0 -1
- package/dist/esm/index.native.js.map +0 -1
- package/dist/esm/types.mjs.map +0 -1
- package/dist/esm/types.native.js.map +0 -1
- package/dist/esm/useSelectBreakpointActive.mjs +0 -7
- package/dist/esm/useSelectBreakpointActive.mjs.map +0 -1
- package/dist/esm/useSelectBreakpointActive.native.js +0 -7
- package/dist/esm/useSelectBreakpointActive.native.js.map +0 -1
- package/dist/jsx/BubbleSelect.mjs +0 -27
- package/dist/jsx/BubbleSelect.mjs.map +0 -1
- package/dist/jsx/BubbleSelect.native.js +0 -30
- package/dist/jsx/BubbleSelect.native.js.map +0 -1
- package/dist/jsx/index.js.map +0 -1
- package/dist/jsx/index.mjs.map +0 -1
- package/dist/jsx/types.mjs.map +0 -1
- package/dist/jsx/useSelectBreakpointActive.mjs +0 -7
- package/dist/jsx/useSelectBreakpointActive.mjs.map +0 -1
- package/dist/jsx/useSelectBreakpointActive.native.js +0 -35
- package/dist/jsx/useSelectBreakpointActive.native.js.map +0 -1
- package/src/BubbleSelect.tsx +0 -50
- package/src/useSelectBreakpointActive.tsx +0 -7
- package/types/BubbleSelect.d.ts +0 -2
- package/types/BubbleSelect.d.ts.map +0 -1
- package/types/useSelectBreakpointActive.d.ts +0 -3
- package/types/useSelectBreakpointActive.d.ts.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { createStyledHOC, styled, View } from '@tamagui/core'
|
|
1
2
|
import { autoUpdate, offset, useFloatingRaw as useFloating } from '@tamagui/floating'
|
|
2
3
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
3
4
|
import type { TamaguiElement } from '@tamagui/core'
|
|
4
|
-
import {
|
|
5
|
+
import { composeEventHandlers } from '@tamagui/helpers'
|
|
5
6
|
import * as React from 'react'
|
|
6
7
|
import { flushSync } from 'react-dom'
|
|
7
8
|
|
|
@@ -18,20 +19,24 @@ import type {
|
|
|
18
19
|
|
|
19
20
|
const SCROLL_UP_BUTTON_NAME = 'SelectScrollUpButton'
|
|
20
21
|
|
|
21
|
-
export const
|
|
22
|
-
|
|
23
|
-
SelectScrollButtonProps
|
|
24
|
-
>((props: SelectScopedProps<SelectScrollButtonProps>, forwardedRef) => {
|
|
25
|
-
return (
|
|
26
|
-
<SelectScrollButtonImpl
|
|
27
|
-
componentName={SCROLL_UP_BUTTON_NAME}
|
|
28
|
-
{...props}
|
|
29
|
-
dir="up"
|
|
30
|
-
ref={forwardedRef}
|
|
31
|
-
/>
|
|
32
|
-
)
|
|
22
|
+
export const SelectScrollButtonFrame = styled(View, {
|
|
23
|
+
displayName: 'SelectScrollButton',
|
|
33
24
|
})
|
|
34
25
|
|
|
26
|
+
export const SelectScrollUpButton = createStyledHOC(
|
|
27
|
+
SelectScrollButtonFrame,
|
|
28
|
+
(props: SelectScopedProps<SelectScrollButtonProps>, forwardedRef) => {
|
|
29
|
+
return (
|
|
30
|
+
<SelectScrollButtonImpl
|
|
31
|
+
partClassName={`is_${SCROLL_UP_BUTTON_NAME}`}
|
|
32
|
+
{...props}
|
|
33
|
+
dir="up"
|
|
34
|
+
ref={forwardedRef}
|
|
35
|
+
/>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
35
40
|
SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME
|
|
36
41
|
|
|
37
42
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -40,29 +45,30 @@ SelectScrollUpButton.displayName = SCROLL_UP_BUTTON_NAME
|
|
|
40
45
|
|
|
41
46
|
const SCROLL_DOWN_BUTTON_NAME = 'SelectScrollDownButton'
|
|
42
47
|
|
|
43
|
-
export const SelectScrollDownButton =
|
|
44
|
-
|
|
45
|
-
SelectScrollButtonProps
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
export const SelectScrollDownButton = createStyledHOC(
|
|
49
|
+
SelectScrollButtonFrame,
|
|
50
|
+
(props: SelectScopedProps<SelectScrollButtonProps>, forwardedRef) => {
|
|
51
|
+
return (
|
|
52
|
+
<SelectScrollButtonImpl
|
|
53
|
+
partClassName={`is_${SCROLL_DOWN_BUTTON_NAME}`}
|
|
54
|
+
{...props}
|
|
55
|
+
dir="down"
|
|
56
|
+
ref={forwardedRef}
|
|
57
|
+
/>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
)
|
|
56
61
|
|
|
57
62
|
SelectScrollDownButton.displayName = SCROLL_DOWN_BUTTON_NAME
|
|
58
63
|
|
|
59
|
-
type SelectScrollButtonImplElement = TamaguiElement
|
|
60
|
-
|
|
61
64
|
const SelectScrollButtonImpl = React.memo(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const {
|
|
65
|
+
createStyledHOC(
|
|
66
|
+
SelectScrollButtonFrame,
|
|
67
|
+
(props: SelectScrollButtonImplProps, forwardedRef) => {
|
|
68
|
+
const { scope, dir, partClassName, ...scrollIndicatorProps } = props
|
|
69
|
+
const { className, onPointerEnter, onPointerLeave, ...frameProps } =
|
|
70
|
+
scrollIndicatorProps
|
|
71
|
+
const { open, fallback, updateScrollArrows, setInnerOffset, ...context } =
|
|
66
72
|
useSelectContext(scope)
|
|
67
73
|
const floatingRef = context.floatingContext?.refs.floating
|
|
68
74
|
|
|
@@ -81,8 +87,17 @@ const SelectScrollButtonImpl = React.memo(
|
|
|
81
87
|
whileElementsMounted: (...args) => autoUpdate(...args, { animationFrame: true }),
|
|
82
88
|
})
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
const setFloatingRef = React.useCallback(
|
|
91
|
+
(node: TamaguiElement | null) => {
|
|
92
|
+
refs.setFloating(node as HTMLElement | null)
|
|
93
|
+
},
|
|
94
|
+
[refs.setFloating]
|
|
95
|
+
)
|
|
96
|
+
const composedRef = useComposedRefs(forwardedRef, setFloatingRef)
|
|
97
|
+
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
return () => cancelAnimationFrame(frameRef.current)
|
|
100
|
+
}, [])
|
|
86
101
|
|
|
87
102
|
if (!isVisible) {
|
|
88
103
|
return null
|
|
@@ -94,7 +109,7 @@ const SelectScrollButtonImpl = React.memo(
|
|
|
94
109
|
if (fallback) {
|
|
95
110
|
if (floating.current) {
|
|
96
111
|
floating.current.scrollTop -= amount
|
|
97
|
-
|
|
112
|
+
updateScrollArrows!()
|
|
98
113
|
}
|
|
99
114
|
} else {
|
|
100
115
|
flushSync(() => setInnerOffset!((value) => value - amount))
|
|
@@ -102,17 +117,17 @@ const SelectScrollButtonImpl = React.memo(
|
|
|
102
117
|
}
|
|
103
118
|
|
|
104
119
|
return (
|
|
105
|
-
<
|
|
120
|
+
<SelectScrollButtonFrame
|
|
106
121
|
ref={composedRef}
|
|
107
|
-
|
|
122
|
+
className={`${partClassName} ${className || ''}`.trim()}
|
|
108
123
|
aria-hidden
|
|
109
|
-
{...
|
|
124
|
+
{...frameProps}
|
|
110
125
|
zIndex={1000}
|
|
111
126
|
position={strategy}
|
|
112
127
|
left={x || 0}
|
|
113
128
|
top={y || 0}
|
|
114
129
|
width={`calc(${(floatingRef?.current?.offsetWidth ?? 0) - 2}px)`}
|
|
115
|
-
onPointerEnter={() => {
|
|
130
|
+
onPointerEnter={composeEventHandlers(onPointerEnter as any, () => {
|
|
116
131
|
statusRef.current = 'active'
|
|
117
132
|
let prevNow = Date.now()
|
|
118
133
|
|
|
@@ -150,11 +165,11 @@ const SelectScrollButtonImpl = React.memo(
|
|
|
150
165
|
|
|
151
166
|
cancelAnimationFrame(frameRef.current)
|
|
152
167
|
frameRef.current = requestAnimationFrame(frame)
|
|
153
|
-
}}
|
|
154
|
-
onPointerLeave={() => {
|
|
168
|
+
})}
|
|
169
|
+
onPointerLeave={composeEventHandlers(onPointerLeave as any, () => {
|
|
155
170
|
statusRef.current = 'idle'
|
|
156
171
|
cancelAnimationFrame(frameRef.current)
|
|
157
|
-
}}
|
|
172
|
+
})}
|
|
158
173
|
/>
|
|
159
174
|
)
|
|
160
175
|
}
|
package/src/SelectTrigger.tsx
CHANGED
|
@@ -1,87 +1,111 @@
|
|
|
1
1
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
2
|
+
import { isWeb } from '@tamagui/constants'
|
|
3
|
+
import {
|
|
4
|
+
createChangeEventDetails,
|
|
5
|
+
createStyledHOC,
|
|
6
|
+
styled,
|
|
7
|
+
View,
|
|
8
|
+
type GetProps,
|
|
9
|
+
} from '@tamagui/core'
|
|
10
|
+
import { composeEventHandlers } from '@tamagui/helpers'
|
|
5
11
|
import * as React from 'react'
|
|
6
12
|
|
|
7
13
|
import { useSelectContext, useSelectItemParentContext } from './context'
|
|
8
|
-
import type { SelectScopedProps } from './types'
|
|
14
|
+
import type { SelectOpenChangeDetails, SelectScopedProps } from './types'
|
|
9
15
|
|
|
10
|
-
/* -------------------------------------------------------------------------------------------------
|
|
11
|
-
* SelectTrigger
|
|
12
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
13
16
|
const TRIGGER_NAME = 'SelectTrigger'
|
|
14
17
|
|
|
15
|
-
export
|
|
18
|
+
export const SelectTriggerFrame = styled(View, {
|
|
19
|
+
displayName: TRIGGER_NAME,
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
flexDirection: 'row',
|
|
22
|
+
render: <button type="button" />,
|
|
23
|
+
})
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
typeof window !== 'undefined' && process.env.TAMAGUI_TARGET === 'web'
|
|
19
|
-
? window.matchMedia('(pointer:coarse)').matches
|
|
20
|
-
: true
|
|
25
|
+
export type SelectTriggerProps = SelectScopedProps<GetProps<typeof SelectTriggerFrame>>
|
|
21
26
|
|
|
22
|
-
export const SelectTrigger =
|
|
27
|
+
export const SelectTrigger = createStyledHOC(
|
|
28
|
+
SelectTriggerFrame,
|
|
23
29
|
function SelectTrigger(props: SelectTriggerProps, forwardedRef) {
|
|
24
|
-
const { scope, disabled = false,
|
|
25
|
-
|
|
30
|
+
const { scope, disabled = false, ...triggerProps } = props
|
|
26
31
|
const context = useSelectContext(scope)
|
|
27
32
|
const itemParentContext = useSelectItemParentContext(scope)
|
|
28
33
|
const composedRefs = useComposedRefs(
|
|
29
34
|
forwardedRef,
|
|
30
35
|
context.floatingContext?.refs.setReference as any
|
|
31
36
|
)
|
|
32
|
-
|
|
33
|
-
// const labelId = useLabelContext(context.trigger)
|
|
34
|
-
// const labelledBy = ariaLabelledby || labelId
|
|
37
|
+
|
|
35
38
|
if (itemParentContext.shouldRenderWebNative) {
|
|
36
39
|
return null
|
|
37
40
|
}
|
|
38
41
|
|
|
42
|
+
const toggleOpen = (
|
|
43
|
+
event?: any,
|
|
44
|
+
reason: 'trigger-press' | 'keyboard' = 'trigger-press'
|
|
45
|
+
) => {
|
|
46
|
+
if (!disabled) {
|
|
47
|
+
itemParentContext.requestOpenChange(
|
|
48
|
+
!context.open,
|
|
49
|
+
createChangeEventDetails(
|
|
50
|
+
reason,
|
|
51
|
+
event?.nativeEvent || event,
|
|
52
|
+
event?.currentTarget
|
|
53
|
+
) as SelectOpenChangeDetails
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const interactionProps =
|
|
58
|
+
process.env.TAMAGUI_TARGET === 'web' && context.interactions
|
|
59
|
+
? context.interactions.getReferenceProps({
|
|
60
|
+
...triggerProps,
|
|
61
|
+
onMouseDown: composeEventHandlers(triggerProps.onMouseDown as any, () =>
|
|
62
|
+
context.floatingContext?.update?.()
|
|
63
|
+
),
|
|
64
|
+
} as any)
|
|
65
|
+
: {
|
|
66
|
+
...triggerProps,
|
|
67
|
+
...(isWeb
|
|
68
|
+
? {
|
|
69
|
+
onMouseDown: composeEventHandlers(
|
|
70
|
+
triggerProps.onMouseDown as any,
|
|
71
|
+
(event: any) => {
|
|
72
|
+
event.preventDefault()
|
|
73
|
+
toggleOpen(event)
|
|
74
|
+
}
|
|
75
|
+
),
|
|
76
|
+
}
|
|
77
|
+
: {
|
|
78
|
+
onPress: composeEventHandlers(triggerProps.onPress as any, toggleOpen),
|
|
79
|
+
}),
|
|
80
|
+
onKeyDown: composeEventHandlers(
|
|
81
|
+
triggerProps.onKeyDown as any,
|
|
82
|
+
(event: any) => {
|
|
83
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
84
|
+
event.preventDefault()
|
|
85
|
+
toggleOpen(event, 'keyboard')
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
}
|
|
90
|
+
|
|
39
91
|
return (
|
|
40
|
-
<
|
|
41
|
-
componentName={TRIGGER_NAME}
|
|
42
|
-
unstyled={unstyled}
|
|
43
|
-
render="button"
|
|
92
|
+
<SelectTriggerFrame
|
|
44
93
|
type="button"
|
|
45
94
|
id={itemParentContext.id}
|
|
46
|
-
{...(!unstyled && {
|
|
47
|
-
focusVisibleStyle: {
|
|
48
|
-
outlineStyle: 'solid',
|
|
49
|
-
outlineWidth: 2,
|
|
50
|
-
outlineColor: '$outlineColor',
|
|
51
|
-
},
|
|
52
|
-
borderWidth: 1,
|
|
53
|
-
size: itemParentContext.size,
|
|
54
|
-
})}
|
|
55
95
|
role="combobox"
|
|
56
96
|
aria-haspopup="listbox"
|
|
57
97
|
aria-expanded={context.open}
|
|
98
|
+
{...(process.env.TAMAGUI_TARGET === 'web' && {
|
|
99
|
+
'data-state': context.open ? 'open' : 'closed',
|
|
100
|
+
})}
|
|
58
101
|
aria-autocomplete="none"
|
|
102
|
+
accessibilityRole={isWeb ? undefined : 'button'}
|
|
103
|
+
accessibilityState={isWeb ? undefined : { expanded: context.open, disabled }}
|
|
59
104
|
dir={context.dir}
|
|
60
105
|
disabled={disabled}
|
|
61
106
|
data-disabled={disabled ? '' : undefined}
|
|
62
|
-
{...
|
|
107
|
+
{...interactionProps}
|
|
63
108
|
ref={composedRefs}
|
|
64
|
-
{...(process.env.TAMAGUI_TARGET === 'web' && itemParentContext.interactions
|
|
65
|
-
? {
|
|
66
|
-
...itemParentContext.interactions.getReferenceProps(),
|
|
67
|
-
...(isPointerCoarse
|
|
68
|
-
? {
|
|
69
|
-
onPress() {
|
|
70
|
-
itemParentContext.setOpen(!context.open)
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
: {
|
|
74
|
-
onMouseDown() {
|
|
75
|
-
context.floatingContext?.update?.()
|
|
76
|
-
itemParentContext.setOpen(!context.open)
|
|
77
|
-
},
|
|
78
|
-
}),
|
|
79
|
-
}
|
|
80
|
-
: {
|
|
81
|
-
onPress() {
|
|
82
|
-
itemParentContext.setOpen(!context.open)
|
|
83
|
-
},
|
|
84
|
-
})}
|
|
85
109
|
/>
|
|
86
110
|
)
|
|
87
111
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
AdaptPortalContents,
|
|
3
|
+
ProvideAdaptContext,
|
|
4
|
+
useAdaptContext,
|
|
5
|
+
useAdaptIsActive,
|
|
6
|
+
} from '@tamagui/adapt'
|
|
7
|
+
import { createStyledHOC, styled, Theme, useThemeName, View } from '@tamagui/core'
|
|
4
8
|
|
|
5
9
|
import { VIEWPORT_NAME } from './constants'
|
|
6
10
|
import {
|
|
@@ -8,33 +12,46 @@ import {
|
|
|
8
12
|
useSelectContext,
|
|
9
13
|
useSelectItemParentContext,
|
|
10
14
|
} from './context'
|
|
11
|
-
import type { SelectViewportProps } from './types'
|
|
15
|
+
import type { SelectViewportExtraProps, SelectViewportProps } from './types'
|
|
16
|
+
|
|
17
|
+
export const SelectViewportFrame = styled(View, {
|
|
18
|
+
displayName: VIEWPORT_NAME,
|
|
19
|
+
position: 'relative',
|
|
20
|
+
})
|
|
12
21
|
|
|
13
|
-
export const SelectViewport = (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
export const SelectViewport = createStyledHOC(
|
|
23
|
+
SelectViewportFrame,
|
|
24
|
+
function SelectViewport(props: SelectViewportProps, forwardedRef) {
|
|
25
|
+
const { scope, children, disableScroll: _disableScroll, ...viewportProps } = props
|
|
26
|
+
const context = useSelectContext(scope)
|
|
27
|
+
const itemParentContext = useSelectItemParentContext(scope)
|
|
28
|
+
const themeName = useThemeName()
|
|
29
|
+
const adaptContext = useAdaptContext(context.adaptScope)
|
|
30
|
+
const isAdapted = useAdaptIsActive(context.adaptScope)
|
|
18
31
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
const contents = (
|
|
33
|
+
<Theme name={themeName}>
|
|
34
|
+
<ForwardSelectContext itemContext={itemParentContext} context={context}>
|
|
35
|
+
<ProvideAdaptContext {...adaptContext}>
|
|
36
|
+
<SelectViewportFrame {...viewportProps} ref={forwardedRef}>
|
|
37
|
+
{children}
|
|
38
|
+
</SelectViewportFrame>
|
|
39
|
+
</ProvideAdaptContext>
|
|
40
|
+
</ForwardSelectContext>
|
|
41
|
+
</Theme>
|
|
42
|
+
)
|
|
28
43
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return
|
|
44
|
+
if (!context.open) {
|
|
45
|
+
if (context.lazyMount && context.renderValue) return null
|
|
46
|
+
return <SelectViewportFrame display="none">{contents}</SelectViewportFrame>
|
|
32
47
|
}
|
|
33
48
|
|
|
34
|
-
return
|
|
49
|
+
return isAdapted ? (
|
|
50
|
+
<AdaptPortalContents scope={context.adaptScope}>{contents}</AdaptPortalContents>
|
|
51
|
+
) : (
|
|
52
|
+
contents
|
|
53
|
+
)
|
|
35
54
|
}
|
|
36
|
-
|
|
37
|
-
return <AdaptPortalContents scope={context.adaptScope}>{contents}</AdaptPortalContents>
|
|
38
|
-
}
|
|
55
|
+
)
|
|
39
56
|
|
|
40
57
|
SelectViewport.displayName = VIEWPORT_NAME
|
package/src/SelectViewport.tsx
CHANGED
|
@@ -2,9 +2,9 @@ import { AdaptPortalContents, useAdaptIsActive } from '@tamagui/adapt'
|
|
|
2
2
|
import { AnimatePresence } from '@tamagui/animate-presence'
|
|
3
3
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
4
4
|
import { isWeb, useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
5
|
-
import { styled } from '@tamagui/core'
|
|
5
|
+
import { createStyledHOC, styled, View } from '@tamagui/core'
|
|
6
6
|
import { needsPortalRepropagation } from '@tamagui/portal'
|
|
7
|
-
import {
|
|
7
|
+
import { YStack } from '@tamagui/stacks'
|
|
8
8
|
import { startTransition } from '@tamagui/start-transition'
|
|
9
9
|
import * as React from 'react'
|
|
10
10
|
import { VIEWPORT_NAME } from './constants'
|
|
@@ -13,51 +13,29 @@ import {
|
|
|
13
13
|
useSelectContext,
|
|
14
14
|
useSelectItemParentContext,
|
|
15
15
|
} from './context'
|
|
16
|
-
import type {
|
|
16
|
+
import type { SelectViewportProps } from './types'
|
|
17
|
+
import { getSelectListboxProps } from './selectionController'
|
|
17
18
|
|
|
18
19
|
/* -------------------------------------------------------------------------------------------------
|
|
19
20
|
* SelectViewport
|
|
20
21
|
* -----------------------------------------------------------------------------------------------*/
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
name: VIEWPORT_NAME,
|
|
26
|
-
|
|
27
|
-
variants: {
|
|
28
|
-
unstyled: {
|
|
29
|
-
false: {
|
|
30
|
-
size: '$2',
|
|
31
|
-
backgroundColor: '$background',
|
|
32
|
-
elevate: true,
|
|
33
|
-
bordered: true,
|
|
34
|
-
userSelect: 'none',
|
|
35
|
-
outlineWidth: 0,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
size: {
|
|
40
|
-
'...size': (val, { tokens }) => {
|
|
41
|
-
return {
|
|
42
|
-
borderRadius: tokens.radius[val] ?? val,
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
} as const,
|
|
47
|
-
|
|
48
|
-
defaultVariants: {
|
|
49
|
-
unstyled: process.env.TAMAGUI_HEADLESS === '1',
|
|
50
|
-
},
|
|
23
|
+
export const SelectViewportFrame = styled(View, {
|
|
24
|
+
displayName: VIEWPORT_NAME,
|
|
25
|
+
position: 'relative',
|
|
51
26
|
})
|
|
52
27
|
|
|
53
28
|
const needsRepropagation = needsPortalRepropagation()
|
|
54
29
|
|
|
55
|
-
export const SelectViewport =
|
|
56
|
-
|
|
30
|
+
export const SelectViewport = createStyledHOC(
|
|
31
|
+
SelectViewportFrame,
|
|
32
|
+
function SelectViewport(props: SelectViewportProps, forwardedRef) {
|
|
57
33
|
const { scope, children, disableScroll, ...viewportProps } = props
|
|
58
34
|
const context = useSelectContext(scope)
|
|
59
35
|
const itemContext = useSelectItemParentContext(scope)
|
|
60
36
|
const isAdapted = useAdaptIsActive(context.adaptScope)
|
|
37
|
+
const viewportRef = React.useRef<any>(null)
|
|
38
|
+
const registeredItemCount = itemContext.registry.getItems().length
|
|
61
39
|
|
|
62
40
|
// lazy mount: defer mounting children until first open using startTransition
|
|
63
41
|
const [lazyMounted, setLazyMounted] = React.useState(context.lazyMount ? false : true)
|
|
@@ -71,9 +49,25 @@ export const SelectViewport = SelectViewportFrame.styleable<SelectViewportExtraP
|
|
|
71
49
|
})
|
|
72
50
|
}, [context.lazyMount, context.open, lazyMounted])
|
|
73
51
|
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
if (!isWeb || !isAdapted || !context.open) return
|
|
54
|
+
const frame = requestAnimationFrame(() => {
|
|
55
|
+
const index =
|
|
56
|
+
context.activeIndexRef.current ?? itemContext.registry.firstEnabledIndex()
|
|
57
|
+
const activeItem =
|
|
58
|
+
(viewportRef.current?.querySelector(
|
|
59
|
+
'[role="option"][tabindex="0"]'
|
|
60
|
+
) as HTMLElement | null) ??
|
|
61
|
+
(index >= 0 ? itemContext.listRef?.current[index] : null)
|
|
62
|
+
activeItem?.focus()
|
|
63
|
+
})
|
|
64
|
+
return () => cancelAnimationFrame(frame)
|
|
65
|
+
}, [context.open, isAdapted, registeredItemCount])
|
|
66
|
+
|
|
74
67
|
const composedRefs = useComposedRefs(
|
|
75
|
-
// @ts-ignore
|
|
68
|
+
// @ts-ignore react 19 ref type mismatch
|
|
76
69
|
forwardedRef,
|
|
70
|
+
viewportRef,
|
|
77
71
|
context.floatingContext?.refs.setFloating as any
|
|
78
72
|
)
|
|
79
73
|
|
|
@@ -85,18 +79,28 @@ export const SelectViewport = SelectViewportFrame.styleable<SelectViewportExtraP
|
|
|
85
79
|
|
|
86
80
|
// after lazy children mount, force floating-ui to recompute so inner middleware
|
|
87
81
|
// can position using the now-present list items
|
|
88
|
-
|
|
82
|
+
React.useEffect(() => {
|
|
89
83
|
if (context.lazyMount && lazyMounted && context.open && context.update) {
|
|
90
|
-
context.update
|
|
84
|
+
const frame = requestAnimationFrame(context.update)
|
|
85
|
+
return () => cancelAnimationFrame(frame)
|
|
91
86
|
}
|
|
92
|
-
}, [lazyMounted])
|
|
87
|
+
}, [lazyMounted, registeredItemCount])
|
|
93
88
|
|
|
94
89
|
if (itemContext.shouldRenderWebNative) {
|
|
95
90
|
return <YStack position="relative">{children}</YStack>
|
|
96
91
|
}
|
|
97
92
|
|
|
98
93
|
if (isAdapted || !isWeb) {
|
|
99
|
-
let content =
|
|
94
|
+
let content = (
|
|
95
|
+
<SelectViewportFrame
|
|
96
|
+
{...viewportProps}
|
|
97
|
+
{...(isWeb ? (getSelectListboxProps(itemContext.mode) as any) : {})}
|
|
98
|
+
data-select-viewport=""
|
|
99
|
+
ref={composedRefs}
|
|
100
|
+
>
|
|
101
|
+
{lazyMounted ? children : null}
|
|
102
|
+
</SelectViewportFrame>
|
|
103
|
+
)
|
|
100
104
|
|
|
101
105
|
if (needsRepropagation) {
|
|
102
106
|
content = (
|
|
@@ -111,44 +115,40 @@ export const SelectViewport = SelectViewportFrame.styleable<SelectViewportExtraP
|
|
|
111
115
|
)
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
if (!
|
|
115
|
-
if (process.env.NODE_ENV === 'development') {
|
|
116
|
-
console.warn(`No interactions provided to Select, potentially missing Adapt`)
|
|
117
|
-
}
|
|
118
|
-
|
|
118
|
+
if (!context.interactions) {
|
|
119
119
|
return null
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
const
|
|
123
|
-
style,
|
|
124
|
-
// remove this, it was set to "Select" always
|
|
125
|
-
className,
|
|
126
|
-
...floatingProps
|
|
127
|
-
} = itemContext.interactions.getFloatingProps()
|
|
122
|
+
const floatingProps = context.interactions.getFloatingProps()
|
|
128
123
|
|
|
129
124
|
// FloatingFocusManager removed — SelectContent already wraps with FocusScope
|
|
130
125
|
// that handles focus trapping and auto-focus
|
|
131
126
|
return (
|
|
132
127
|
<>
|
|
133
|
-
{!disableScroll &&
|
|
128
|
+
{!disableScroll && (
|
|
134
129
|
<style
|
|
135
130
|
dangerouslySetInnerHTML={{
|
|
136
131
|
__html: selectViewportCSS,
|
|
137
132
|
}}
|
|
138
133
|
/>
|
|
139
134
|
)}
|
|
140
|
-
|
|
135
|
+
{/* every styled item reads the presence context, and the default
|
|
136
|
+
(layout-affecting) presence hands out a new context per render, so
|
|
137
|
+
each viewport render would re-render the whole list */}
|
|
138
|
+
<AnimatePresence presenceAffectsLayout={false}>
|
|
141
139
|
{context.open ? (
|
|
142
140
|
<SelectViewportFrame
|
|
143
141
|
key="select-viewport"
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
data-select-viewport=""
|
|
143
|
+
{...(isWeb && {
|
|
144
|
+
'data-state': context.open ? 'open' : 'closed',
|
|
145
|
+
})}
|
|
146
146
|
{...viewportProps}
|
|
147
|
-
{...
|
|
147
|
+
{...context.floatingPosition}
|
|
148
|
+
outlineWidth={0}
|
|
148
149
|
{...floatingProps}
|
|
149
|
-
{...(
|
|
150
|
-
|
|
151
|
-
})}
|
|
150
|
+
{...getSelectListboxProps(itemContext.mode)}
|
|
151
|
+
overflowY={disableScroll ? undefined : 'auto'}
|
|
152
152
|
ref={composedRefs}
|
|
153
153
|
>
|
|
154
154
|
{lazyMounted ? children : null}
|
|
@@ -167,13 +167,13 @@ export const SelectViewport = SelectViewportFrame.styleable<SelectViewportExtraP
|
|
|
167
167
|
)
|
|
168
168
|
|
|
169
169
|
const selectViewportCSS = `
|
|
170
|
-
|
|
170
|
+
[data-select-viewport] {
|
|
171
171
|
scrollbar-width: none;
|
|
172
172
|
-webkit-overflow-scrolling: touch;
|
|
173
173
|
overscroll-behavior: contain;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
[data-select-viewport]::-webkit-scrollbar{
|
|
177
177
|
display:none
|
|
178
178
|
}
|
|
179
179
|
`
|
package/src/context.tsx
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { createStyledContext } from '@tamagui/core'
|
|
2
2
|
import { getPortal } from '@tamagui/native'
|
|
3
|
-
import { createContext } from 'react'
|
|
3
|
+
import { createContext, type ComponentType } from 'react'
|
|
4
4
|
import type { SelectContextValue, SelectItemParentContextValue } from './types'
|
|
5
5
|
|
|
6
6
|
// zIndex flows from root Select prop to SelectContent portal
|
|
7
7
|
export const SelectZIndexContext = createContext<number | undefined>(undefined)
|
|
8
8
|
|
|
9
|
+
// the behavior surface renders a raw native select. the styled tamagui surface
|
|
10
|
+
// supplies its native-select skin through this slot.
|
|
11
|
+
export const SelectNativeComponentContext = createContext<ComponentType<any> | null>(null)
|
|
12
|
+
|
|
9
13
|
export const { Provider: SelectProvider, useStyledContext: useSelectContext } =
|
|
10
14
|
createStyledContext<SelectContextValue>(null as any, 'Select')
|
|
11
15
|
|
|
@@ -34,7 +38,7 @@ export const ForwardSelectContext = ({
|
|
|
34
38
|
|
|
35
39
|
// fall back to context forwarding for legacy portal implementations
|
|
36
40
|
return (
|
|
37
|
-
<SelectProvider
|
|
41
|
+
<SelectProvider scope={context.scopeName} {...context}>
|
|
38
42
|
<SelectItemParentProvider scope={context.scopeName} {...itemContext}>
|
|
39
43
|
{children}
|
|
40
44
|
</SelectItemParentProvider>
|
package/src/index.tsx
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export * from './Select'
|
|
2
|
+
export * from './SelectItem'
|
|
3
|
+
export * from './SelectItemText'
|
|
4
|
+
export * from './SelectScrollButton'
|
|
5
|
+
export * from './SelectTrigger'
|
|
6
|
+
export * from './SelectViewport'
|
|
2
7
|
export type * from './types'
|
|
3
8
|
export * from './context'
|
|
4
|
-
export type { SelectItemProps, SelectItemExtraProps } from './SelectItem'
|
|
5
|
-
export type { SelectTriggerProps } from './SelectTrigger'
|