@tamagui/switch 2.7.7 → 3.0.0-beta.643.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/StyledContext.cjs +19 -23
- package/dist/cjs/StyledContext.native.cjs +33 -0
- package/dist/cjs/StyledContext.native.js +19 -22
- package/dist/cjs/StyledContext.native.js.map +1 -1
- package/dist/cjs/Switch.cjs +140 -86
- package/dist/cjs/Switch.native.cjs +163 -0
- package/dist/cjs/Switch.native.js +147 -90
- package/dist/cjs/Switch.native.js.map +1 -1
- package/dist/cjs/index.cjs +14 -25
- package/dist/cjs/index.native.cjs +31 -0
- package/dist/cjs/index.native.js +15 -25
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/types.cjs +10 -11
- package/dist/cjs/types.native.cjs +19 -0
- package/dist/cjs/types.native.js +10 -10
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/cjs/useSwitchNative.cjs +16 -19
- package/dist/cjs/useSwitchNative.native.cjs +65 -0
- package/dist/cjs/useSwitchNative.native.js +44 -54
- package/dist/cjs/useSwitchNative.native.js.map +1 -1
- package/dist/esm/StyledContext.mjs +6 -5
- package/dist/esm/StyledContext.mjs.map +1 -1
- package/dist/esm/StyledContext.native.js +6 -5
- package/dist/esm/StyledContext.native.js.map +1 -1
- package/dist/esm/Switch.mjs +119 -71
- package/dist/esm/Switch.mjs.map +1 -1
- package/dist/esm/Switch.native.js +126 -76
- package/dist/esm/Switch.native.js.map +1 -1
- package/dist/esm/index.js +8 -12
- package/dist/esm/index.mjs +8 -12
- package/dist/esm/index.native.js +8 -12
- package/dist/esm/types.mjs +0 -2
- package/dist/esm/types.native.js +0 -2
- package/dist/esm/useSwitchNative.mjs +2 -1
- package/dist/esm/useSwitchNative.mjs.map +1 -1
- package/dist/esm/useSwitchNative.native.js +30 -31
- package/dist/esm/useSwitchNative.native.js.map +1 -1
- package/dist/jsx/StyledContext.mjs +6 -5
- package/dist/jsx/StyledContext.mjs.map +1 -1
- package/dist/jsx/StyledContext.native.cjs +33 -0
- package/dist/jsx/StyledContext.native.js +19 -22
- package/dist/jsx/StyledContext.native.js.map +1 -1
- package/dist/jsx/Switch.mjs +119 -71
- package/dist/jsx/Switch.mjs.map +1 -1
- package/dist/jsx/Switch.native.cjs +163 -0
- package/dist/jsx/Switch.native.js +147 -90
- package/dist/jsx/Switch.native.js.map +1 -1
- package/dist/jsx/index.js +8 -12
- package/dist/jsx/index.mjs +8 -12
- package/dist/jsx/index.native.cjs +31 -0
- package/dist/jsx/index.native.js +15 -25
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/types.mjs +0 -2
- package/dist/jsx/types.native.cjs +19 -0
- package/dist/jsx/types.native.js +10 -10
- package/dist/jsx/types.native.js.map +1 -1
- package/dist/jsx/useSwitchNative.mjs +2 -1
- package/dist/jsx/useSwitchNative.mjs.map +1 -1
- package/dist/jsx/useSwitchNative.native.cjs +65 -0
- package/dist/jsx/useSwitchNative.native.js +44 -54
- package/dist/jsx/useSwitchNative.native.js.map +1 -1
- package/package.json +7 -14
- package/src/StyledContext.tsx +1 -3
- package/src/Switch.tsx +190 -89
- package/src/index.ts +0 -20
- package/src/types.ts +3 -5
- package/types/StyledContext.d.ts +2 -3
- package/types/StyledContext.d.ts.map +1 -1
- package/types/Switch.d.ts +209 -37
- package/types/Switch.d.ts.map +1 -1
- package/types/index.d.ts +0 -146
- package/types/index.d.ts.map +1 -1
- package/types/types.d.ts +3 -4
- package/types/types.d.ts.map +1 -1
- package/dist/cjs/createSwitch.cjs +0 -186
- package/dist/cjs/createSwitch.native.js +0 -194
- package/dist/cjs/createSwitch.native.js.map +0 -1
- package/dist/esm/createSwitch.mjs +0 -150
- package/dist/esm/createSwitch.mjs.map +0 -1
- package/dist/esm/createSwitch.native.js +0 -155
- package/dist/esm/createSwitch.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/jsx/createSwitch.mjs +0 -150
- package/dist/jsx/createSwitch.mjs.map +0 -1
- package/dist/jsx/createSwitch.native.js +0 -194
- package/dist/jsx/createSwitch.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/src/Switch.draggable-tmp +0 -340
- package/src/createSwitch.tsx +0 -201
- package/types/createSwitch.d.ts +0 -141
- package/types/createSwitch.d.ts.map +0 -1
package/src/Switch.draggable-tmp
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
// via radix
|
|
2
|
-
// https://github.com/radix-ui/primitives/blob/main/packages/react/switch/src/Switch.tsx
|
|
3
|
-
|
|
4
|
-
import { usePrevious } from '@tamagui/use-previous'
|
|
5
|
-
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
6
|
-
import {
|
|
7
|
-
GetProps,
|
|
8
|
-
SizeTokens,
|
|
9
|
-
calc,
|
|
10
|
-
getSize,
|
|
11
|
-
getVariableValue,
|
|
12
|
-
isWeb,
|
|
13
|
-
styled,
|
|
14
|
-
withStaticProperties,
|
|
15
|
-
} from '@tamagui/core'
|
|
16
|
-
import { ScopedProps, createContextScope } from '@tamagui/create-context'
|
|
17
|
-
import { registerFocusable } from '@tamagui/focusable'
|
|
18
|
-
import { useLabelContext } from '@tamagui/label'
|
|
19
|
-
import { ThemeableStack, XStack } from '@tamagui/stacks'
|
|
20
|
-
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
21
|
-
import * as React from 'react'
|
|
22
|
-
import { Animated, LayoutRectangle, PanResponder, View } from 'react-native'
|
|
23
|
-
|
|
24
|
-
const SWITCH_NAME = 'Switch'
|
|
25
|
-
|
|
26
|
-
// TODO make customizable
|
|
27
|
-
const getSwitchHeight = (val: SizeTokens) => Math.round(getVariableValue(getSize(val)) * 0.65)
|
|
28
|
-
const getSwitchWidth = (val: SizeTokens) => getSwitchHeight(val) * 2
|
|
29
|
-
|
|
30
|
-
const scopeContexts = createContextScope(SWITCH_NAME)
|
|
31
|
-
const [createSwitchContext] = scopeContexts
|
|
32
|
-
export const createSwitchScope = scopeContexts[1]
|
|
33
|
-
|
|
34
|
-
const [SwitchProvider, useSwitchContext] = createSwitchContext<{
|
|
35
|
-
checked: boolean
|
|
36
|
-
disabled?: boolean
|
|
37
|
-
size: SizeTokens
|
|
38
|
-
frameLayout?: LayoutRectangle
|
|
39
|
-
}>(SWITCH_NAME)
|
|
40
|
-
|
|
41
|
-
/* -------------------------------------------------------------------------------------------------
|
|
42
|
-
* SwitchThumb
|
|
43
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
44
|
-
|
|
45
|
-
const THUMB_NAME = 'SwitchThumb'
|
|
46
|
-
|
|
47
|
-
export const SwitchThumbFrame = styled(ThemeableStack, {
|
|
48
|
-
name: 'SwitchThumb',
|
|
49
|
-
backgroundColor: '$background',
|
|
50
|
-
borderRadius: 1000,
|
|
51
|
-
|
|
52
|
-
variants: {
|
|
53
|
-
size: {
|
|
54
|
-
'...size': (val) => ({
|
|
55
|
-
height: getSwitchHeight(val),
|
|
56
|
-
width: getSwitchHeight(val),
|
|
57
|
-
}),
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
defaultVariants: {
|
|
62
|
-
size: '$4',
|
|
63
|
-
},
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
export type SwitchThumbProps = GetProps<typeof SwitchThumbFrame>
|
|
67
|
-
|
|
68
|
-
export const SwitchThumb = SwitchThumbFrame.extractable(
|
|
69
|
-
React.forwardRef<React.ElementRef<'span'>, SwitchThumbProps>(
|
|
70
|
-
(props: ScopedProps<SwitchThumbProps, 'Switch'>, forwardedRef) => {
|
|
71
|
-
const { __scopeSwitch, ...thumbProps } = props
|
|
72
|
-
const { size, disabled, checked, frameLayout } = useSwitchContext(THUMB_NAME, __scopeSwitch)
|
|
73
|
-
const [position] = React.useState(new Animated.ValueXY(0))
|
|
74
|
-
const [thumbWidth, setThumbWidth] = React.useState(0)
|
|
75
|
-
const responder = React.useMemo(() => {
|
|
76
|
-
return PanResponder.create({
|
|
77
|
-
onStartShouldSetPanResponder: () => true,
|
|
78
|
-
onPanResponderMove: Animated.event(
|
|
79
|
-
[
|
|
80
|
-
null,
|
|
81
|
-
{
|
|
82
|
-
dx: position.x,
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
{
|
|
86
|
-
useNativeDriver: false,
|
|
87
|
-
}
|
|
88
|
-
),
|
|
89
|
-
})
|
|
90
|
-
}, [])
|
|
91
|
-
|
|
92
|
-
React.useEffect(() => {
|
|
93
|
-
position.addListener((val) => {
|
|
94
|
-
console.log('x', val)
|
|
95
|
-
})
|
|
96
|
-
}, [])
|
|
97
|
-
|
|
98
|
-
const maxMove =
|
|
99
|
-
getVariableValue(getSwitchWidth(size)) - getVariableValue(getSwitchHeight(size))
|
|
100
|
-
|
|
101
|
-
const maxDrag = (frameLayout?.width || 0) - thumbWidth
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
<Animated.View
|
|
105
|
-
style={[
|
|
106
|
-
{
|
|
107
|
-
transform: [{ translateX: position.x }],
|
|
108
|
-
},
|
|
109
|
-
]}
|
|
110
|
-
>
|
|
111
|
-
<SwitchThumbFrame
|
|
112
|
-
size={size}
|
|
113
|
-
data-state={getState(checked)}
|
|
114
|
-
data-disabled={disabled ? '' : undefined}
|
|
115
|
-
{...responder.panHandlers}
|
|
116
|
-
{...thumbProps}
|
|
117
|
-
onLayout={({ nativeEvent }) => {
|
|
118
|
-
console.log('thumb', nativeEvent.layout)
|
|
119
|
-
setThumbWidth(nativeEvent.layout.width)
|
|
120
|
-
}}
|
|
121
|
-
x={checked ? maxMove : 0}
|
|
122
|
-
ref={forwardedRef}
|
|
123
|
-
/>
|
|
124
|
-
</Animated.View>
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
)
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
SwitchThumb.displayName = THUMB_NAME
|
|
131
|
-
|
|
132
|
-
/* -------------------------------------------------------------------------------------------------
|
|
133
|
-
* Switch
|
|
134
|
-
* -----------------------------------------------------------------------------------------------*/
|
|
135
|
-
|
|
136
|
-
export const SwitchFrame = styled(XStack, {
|
|
137
|
-
name: 'Switch',
|
|
138
|
-
tag: 'button',
|
|
139
|
-
borderRadius: 1000,
|
|
140
|
-
borderWidth: 2,
|
|
141
|
-
borderColor: 'transparent',
|
|
142
|
-
backgroundColor: '$background',
|
|
143
|
-
|
|
144
|
-
focusStyle: {
|
|
145
|
-
borderColor: '$borderColorFocus',
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
variants: {
|
|
149
|
-
size: {
|
|
150
|
-
'...size': (val) => {
|
|
151
|
-
const height = calc(getSwitchHeight(val), '+', 4)
|
|
152
|
-
const width = calc(getSwitchWidth(val), '+', 4)
|
|
153
|
-
return {
|
|
154
|
-
height,
|
|
155
|
-
minHeight: height,
|
|
156
|
-
width,
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
defaultVariants: {
|
|
163
|
-
size: '$4',
|
|
164
|
-
},
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
type SwitchButtonProps = GetProps<typeof SwitchFrame>
|
|
168
|
-
|
|
169
|
-
export type SwitchProps = SwitchButtonProps & {
|
|
170
|
-
labeledBy?: string
|
|
171
|
-
name?: string
|
|
172
|
-
value?: string
|
|
173
|
-
checked?: boolean
|
|
174
|
-
defaultChecked?: boolean
|
|
175
|
-
required?: boolean
|
|
176
|
-
onCheckedChange?(checked: boolean): void
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export const Switch = withStaticProperties(
|
|
180
|
-
SwitchFrame.extractable(
|
|
181
|
-
React.forwardRef<HTMLButtonElement | View, SwitchProps>(
|
|
182
|
-
(props: ScopedProps<SwitchProps, 'Switch'>, forwardedRef) => {
|
|
183
|
-
const {
|
|
184
|
-
__scopeSwitch,
|
|
185
|
-
labeledBy: ariaLabelledby,
|
|
186
|
-
name,
|
|
187
|
-
checked: checkedProp,
|
|
188
|
-
defaultChecked,
|
|
189
|
-
required,
|
|
190
|
-
disabled,
|
|
191
|
-
value = 'on',
|
|
192
|
-
onCheckedChange,
|
|
193
|
-
size = '$4',
|
|
194
|
-
...switchProps
|
|
195
|
-
} = props
|
|
196
|
-
const [button, setButton] = React.useState<HTMLButtonElement | null>(null)
|
|
197
|
-
const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node as any))
|
|
198
|
-
const labelId = useLabelContext(button)
|
|
199
|
-
const labelledBy = ariaLabelledby || labelId
|
|
200
|
-
const hasConsumerStoppedPropagationRef = React.useRef(false)
|
|
201
|
-
const [frameLayout, setFrameLayout] = React.useState<LayoutRectangle>()
|
|
202
|
-
// We set this to true by default so that events bubble to forms without JS (SSR)
|
|
203
|
-
const isFormControl = isWeb ? (button ? Boolean(button.closest('form')) : true) : false
|
|
204
|
-
const [checked = false, setChecked] = useControllableState({
|
|
205
|
-
prop: checkedProp,
|
|
206
|
-
defaultProp: defaultChecked || false,
|
|
207
|
-
onChange: onCheckedChange,
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
if (!isWeb) {
|
|
211
|
-
|
|
212
|
-
React.useEffect(() => {
|
|
213
|
-
if (!props.id) return
|
|
214
|
-
return registerFocusable(props.id, {
|
|
215
|
-
focus: () => {
|
|
216
|
-
setChecked((x) => !x)
|
|
217
|
-
},
|
|
218
|
-
})
|
|
219
|
-
}, [props.id, setChecked])
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return (
|
|
223
|
-
<SwitchProvider
|
|
224
|
-
scope={__scopeSwitch}
|
|
225
|
-
checked={checked}
|
|
226
|
-
disabled={disabled}
|
|
227
|
-
size={size}
|
|
228
|
-
frameLayout={frameLayout}
|
|
229
|
-
>
|
|
230
|
-
<SwitchFrame
|
|
231
|
-
size={size}
|
|
232
|
-
onLayout={({ nativeEvent }) => {
|
|
233
|
-
console.log('?', nativeEvent.layout)
|
|
234
|
-
setFrameLayout(nativeEvent.layout)
|
|
235
|
-
}}
|
|
236
|
-
// @ts-ignore
|
|
237
|
-
role="switch"
|
|
238
|
-
aria-checked={checked}
|
|
239
|
-
aria-labelledby={labelledBy}
|
|
240
|
-
aria-required={required}
|
|
241
|
-
data-state={getState(checked)}
|
|
242
|
-
data-disabled={disabled ? '' : undefined}
|
|
243
|
-
disabled={disabled}
|
|
244
|
-
theme={checked ? 'active' : null}
|
|
245
|
-
themeShallow
|
|
246
|
-
// @ts-ignore
|
|
247
|
-
tabIndex={disabled ? undefined : 0}
|
|
248
|
-
// @ts-ignore
|
|
249
|
-
value={value}
|
|
250
|
-
{...switchProps}
|
|
251
|
-
ref={composedRefs}
|
|
252
|
-
onPress={(event) => {
|
|
253
|
-
props.onPress?.(event)
|
|
254
|
-
setChecked((prevChecked) => !prevChecked)
|
|
255
|
-
if (isWeb && isFormControl) {
|
|
256
|
-
hasConsumerStoppedPropagationRef.current = event.isPropagationStopped()
|
|
257
|
-
// if switch is in a form, stop propagation from the button so that we only propagate
|
|
258
|
-
// one click event (from the input). We propagate changes from an input so that native
|
|
259
|
-
// form validation works and form events reflect switch updates.
|
|
260
|
-
if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation()
|
|
261
|
-
}
|
|
262
|
-
}}
|
|
263
|
-
/>
|
|
264
|
-
{isWeb && isFormControl && (
|
|
265
|
-
<BubbleInput
|
|
266
|
-
control={button}
|
|
267
|
-
bubbles={!hasConsumerStoppedPropagationRef.current}
|
|
268
|
-
name={name}
|
|
269
|
-
value={value}
|
|
270
|
-
checked={checked}
|
|
271
|
-
required={required}
|
|
272
|
-
disabled={disabled}
|
|
273
|
-
// We transform because the input is absolutely positioned but we have
|
|
274
|
-
// rendered it **after** the button. This pulls it back to sit on top
|
|
275
|
-
// of the button.
|
|
276
|
-
style={{ transform: 'translateX(-100%)' }}
|
|
277
|
-
/>
|
|
278
|
-
)}
|
|
279
|
-
</SwitchProvider>
|
|
280
|
-
)
|
|
281
|
-
}
|
|
282
|
-
)
|
|
283
|
-
),
|
|
284
|
-
{
|
|
285
|
-
Thumb: SwitchThumb,
|
|
286
|
-
}
|
|
287
|
-
)
|
|
288
|
-
|
|
289
|
-
/* ---------------------------------------------------------------------------------------------- */
|
|
290
|
-
|
|
291
|
-
type InputProps = any //Radix.ComponentPropsWithoutRef<'input'>
|
|
292
|
-
interface BubbleInputProps extends Omit<InputProps, 'checked'> {
|
|
293
|
-
checked: boolean
|
|
294
|
-
control: HTMLElement | null
|
|
295
|
-
bubbles: boolean
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// TODO make this native friendly
|
|
299
|
-
const BubbleInput = (props: BubbleInputProps) => {
|
|
300
|
-
const { control, checked, bubbles = true, ...inputProps } = props
|
|
301
|
-
const ref = React.useRef<HTMLInputElement>(null)
|
|
302
|
-
const prevChecked = usePrevious(checked)
|
|
303
|
-
// const controlSize = useSize(control)
|
|
304
|
-
|
|
305
|
-
// Bubble checked change to parents (e.g form change event)
|
|
306
|
-
React.useEffect(() => {
|
|
307
|
-
const input = ref.current!
|
|
308
|
-
const inputProto = window.HTMLInputElement.prototype
|
|
309
|
-
const descriptor = Object.getOwnPropertyDescriptor(inputProto, 'checked') as PropertyDescriptor
|
|
310
|
-
const setChecked = descriptor.set
|
|
311
|
-
if (prevChecked !== checked && setChecked) {
|
|
312
|
-
const event = new Event('click', { bubbles })
|
|
313
|
-
setChecked.call(input, checked)
|
|
314
|
-
input.dispatchEvent(event)
|
|
315
|
-
}
|
|
316
|
-
}, [prevChecked, checked, bubbles])
|
|
317
|
-
|
|
318
|
-
return (
|
|
319
|
-
<input
|
|
320
|
-
type="checkbox"
|
|
321
|
-
aria-hidden
|
|
322
|
-
defaultChecked={checked}
|
|
323
|
-
{...inputProps}
|
|
324
|
-
tabIndex={-1}
|
|
325
|
-
ref={ref}
|
|
326
|
-
style={{
|
|
327
|
-
...props.style,
|
|
328
|
-
// ...controlSize,
|
|
329
|
-
position: 'absolute',
|
|
330
|
-
pointerEvents: 'none',
|
|
331
|
-
opacity: 0,
|
|
332
|
-
margin: 0,
|
|
333
|
-
}}
|
|
334
|
-
/>
|
|
335
|
-
)
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function getState(checked: boolean) {
|
|
339
|
-
return checked ? 'checked' : 'unchecked'
|
|
340
|
-
}
|
package/src/createSwitch.tsx
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
composeEventHandlers,
|
|
3
|
-
getVariableValue,
|
|
4
|
-
isWeb,
|
|
5
|
-
View,
|
|
6
|
-
withStaticProperties,
|
|
7
|
-
} from '@tamagui/core'
|
|
8
|
-
import { useSwitch } from '@tamagui/switch-headless'
|
|
9
|
-
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
10
|
-
import * as React from 'react'
|
|
11
|
-
import type { LayoutChangeEvent } from 'react-native'
|
|
12
|
-
import { SwitchStyledContext } from './StyledContext'
|
|
13
|
-
import { SwitchFrame as DefaultSwitchFrame, SwitchThumb } from './Switch'
|
|
14
|
-
import type {
|
|
15
|
-
SwitchComponent,
|
|
16
|
-
SwitchExtraProps,
|
|
17
|
-
SwitchProps,
|
|
18
|
-
SwitchThumbComponent,
|
|
19
|
-
SwitchThumbProps,
|
|
20
|
-
} from './types'
|
|
21
|
-
import { useSwitchNative } from './useSwitchNative'
|
|
22
|
-
|
|
23
|
-
export type { SwitchExtraProps, SwitchProps, SwitchThumbProps }
|
|
24
|
-
|
|
25
|
-
export function createSwitch<
|
|
26
|
-
F extends SwitchComponent,
|
|
27
|
-
T extends SwitchThumbComponent,
|
|
28
|
-
>(createProps: { Frame?: F; Thumb?: T }) {
|
|
29
|
-
const { Frame = DefaultSwitchFrame, Thumb = SwitchThumb } = createProps as any as {
|
|
30
|
-
Frame: typeof DefaultSwitchFrame
|
|
31
|
-
Thumb: typeof SwitchThumb
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (process.env.NODE_ENV === 'development') {
|
|
35
|
-
if (
|
|
36
|
-
(Frame !== DefaultSwitchFrame &&
|
|
37
|
-
Frame.staticConfig.context &&
|
|
38
|
-
Frame.staticConfig.context !== SwitchStyledContext) ||
|
|
39
|
-
(Thumb !== SwitchThumb &&
|
|
40
|
-
Thumb.staticConfig.context &&
|
|
41
|
-
Thumb.staticConfig.context !== SwitchStyledContext)
|
|
42
|
-
) {
|
|
43
|
-
console.warn(
|
|
44
|
-
`Warning: createSwitch() needs to control context to pass checked state from Frame to Thumb, any custom context passed will be overridden.`
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
Frame.staticConfig.context = SwitchStyledContext
|
|
50
|
-
Thumb.staticConfig.context = SwitchStyledContext
|
|
51
|
-
|
|
52
|
-
const SwitchThumbComponent = Thumb.styleable<SwitchThumbProps>(
|
|
53
|
-
function SwitchThumb(props, forwardedRef) {
|
|
54
|
-
const { size: sizeProp, unstyled: unstyledProp, activeStyle, ...thumbProps } = props
|
|
55
|
-
const styledContext = SwitchStyledContext.useStyledContext()
|
|
56
|
-
const {
|
|
57
|
-
unstyled: unstyledContext,
|
|
58
|
-
size: sizeContext,
|
|
59
|
-
active,
|
|
60
|
-
disabled,
|
|
61
|
-
frameWidth = 0,
|
|
62
|
-
} = styledContext
|
|
63
|
-
const unstyled =
|
|
64
|
-
process.env.TAMAGUI_HEADLESS === '1'
|
|
65
|
-
? true
|
|
66
|
-
: (unstyledProp ?? unstyledContext ?? false)
|
|
67
|
-
const size = sizeProp ?? sizeContext ?? '$true'
|
|
68
|
-
const initialChecked = React.useRef(active).current
|
|
69
|
-
const initialWidth = getVariableValue(props.width || size, 'size')
|
|
70
|
-
const [thumbWidth, setThumbWidth] = React.useState(
|
|
71
|
-
typeof initialWidth === 'number' ? initialWidth : 0
|
|
72
|
-
)
|
|
73
|
-
const distance = frameWidth - thumbWidth
|
|
74
|
-
const x = initialChecked ? (active ? 0 : -distance) : active ? distance : 0
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<Thumb
|
|
78
|
-
ref={forwardedRef}
|
|
79
|
-
unstyled={unstyled}
|
|
80
|
-
{...(unstyled === false && {
|
|
81
|
-
size,
|
|
82
|
-
})}
|
|
83
|
-
alignSelf={initialChecked ? 'flex-end' : 'flex-start'}
|
|
84
|
-
x={x}
|
|
85
|
-
onLayout={composeEventHandlers(props.onLayout, (e) => {
|
|
86
|
-
const next = e.nativeEvent.layout.width
|
|
87
|
-
setThumbWidth(next)
|
|
88
|
-
})}
|
|
89
|
-
disabled={disabled}
|
|
90
|
-
{...thumbProps}
|
|
91
|
-
{...(active && activeStyle)}
|
|
92
|
-
/>
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
const SwitchComponent = Frame.styleable<SwitchProps>(
|
|
98
|
-
function SwitchFrame(_props, forwardedRef) {
|
|
99
|
-
const {
|
|
100
|
-
native,
|
|
101
|
-
nativeProps,
|
|
102
|
-
checked: checkedProp,
|
|
103
|
-
defaultChecked,
|
|
104
|
-
onCheckedChange,
|
|
105
|
-
activeStyle,
|
|
106
|
-
unstyled: unstyledProp,
|
|
107
|
-
activeTheme: activeThemeProp,
|
|
108
|
-
...props
|
|
109
|
-
} = _props
|
|
110
|
-
const [checked, setChecked] = useControllableState({
|
|
111
|
-
prop: checkedProp,
|
|
112
|
-
defaultProp: defaultChecked || false,
|
|
113
|
-
onChange: onCheckedChange,
|
|
114
|
-
transition: true,
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
const styledContext = React.useContext(SwitchStyledContext.context)
|
|
118
|
-
|
|
119
|
-
// this is actually inner width
|
|
120
|
-
const [frameWidth, setFrameInnerWidth] = React.useState(0)
|
|
121
|
-
|
|
122
|
-
const { switchProps, bubbleInput, switchRef } = useSwitch(
|
|
123
|
-
props as any,
|
|
124
|
-
[checked, setChecked],
|
|
125
|
-
// @ts-ignore TODO tamagui react 19 type error
|
|
126
|
-
forwardedRef
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
const nativeSwitch = useSwitchNative({
|
|
130
|
-
id: props.id,
|
|
131
|
-
disabled: props.disabled,
|
|
132
|
-
native,
|
|
133
|
-
nativeProps,
|
|
134
|
-
checked,
|
|
135
|
-
setChecked,
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
if (nativeSwitch) {
|
|
139
|
-
return nativeSwitch
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const disabled = props.disabled
|
|
143
|
-
|
|
144
|
-
const handleLayout = (e: LayoutChangeEvent) => {
|
|
145
|
-
const next = e.nativeEvent.layout.width
|
|
146
|
-
if (next !== frameWidth) {
|
|
147
|
-
setFrameInnerWidth(next)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const unstyled = styledContext.unstyled ?? unstyledProp ?? false
|
|
152
|
-
|
|
153
|
-
return (
|
|
154
|
-
<>
|
|
155
|
-
<SwitchStyledContext.Provider
|
|
156
|
-
size={styledContext.size ?? props.size ?? '$true'}
|
|
157
|
-
unstyled={unstyled}
|
|
158
|
-
active={checked}
|
|
159
|
-
disabled={disabled}
|
|
160
|
-
frameWidth={frameWidth}
|
|
161
|
-
>
|
|
162
|
-
<Frame
|
|
163
|
-
ref={switchRef}
|
|
164
|
-
render="button"
|
|
165
|
-
// activeThemeProp should be a theme name string like "active", not a style object
|
|
166
|
-
theme={activeThemeProp ?? null}
|
|
167
|
-
{...(isWeb && { type: 'button' })}
|
|
168
|
-
{...(!unstyled && {
|
|
169
|
-
size: styledContext.size ?? props.size ?? '$true',
|
|
170
|
-
})}
|
|
171
|
-
unstyled={unstyled}
|
|
172
|
-
{...props}
|
|
173
|
-
{...(switchProps as any)}
|
|
174
|
-
disabled={disabled}
|
|
175
|
-
{...(checked && {
|
|
176
|
-
...(!unstyled &&
|
|
177
|
-
!activeStyle && {
|
|
178
|
-
backgroundColor: '$backgroundActive',
|
|
179
|
-
}),
|
|
180
|
-
...activeStyle,
|
|
181
|
-
})}
|
|
182
|
-
>
|
|
183
|
-
<View alignSelf="stretch" flex={1} onLayout={handleLayout}>
|
|
184
|
-
{props.children}
|
|
185
|
-
</View>
|
|
186
|
-
</Frame>
|
|
187
|
-
</SwitchStyledContext.Provider>
|
|
188
|
-
|
|
189
|
-
{bubbleInput}
|
|
190
|
-
</>
|
|
191
|
-
)
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
disableTheme: true,
|
|
195
|
-
}
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
return withStaticProperties(SwitchComponent, {
|
|
199
|
-
Thumb: SwitchThumbComponent,
|
|
200
|
-
})
|
|
201
|
-
}
|