@tamagui/switch 1.0.1-beta.138 → 1.0.1-beta.141
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/Switch.js +0 -0
- package/dist/cjs/Switch.js.map +0 -0
- package/dist/cjs/index.js +0 -0
- package/dist/cjs/index.js.map +0 -0
- package/dist/esm/Switch.js +0 -0
- package/dist/esm/Switch.js.map +0 -0
- package/dist/esm/index.js +0 -0
- package/dist/esm/index.js.map +0 -0
- package/dist/jsx/Switch.js +1 -2
- package/dist/jsx/Switch.js.map +1 -1
- package/dist/jsx/index.js +0 -0
- package/dist/jsx/index.js.map +0 -0
- package/package.json +9 -9
- package/src/Switch.draggable-tmp +340 -0
package/dist/cjs/Switch.js
CHANGED
|
File without changes
|
package/dist/cjs/Switch.js.map
CHANGED
|
File without changes
|
package/dist/cjs/index.js
CHANGED
|
File without changes
|
package/dist/cjs/index.js.map
CHANGED
|
File without changes
|
package/dist/esm/Switch.js
CHANGED
|
File without changes
|
package/dist/esm/Switch.js.map
CHANGED
|
File without changes
|
package/dist/esm/index.js
CHANGED
|
File without changes
|
package/dist/esm/index.js.map
CHANGED
|
File without changes
|
package/dist/jsx/Switch.js
CHANGED
|
@@ -109,8 +109,7 @@ const Switch = withStaticProperties(SwitchFrame.extractable(React.forwardRef((pr
|
|
|
109
109
|
}
|
|
110
110
|
return <SwitchProvider scope={__scopeSwitch} checked={checked} disabled={disabled} size={size}>
|
|
111
111
|
<SwitchFrame size={size} role="switch" aria-checked={checked} aria-labelledby={labelledBy} aria-required={required} data-state={getState(checked)} data-disabled={disabled ? "" : void 0} disabled={disabled} theme={checked ? "active" : null} themeShallow tabIndex={disabled ? void 0 : 0} value={value} {...switchProps} ref={composedRefs} onPress={(event) => {
|
|
112
|
-
|
|
113
|
-
(_a = props.onPress) == null ? void 0 : _a.call(props, event);
|
|
112
|
+
props.onPress?.(event);
|
|
114
113
|
setChecked((prevChecked) => !prevChecked);
|
|
115
114
|
if (isWeb && isFormControl) {
|
|
116
115
|
hasConsumerStoppedPropagationRef.current = event.isPropagationStopped();
|
package/dist/jsx/Switch.js.map
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/Switch.tsx"],
|
|
4
4
|
"sourcesContent": ["// via radix\n// https://github.com/radix-ui/primitives/blob/main/packages/react/switch/src/Switch.tsx\n\nimport { usePrevious } from '@radix-ui/react-use-previous'\nimport { useComposedRefs } from '@tamagui/compose-refs'\nimport {\n GetProps,\n SizeTokens,\n calc,\n getSize,\n getVariableValue,\n isWeb,\n styled,\n withStaticProperties,\n} from '@tamagui/core'\nimport { ScopedProps, createContextScope } from '@tamagui/create-context'\nimport { registerFocusable } from '@tamagui/focusable'\nimport { useLabelContext } from '@tamagui/label'\nimport { ThemeableStack, XStack } from '@tamagui/stacks'\nimport { useControllableState } from '@tamagui/use-controllable-state'\nimport * as React from 'react'\nimport { View } from 'react-native'\n\nconst SWITCH_NAME = 'Switch'\n\n// TODO make customizable\nconst getSwitchHeight = (val: SizeTokens) => Math.round(getVariableValue(getSize(val)) * 0.65)\nconst getSwitchWidth = (val: SizeTokens) => getSwitchHeight(val) * 2\n\nconst scopeContexts = createContextScope(SWITCH_NAME)\nconst [createSwitchContext] = scopeContexts\nexport const createSwitchScope = scopeContexts[1]\n\nconst [SwitchProvider, useSwitchContext] = createSwitchContext<{\n checked: boolean\n disabled?: boolean\n size: SizeTokens\n}>(SWITCH_NAME)\n\n/* -------------------------------------------------------------------------------------------------\n * SwitchThumb\n * -----------------------------------------------------------------------------------------------*/\n\nconst THUMB_NAME = 'SwitchThumb'\n\nexport const SwitchThumbFrame = styled(ThemeableStack, {\n name: 'SwitchThumb',\n backgroundColor: '$background',\n borderRadius: 1000,\n\n variants: {\n size: {\n '...size': (val) => ({\n height: getSwitchHeight(val),\n width: getSwitchHeight(val),\n }),\n },\n },\n\n defaultVariants: {\n size: '$4',\n },\n})\n\nexport type SwitchThumbProps = GetProps<typeof SwitchThumbFrame>\n\nexport const SwitchThumb = SwitchThumbFrame.extractable(\n React.forwardRef<React.ElementRef<'span'>, SwitchThumbProps>(\n (props: ScopedProps<SwitchThumbProps, 'Switch'>, forwardedRef) => {\n const { __scopeSwitch, ...thumbProps } = props\n const { size, disabled, checked } = useSwitchContext(THUMB_NAME, __scopeSwitch)\n return (\n <SwitchThumbFrame\n size={size}\n data-state={getState(checked)}\n data-disabled={disabled ? '' : undefined}\n {...thumbProps}\n x={\n checked\n ? getVariableValue(getSwitchWidth(size)) - getVariableValue(getSwitchHeight(size))\n : 0\n }\n ref={forwardedRef}\n />\n )\n }\n )\n)\n\nSwitchThumb.displayName = THUMB_NAME\n\n/* -------------------------------------------------------------------------------------------------\n * Switch\n * -----------------------------------------------------------------------------------------------*/\n\nexport const SwitchFrame = styled(XStack, {\n name: 'Switch',\n tag: 'button',\n borderRadius: 1000,\n borderWidth: 2,\n borderColor: 'transparent',\n backgroundColor: '$background',\n\n focusStyle: {\n borderColor: '$borderColorFocus',\n },\n\n variants: {\n size: {\n '...size': (val) => {\n const height = calc(getSwitchHeight(val), '+', 4)\n const width = calc(getSwitchWidth(val), '+', 4)\n return {\n height,\n minHeight: height,\n width,\n }\n },\n },\n },\n\n defaultVariants: {\n size: '$4',\n },\n})\n\ntype SwitchButtonProps = GetProps<typeof SwitchFrame>\n\nexport type SwitchProps = SwitchButtonProps & {\n labeledBy?: string\n name?: string\n value?: string\n checked?: boolean\n defaultChecked?: boolean\n required?: boolean\n onCheckedChange?(checked: boolean): void\n}\n\nexport const Switch = withStaticProperties(\n SwitchFrame.extractable(\n React.forwardRef<HTMLButtonElement | View, SwitchProps>(\n (props: ScopedProps<SwitchProps, 'Switch'>, forwardedRef) => {\n const {\n __scopeSwitch,\n labeledBy: ariaLabelledby,\n name,\n checked: checkedProp,\n defaultChecked,\n required,\n disabled,\n value = 'on',\n onCheckedChange,\n size = '$4',\n ...switchProps\n } = props\n const [button, setButton] = React.useState<HTMLButtonElement | null>(null)\n const composedRefs = useComposedRefs(forwardedRef, (node) => setButton(node as any))\n const labelId = useLabelContext(button)\n const labelledBy = ariaLabelledby || labelId\n const hasConsumerStoppedPropagationRef = React.useRef(false)\n // We set this to true by default so that events bubble to forms without JS (SSR)\n const isFormControl = isWeb ? (button ? Boolean(button.closest('form')) : true) : false\n const [checked = false, setChecked] = useControllableState({\n prop: checkedProp,\n defaultProp: defaultChecked || false,\n onChange: onCheckedChange,\n })\n\n if (!isWeb) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n React.useEffect(() => {\n if (!props.id) return\n return registerFocusable(props.id, {\n focus: () => {\n setChecked((x) => !x)\n },\n })\n }, [props.id, setChecked])\n }\n\n return (\n <SwitchProvider scope={__scopeSwitch} checked={checked} disabled={disabled} size={size}>\n <SwitchFrame\n size={size}\n // @ts-ignore\n role=\"switch\"\n aria-checked={checked}\n aria-labelledby={labelledBy}\n aria-required={required}\n data-state={getState(checked)}\n data-disabled={disabled ? '' : undefined}\n disabled={disabled}\n theme={checked ? 'active' : null}\n themeShallow\n // @ts-ignore\n tabIndex={disabled ? undefined : 0}\n // @ts-ignore\n value={value}\n {...switchProps}\n ref={composedRefs}\n onPress={(event) => {\n props.onPress?.(event)\n setChecked((prevChecked) => !prevChecked)\n if (isWeb && isFormControl) {\n hasConsumerStoppedPropagationRef.current = event.isPropagationStopped()\n // if switch is in a form, stop propagation from the button so that we only propagate\n // one click event (from the input). We propagate changes from an input so that native\n // form validation works and form events reflect switch updates.\n if (!hasConsumerStoppedPropagationRef.current) event.stopPropagation()\n }\n }}\n />\n {isWeb && isFormControl && (\n <BubbleInput\n control={button}\n bubbles={!hasConsumerStoppedPropagationRef.current}\n name={name}\n value={value}\n checked={checked}\n required={required}\n disabled={disabled}\n // We transform because the input is absolutely positioned but we have\n // rendered it **after** the button. This pulls it back to sit on top\n // of the button.\n style={{ transform: 'translateX(-100%)' }}\n />\n )}\n </SwitchProvider>\n )\n }\n )\n ),\n {\n Thumb: SwitchThumb,\n }\n)\n\n/* ---------------------------------------------------------------------------------------------- */\n\ntype InputProps = any //Radix.ComponentPropsWithoutRef<'input'>\ninterface BubbleInputProps extends Omit<InputProps, 'checked'> {\n checked: boolean\n control: HTMLElement | null\n bubbles: boolean\n}\n\n// TODO make this native friendly\nconst BubbleInput = (props: BubbleInputProps) => {\n const { control, checked, bubbles = true, ...inputProps } = props\n const ref = React.useRef<HTMLInputElement>(null)\n const prevChecked = usePrevious(checked)\n // const controlSize = useSize(control)\n\n // Bubble checked change to parents (e.g form change event)\n React.useEffect(() => {\n const input = ref.current!\n const inputProto = window.HTMLInputElement.prototype\n const descriptor = Object.getOwnPropertyDescriptor(inputProto, 'checked') as PropertyDescriptor\n const setChecked = descriptor.set\n if (prevChecked !== checked && setChecked) {\n const event = new Event('click', { bubbles })\n setChecked.call(input, checked)\n input.dispatchEvent(event)\n }\n }, [prevChecked, checked, bubbles])\n\n return (\n <input\n type=\"checkbox\"\n aria-hidden\n defaultChecked={checked}\n {...inputProps}\n tabIndex={-1}\n ref={ref}\n style={{\n ...props.style,\n // ...controlSize,\n position: 'absolute',\n pointerEvents: 'none',\n opacity: 0,\n margin: 0,\n }}\n />\n )\n}\n\nfunction getState(checked: boolean) {\n return checked ? 'checked' : 'unchecked'\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/jsx/index.js
CHANGED
|
File without changes
|
package/dist/jsx/index.js.map
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/switch",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.141",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"*.css"
|
|
6
6
|
],
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@radix-ui/react-use-previous": "^0.1.1",
|
|
27
|
-
"@tamagui/compose-refs": "^1.0.1-beta.
|
|
28
|
-
"@tamagui/core": "^1.0.1-beta.
|
|
29
|
-
"@tamagui/create-context": "^1.0.1-beta.
|
|
30
|
-
"@tamagui/focusable": "^1.0.1-beta.
|
|
31
|
-
"@tamagui/label": "^1.0.1-beta.
|
|
32
|
-
"@tamagui/stacks": "^1.0.1-beta.
|
|
33
|
-
"@tamagui/use-controllable-state": "^1.0.1-beta.
|
|
27
|
+
"@tamagui/compose-refs": "^1.0.1-beta.141",
|
|
28
|
+
"@tamagui/core": "^1.0.1-beta.141",
|
|
29
|
+
"@tamagui/create-context": "^1.0.1-beta.141",
|
|
30
|
+
"@tamagui/focusable": "^1.0.1-beta.141",
|
|
31
|
+
"@tamagui/label": "^1.0.1-beta.141",
|
|
32
|
+
"@tamagui/stacks": "^1.0.1-beta.141",
|
|
33
|
+
"@tamagui/use-controllable-state": "^1.0.1-beta.141"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "*",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"react-native": "*"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@tamagui/build": "^1.0.1-beta.
|
|
41
|
+
"@tamagui/build": "^1.0.1-beta.141",
|
|
42
42
|
"@types/react-native": "^0.69.2",
|
|
43
43
|
"react": "*",
|
|
44
44
|
"react-dom": "*",
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// via radix
|
|
2
|
+
// https://github.com/radix-ui/primitives/blob/main/packages/react/switch/src/Switch.tsx
|
|
3
|
+
|
|
4
|
+
import { usePrevious } from '@radix-ui/react-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
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
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
|
+
}
|