@tamagui/switch 1.88.12 → 1.89.0-1706308641099
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/LICENSE +21 -0
- package/dist/esm/Switch.mjs +75 -0
- package/dist/esm/SwitchContext.mjs +9 -0
- package/dist/esm/createSwitch.mjs +215 -0
- package/dist/esm/index.mjs +10 -0
- package/dist/jsx/Switch.mjs +75 -0
- package/dist/jsx/SwitchContext.mjs +9 -0
- package/dist/jsx/createSwitch.mjs +215 -0
- package/dist/jsx/index.mjs +10 -0
- package/package.json +12 -12
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Nate Wienert
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getVariableValue, styled } from "@tamagui/core";
|
|
2
|
+
import { getSize } from "@tamagui/get-token";
|
|
3
|
+
import { ThemeableStack, YStack } from "@tamagui/stacks";
|
|
4
|
+
import { SwitchContext } from "./SwitchContext.mjs";
|
|
5
|
+
const SwitchThumb = styled(ThemeableStack, {
|
|
6
|
+
name: "SwitchThumb",
|
|
7
|
+
context: SwitchContext,
|
|
8
|
+
variants: {
|
|
9
|
+
unstyled: {
|
|
10
|
+
false: {
|
|
11
|
+
size: "$true",
|
|
12
|
+
backgroundColor: "$background",
|
|
13
|
+
borderRadius: 1e3
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
checked: {
|
|
17
|
+
true: {}
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
"...size": val => {
|
|
21
|
+
const size = getSwitchHeight(val);
|
|
22
|
+
return {
|
|
23
|
+
height: size,
|
|
24
|
+
width: size
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
unstyled: process.env.TAMAGUI_HEADLESS === "1"
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
33
|
+
getSwitchHeight = val => Math.round(getVariableValue(getSize(val)) * 0.65),
|
|
34
|
+
getSwitchWidth = val => getSwitchHeight(val) * 2,
|
|
35
|
+
SwitchFrame = styled(YStack, {
|
|
36
|
+
name: "Switch",
|
|
37
|
+
context: SwitchContext,
|
|
38
|
+
variants: {
|
|
39
|
+
unstyled: {
|
|
40
|
+
false: {
|
|
41
|
+
size: "$true",
|
|
42
|
+
borderRadius: 1e3,
|
|
43
|
+
backgroundColor: "$background",
|
|
44
|
+
borderWidth: 2,
|
|
45
|
+
borderColor: "$background",
|
|
46
|
+
focusStyle: {
|
|
47
|
+
outlineColor: "$outlineColor",
|
|
48
|
+
outlineStyle: "solid",
|
|
49
|
+
outlineWidth: 2
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
checked: {
|
|
54
|
+
true: {}
|
|
55
|
+
},
|
|
56
|
+
frameWidth: {
|
|
57
|
+
":number": () => null
|
|
58
|
+
},
|
|
59
|
+
size: {
|
|
60
|
+
"...size": val => {
|
|
61
|
+
const height = getSwitchHeight(val) + 4,
|
|
62
|
+
width = getSwitchWidth(val) + 4;
|
|
63
|
+
return {
|
|
64
|
+
height,
|
|
65
|
+
minHeight: height,
|
|
66
|
+
width
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
defaultVariants: {
|
|
72
|
+
unstyled: process.env.TAMAGUI_HEADLESS === "1"
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
export { SwitchFrame, SwitchThumb };
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { useComposedRefs } from "@tamagui/compose-refs";
|
|
2
|
+
import { isWeb } from "@tamagui/constants";
|
|
3
|
+
import { useProps } from "@tamagui/core";
|
|
4
|
+
import { registerFocusable } from "@tamagui/focusable";
|
|
5
|
+
import { composeEventHandlers, withStaticProperties } from "@tamagui/helpers";
|
|
6
|
+
import { useLabelContext } from "@tamagui/label";
|
|
7
|
+
import { ButtonNestingContext, YStack } from "@tamagui/stacks";
|
|
8
|
+
import { useControllableState } from "@tamagui/use-controllable-state";
|
|
9
|
+
import { usePrevious } from "@tamagui/use-previous";
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { Switch as NativeSwitch, Platform } from "react-native-web";
|
|
12
|
+
import { SwitchFrame as DefaultSwitchFrame, SwitchThumb } from "./Switch.mjs";
|
|
13
|
+
import { SwitchContext } from "./SwitchContext.mjs";
|
|
14
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
function createSwitch(createProps) {
|
|
16
|
+
const {
|
|
17
|
+
disableActiveTheme,
|
|
18
|
+
Frame = DefaultSwitchFrame,
|
|
19
|
+
Thumb = SwitchThumb
|
|
20
|
+
} = createProps;
|
|
21
|
+
process.env.NODE_ENV === "development" && (Frame !== DefaultSwitchFrame && Frame.staticConfig.context && console.warn("Warning: createSwitch() needs to control context to pass checked state from Frame to Thumb, any custom context passed will be overridden."), Thumb !== SwitchThumb && Thumb.staticConfig.context && console.warn("Warning: createSwitch() needs to control context to pass checked state from Frame to Thumb, any custom context passed will be overridden.")), Frame.staticConfig.context = SwitchContext, Thumb.staticConfig.context = SwitchContext;
|
|
22
|
+
const SwitchThumbComponent = Thumb.styleable(function (props, forwardedRef) {
|
|
23
|
+
const {
|
|
24
|
+
size: sizeProp,
|
|
25
|
+
unstyled: unstyledProp,
|
|
26
|
+
...thumbProps
|
|
27
|
+
} = props,
|
|
28
|
+
context = React.useContext(SwitchContext),
|
|
29
|
+
{
|
|
30
|
+
disabled,
|
|
31
|
+
checked,
|
|
32
|
+
unstyled: unstyledContext,
|
|
33
|
+
frameWidth,
|
|
34
|
+
size: sizeContext
|
|
35
|
+
} = context,
|
|
36
|
+
[thumbWidth, setThumbWidth] = React.useState(0),
|
|
37
|
+
initialChecked = React.useRef(checked).current,
|
|
38
|
+
distance = frameWidth - thumbWidth,
|
|
39
|
+
x = initialChecked ? checked ? 0 : -distance : checked ? distance : 0;
|
|
40
|
+
return (
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
/* @__PURE__ */
|
|
43
|
+
jsx(Thumb, {
|
|
44
|
+
...((unstyledProp ?? unstyledContext ?? !1) === !1 && {
|
|
45
|
+
unstyled: process.env.TAMAGUI_HEADLESS === "1",
|
|
46
|
+
size: sizeProp ?? sizeContext ?? "$true",
|
|
47
|
+
...(!disableActiveTheme && {
|
|
48
|
+
theme: checked ? "active" : null
|
|
49
|
+
})
|
|
50
|
+
}),
|
|
51
|
+
"data-state": getState(checked),
|
|
52
|
+
"data-disabled": disabled ? "" : void 0,
|
|
53
|
+
alignSelf: initialChecked ? "flex-end" : "flex-start",
|
|
54
|
+
checked,
|
|
55
|
+
x,
|
|
56
|
+
...thumbProps,
|
|
57
|
+
onLayout: composeEventHandlers(props.onLayout, e =>
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
setThumbWidth(e.nativeEvent.layout.width)),
|
|
60
|
+
ref: forwardedRef
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
}),
|
|
64
|
+
SwitchComponent = Frame.styleable(function (propsIn, forwardedRef) {
|
|
65
|
+
const styledContext = React.useContext(SwitchContext),
|
|
66
|
+
props = useProps(propsIn, {
|
|
67
|
+
noNormalize: !0,
|
|
68
|
+
noExpand: !0,
|
|
69
|
+
resolveValues: "none",
|
|
70
|
+
forComponent: Frame
|
|
71
|
+
}),
|
|
72
|
+
{
|
|
73
|
+
labeledBy: ariaLabelledby,
|
|
74
|
+
name,
|
|
75
|
+
checked: checkedProp,
|
|
76
|
+
defaultChecked,
|
|
77
|
+
required,
|
|
78
|
+
disabled,
|
|
79
|
+
value = "on",
|
|
80
|
+
onCheckedChange,
|
|
81
|
+
size = styledContext.size ?? "$true",
|
|
82
|
+
unstyled = styledContext.unstyled ?? !1,
|
|
83
|
+
native: nativeProp,
|
|
84
|
+
nativeProps,
|
|
85
|
+
children,
|
|
86
|
+
...switchProps
|
|
87
|
+
} = props,
|
|
88
|
+
native = Array.isArray(nativeProp) ? nativeProp : [nativeProp],
|
|
89
|
+
shouldRenderMobileNative = !isWeb && nativeProp === !0 || !isWeb && native.includes("mobile") || native.includes("android") && Platform.OS === "android" || native.includes("ios") && Platform.OS === "ios",
|
|
90
|
+
[button, setButton] = React.useState(null),
|
|
91
|
+
composedRefs = useComposedRefs(forwardedRef, setButton),
|
|
92
|
+
labelId = useLabelContext(button),
|
|
93
|
+
labelledBy = ariaLabelledby || labelId,
|
|
94
|
+
hasConsumerStoppedPropagationRef = React.useRef(!1),
|
|
95
|
+
isFormControl = isWeb ? button ? !!button.closest("form") : !0 : !1,
|
|
96
|
+
[frameWidth, setFrameWidth] = React.useState(0),
|
|
97
|
+
[checked = !1, setChecked] = useControllableState({
|
|
98
|
+
prop: checkedProp,
|
|
99
|
+
defaultProp: defaultChecked || !1,
|
|
100
|
+
onChange: onCheckedChange,
|
|
101
|
+
transition: !0
|
|
102
|
+
});
|
|
103
|
+
if (shouldRenderMobileNative) return /* @__PURE__ */jsx(NativeSwitch, {
|
|
104
|
+
value: checkedProp,
|
|
105
|
+
onValueChange: onCheckedChange,
|
|
106
|
+
...nativeProps
|
|
107
|
+
});
|
|
108
|
+
isWeb || React.useEffect(() => {
|
|
109
|
+
if (props.id) return registerFocusable(props.id, {
|
|
110
|
+
focus: () => {
|
|
111
|
+
setChecked(x => !x);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}, [props.id, setChecked]);
|
|
115
|
+
const isInsideButton = React.useContext(ButtonNestingContext);
|
|
116
|
+
return /* @__PURE__ */jsxs(Fragment, {
|
|
117
|
+
children: [/* @__PURE__ */jsx(ButtonNestingContext.Provider, {
|
|
118
|
+
value: !0,
|
|
119
|
+
children: /* @__PURE__ */jsx(Frame, {
|
|
120
|
+
tag: isInsideButton ? "span" : "button",
|
|
121
|
+
unstyled,
|
|
122
|
+
size,
|
|
123
|
+
checked,
|
|
124
|
+
disabled,
|
|
125
|
+
frameWidth,
|
|
126
|
+
themeShallow: !0,
|
|
127
|
+
...(!disableActiveTheme && {
|
|
128
|
+
theme: checked ? "active" : null,
|
|
129
|
+
themeShallow: !0
|
|
130
|
+
}),
|
|
131
|
+
role: "switch",
|
|
132
|
+
"aria-checked": checked,
|
|
133
|
+
"aria-labelledby": labelledBy,
|
|
134
|
+
"aria-required": required,
|
|
135
|
+
"data-state": getState(checked),
|
|
136
|
+
"data-disabled": disabled ? "" : void 0,
|
|
137
|
+
tabIndex: disabled ? void 0 : 0,
|
|
138
|
+
value,
|
|
139
|
+
...switchProps,
|
|
140
|
+
ref: composedRefs,
|
|
141
|
+
onPress: composeEventHandlers(props.onPress, event => {
|
|
142
|
+
setChecked(prevChecked => !prevChecked), isWeb && isFormControl && (hasConsumerStoppedPropagationRef.current = event.isPropagationStopped(), hasConsumerStoppedPropagationRef.current || event.stopPropagation());
|
|
143
|
+
}),
|
|
144
|
+
children: /* @__PURE__ */jsx(YStack, {
|
|
145
|
+
alignSelf: "stretch",
|
|
146
|
+
flex: 1,
|
|
147
|
+
onLayout: e => {
|
|
148
|
+
setFrameWidth(e.nativeEvent.layout.width);
|
|
149
|
+
},
|
|
150
|
+
children: typeof children == "function" ? children(checked) : children
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
}), isWeb && isFormControl && /* @__PURE__ */jsx(BubbleInput, {
|
|
154
|
+
control: button,
|
|
155
|
+
bubbles: !hasConsumerStoppedPropagationRef.current,
|
|
156
|
+
name,
|
|
157
|
+
value,
|
|
158
|
+
checked,
|
|
159
|
+
required,
|
|
160
|
+
disabled,
|
|
161
|
+
style: {
|
|
162
|
+
transform: "translateX(-100%)"
|
|
163
|
+
}
|
|
164
|
+
})]
|
|
165
|
+
});
|
|
166
|
+
}, {
|
|
167
|
+
disableTheme: !0
|
|
168
|
+
}),
|
|
169
|
+
BubbleInput = props => {
|
|
170
|
+
const {
|
|
171
|
+
control,
|
|
172
|
+
checked,
|
|
173
|
+
bubbles = !0,
|
|
174
|
+
...inputProps
|
|
175
|
+
} = props,
|
|
176
|
+
ref = React.useRef(null),
|
|
177
|
+
prevChecked = usePrevious(checked);
|
|
178
|
+
return React.useEffect(() => {
|
|
179
|
+
const input = ref.current,
|
|
180
|
+
inputProto = window.HTMLInputElement.prototype,
|
|
181
|
+
setChecked = Object.getOwnPropertyDescriptor(inputProto, "checked").set;
|
|
182
|
+
if (prevChecked !== checked && setChecked) {
|
|
183
|
+
const event = new Event("click", {
|
|
184
|
+
bubbles
|
|
185
|
+
});
|
|
186
|
+
setChecked.call(input, checked), input.dispatchEvent(event);
|
|
187
|
+
}
|
|
188
|
+
}, [prevChecked, checked, bubbles]),
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
/* @__PURE__ */
|
|
191
|
+
jsx("input", {
|
|
192
|
+
type: "checkbox",
|
|
193
|
+
"aria-hidden": !0,
|
|
194
|
+
defaultChecked: checked,
|
|
195
|
+
...inputProps,
|
|
196
|
+
tabIndex: -1,
|
|
197
|
+
ref,
|
|
198
|
+
style: {
|
|
199
|
+
...props.style,
|
|
200
|
+
// ...controlSize,
|
|
201
|
+
position: "absolute",
|
|
202
|
+
pointerEvents: "none",
|
|
203
|
+
opacity: 0,
|
|
204
|
+
margin: 0
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
function getState(checked) {
|
|
209
|
+
return checked ? "checked" : "unchecked";
|
|
210
|
+
}
|
|
211
|
+
return withStaticProperties(SwitchComponent, {
|
|
212
|
+
Thumb: SwitchThumbComponent
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
export { createSwitch };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createSwitch } from "./createSwitch.mjs";
|
|
2
|
+
import { SwitchFrame, SwitchThumb } from "./Switch.mjs";
|
|
3
|
+
export * from "./Switch.mjs";
|
|
4
|
+
export * from "./SwitchContext.mjs";
|
|
5
|
+
export * from "./createSwitch.mjs";
|
|
6
|
+
const Switch = createSwitch({
|
|
7
|
+
Frame: SwitchFrame,
|
|
8
|
+
Thumb: SwitchThumb
|
|
9
|
+
});
|
|
10
|
+
export { Switch };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getVariableValue, styled } from "@tamagui/core";
|
|
2
|
+
import { getSize } from "@tamagui/get-token";
|
|
3
|
+
import { ThemeableStack, YStack } from "@tamagui/stacks";
|
|
4
|
+
import { SwitchContext } from "./SwitchContext.mjs";
|
|
5
|
+
const SwitchThumb = styled(ThemeableStack, {
|
|
6
|
+
name: "SwitchThumb",
|
|
7
|
+
context: SwitchContext,
|
|
8
|
+
variants: {
|
|
9
|
+
unstyled: {
|
|
10
|
+
false: {
|
|
11
|
+
size: "$true",
|
|
12
|
+
backgroundColor: "$background",
|
|
13
|
+
borderRadius: 1e3
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
checked: {
|
|
17
|
+
true: {}
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
"...size": val => {
|
|
21
|
+
const size = getSwitchHeight(val);
|
|
22
|
+
return {
|
|
23
|
+
height: size,
|
|
24
|
+
width: size
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
unstyled: process.env.TAMAGUI_HEADLESS === "1"
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
33
|
+
getSwitchHeight = val => Math.round(getVariableValue(getSize(val)) * 0.65),
|
|
34
|
+
getSwitchWidth = val => getSwitchHeight(val) * 2,
|
|
35
|
+
SwitchFrame = styled(YStack, {
|
|
36
|
+
name: "Switch",
|
|
37
|
+
context: SwitchContext,
|
|
38
|
+
variants: {
|
|
39
|
+
unstyled: {
|
|
40
|
+
false: {
|
|
41
|
+
size: "$true",
|
|
42
|
+
borderRadius: 1e3,
|
|
43
|
+
backgroundColor: "$background",
|
|
44
|
+
borderWidth: 2,
|
|
45
|
+
borderColor: "$background",
|
|
46
|
+
focusStyle: {
|
|
47
|
+
outlineColor: "$outlineColor",
|
|
48
|
+
outlineStyle: "solid",
|
|
49
|
+
outlineWidth: 2
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
checked: {
|
|
54
|
+
true: {}
|
|
55
|
+
},
|
|
56
|
+
frameWidth: {
|
|
57
|
+
":number": () => null
|
|
58
|
+
},
|
|
59
|
+
size: {
|
|
60
|
+
"...size": val => {
|
|
61
|
+
const height = getSwitchHeight(val) + 4,
|
|
62
|
+
width = getSwitchWidth(val) + 4;
|
|
63
|
+
return {
|
|
64
|
+
height,
|
|
65
|
+
minHeight: height,
|
|
66
|
+
width
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
defaultVariants: {
|
|
72
|
+
unstyled: process.env.TAMAGUI_HEADLESS === "1"
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
export { SwitchFrame, SwitchThumb };
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { useComposedRefs } from "@tamagui/compose-refs";
|
|
2
|
+
import { isWeb } from "@tamagui/constants";
|
|
3
|
+
import { useProps } from "@tamagui/core";
|
|
4
|
+
import { registerFocusable } from "@tamagui/focusable";
|
|
5
|
+
import { composeEventHandlers, withStaticProperties } from "@tamagui/helpers";
|
|
6
|
+
import { useLabelContext } from "@tamagui/label";
|
|
7
|
+
import { ButtonNestingContext, YStack } from "@tamagui/stacks";
|
|
8
|
+
import { useControllableState } from "@tamagui/use-controllable-state";
|
|
9
|
+
import { usePrevious } from "@tamagui/use-previous";
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { Switch as NativeSwitch, Platform } from "react-native-web";
|
|
12
|
+
import { SwitchFrame as DefaultSwitchFrame, SwitchThumb } from "./Switch.mjs";
|
|
13
|
+
import { SwitchContext } from "./SwitchContext.mjs";
|
|
14
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
function createSwitch(createProps) {
|
|
16
|
+
const {
|
|
17
|
+
disableActiveTheme,
|
|
18
|
+
Frame = DefaultSwitchFrame,
|
|
19
|
+
Thumb = SwitchThumb
|
|
20
|
+
} = createProps;
|
|
21
|
+
process.env.NODE_ENV === "development" && (Frame !== DefaultSwitchFrame && Frame.staticConfig.context && console.warn("Warning: createSwitch() needs to control context to pass checked state from Frame to Thumb, any custom context passed will be overridden."), Thumb !== SwitchThumb && Thumb.staticConfig.context && console.warn("Warning: createSwitch() needs to control context to pass checked state from Frame to Thumb, any custom context passed will be overridden.")), Frame.staticConfig.context = SwitchContext, Thumb.staticConfig.context = SwitchContext;
|
|
22
|
+
const SwitchThumbComponent = Thumb.styleable(function (props, forwardedRef) {
|
|
23
|
+
const {
|
|
24
|
+
size: sizeProp,
|
|
25
|
+
unstyled: unstyledProp,
|
|
26
|
+
...thumbProps
|
|
27
|
+
} = props,
|
|
28
|
+
context = React.useContext(SwitchContext),
|
|
29
|
+
{
|
|
30
|
+
disabled,
|
|
31
|
+
checked,
|
|
32
|
+
unstyled: unstyledContext,
|
|
33
|
+
frameWidth,
|
|
34
|
+
size: sizeContext
|
|
35
|
+
} = context,
|
|
36
|
+
[thumbWidth, setThumbWidth] = React.useState(0),
|
|
37
|
+
initialChecked = React.useRef(checked).current,
|
|
38
|
+
distance = frameWidth - thumbWidth,
|
|
39
|
+
x = initialChecked ? checked ? 0 : -distance : checked ? distance : 0;
|
|
40
|
+
return (
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
/* @__PURE__ */
|
|
43
|
+
jsx(Thumb, {
|
|
44
|
+
...((unstyledProp ?? unstyledContext ?? !1) === !1 && {
|
|
45
|
+
unstyled: process.env.TAMAGUI_HEADLESS === "1",
|
|
46
|
+
size: sizeProp ?? sizeContext ?? "$true",
|
|
47
|
+
...(!disableActiveTheme && {
|
|
48
|
+
theme: checked ? "active" : null
|
|
49
|
+
})
|
|
50
|
+
}),
|
|
51
|
+
"data-state": getState(checked),
|
|
52
|
+
"data-disabled": disabled ? "" : void 0,
|
|
53
|
+
alignSelf: initialChecked ? "flex-end" : "flex-start",
|
|
54
|
+
checked,
|
|
55
|
+
x,
|
|
56
|
+
...thumbProps,
|
|
57
|
+
onLayout: composeEventHandlers(props.onLayout, e =>
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
setThumbWidth(e.nativeEvent.layout.width)),
|
|
60
|
+
ref: forwardedRef
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
}),
|
|
64
|
+
SwitchComponent = Frame.styleable(function (propsIn, forwardedRef) {
|
|
65
|
+
const styledContext = React.useContext(SwitchContext),
|
|
66
|
+
props = useProps(propsIn, {
|
|
67
|
+
noNormalize: !0,
|
|
68
|
+
noExpand: !0,
|
|
69
|
+
resolveValues: "none",
|
|
70
|
+
forComponent: Frame
|
|
71
|
+
}),
|
|
72
|
+
{
|
|
73
|
+
labeledBy: ariaLabelledby,
|
|
74
|
+
name,
|
|
75
|
+
checked: checkedProp,
|
|
76
|
+
defaultChecked,
|
|
77
|
+
required,
|
|
78
|
+
disabled,
|
|
79
|
+
value = "on",
|
|
80
|
+
onCheckedChange,
|
|
81
|
+
size = styledContext.size ?? "$true",
|
|
82
|
+
unstyled = styledContext.unstyled ?? !1,
|
|
83
|
+
native: nativeProp,
|
|
84
|
+
nativeProps,
|
|
85
|
+
children,
|
|
86
|
+
...switchProps
|
|
87
|
+
} = props,
|
|
88
|
+
native = Array.isArray(nativeProp) ? nativeProp : [nativeProp],
|
|
89
|
+
shouldRenderMobileNative = !isWeb && nativeProp === !0 || !isWeb && native.includes("mobile") || native.includes("android") && Platform.OS === "android" || native.includes("ios") && Platform.OS === "ios",
|
|
90
|
+
[button, setButton] = React.useState(null),
|
|
91
|
+
composedRefs = useComposedRefs(forwardedRef, setButton),
|
|
92
|
+
labelId = useLabelContext(button),
|
|
93
|
+
labelledBy = ariaLabelledby || labelId,
|
|
94
|
+
hasConsumerStoppedPropagationRef = React.useRef(!1),
|
|
95
|
+
isFormControl = isWeb ? button ? !!button.closest("form") : !0 : !1,
|
|
96
|
+
[frameWidth, setFrameWidth] = React.useState(0),
|
|
97
|
+
[checked = !1, setChecked] = useControllableState({
|
|
98
|
+
prop: checkedProp,
|
|
99
|
+
defaultProp: defaultChecked || !1,
|
|
100
|
+
onChange: onCheckedChange,
|
|
101
|
+
transition: !0
|
|
102
|
+
});
|
|
103
|
+
if (shouldRenderMobileNative) return /* @__PURE__ */jsx(NativeSwitch, {
|
|
104
|
+
value: checkedProp,
|
|
105
|
+
onValueChange: onCheckedChange,
|
|
106
|
+
...nativeProps
|
|
107
|
+
});
|
|
108
|
+
isWeb || React.useEffect(() => {
|
|
109
|
+
if (props.id) return registerFocusable(props.id, {
|
|
110
|
+
focus: () => {
|
|
111
|
+
setChecked(x => !x);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}, [props.id, setChecked]);
|
|
115
|
+
const isInsideButton = React.useContext(ButtonNestingContext);
|
|
116
|
+
return /* @__PURE__ */jsxs(Fragment, {
|
|
117
|
+
children: [/* @__PURE__ */jsx(ButtonNestingContext.Provider, {
|
|
118
|
+
value: !0,
|
|
119
|
+
children: /* @__PURE__ */jsx(Frame, {
|
|
120
|
+
tag: isInsideButton ? "span" : "button",
|
|
121
|
+
unstyled,
|
|
122
|
+
size,
|
|
123
|
+
checked,
|
|
124
|
+
disabled,
|
|
125
|
+
frameWidth,
|
|
126
|
+
themeShallow: !0,
|
|
127
|
+
...(!disableActiveTheme && {
|
|
128
|
+
theme: checked ? "active" : null,
|
|
129
|
+
themeShallow: !0
|
|
130
|
+
}),
|
|
131
|
+
role: "switch",
|
|
132
|
+
"aria-checked": checked,
|
|
133
|
+
"aria-labelledby": labelledBy,
|
|
134
|
+
"aria-required": required,
|
|
135
|
+
"data-state": getState(checked),
|
|
136
|
+
"data-disabled": disabled ? "" : void 0,
|
|
137
|
+
tabIndex: disabled ? void 0 : 0,
|
|
138
|
+
value,
|
|
139
|
+
...switchProps,
|
|
140
|
+
ref: composedRefs,
|
|
141
|
+
onPress: composeEventHandlers(props.onPress, event => {
|
|
142
|
+
setChecked(prevChecked => !prevChecked), isWeb && isFormControl && (hasConsumerStoppedPropagationRef.current = event.isPropagationStopped(), hasConsumerStoppedPropagationRef.current || event.stopPropagation());
|
|
143
|
+
}),
|
|
144
|
+
children: /* @__PURE__ */jsx(YStack, {
|
|
145
|
+
alignSelf: "stretch",
|
|
146
|
+
flex: 1,
|
|
147
|
+
onLayout: e => {
|
|
148
|
+
setFrameWidth(e.nativeEvent.layout.width);
|
|
149
|
+
},
|
|
150
|
+
children: typeof children == "function" ? children(checked) : children
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
}), isWeb && isFormControl && /* @__PURE__ */jsx(BubbleInput, {
|
|
154
|
+
control: button,
|
|
155
|
+
bubbles: !hasConsumerStoppedPropagationRef.current,
|
|
156
|
+
name,
|
|
157
|
+
value,
|
|
158
|
+
checked,
|
|
159
|
+
required,
|
|
160
|
+
disabled,
|
|
161
|
+
style: {
|
|
162
|
+
transform: "translateX(-100%)"
|
|
163
|
+
}
|
|
164
|
+
})]
|
|
165
|
+
});
|
|
166
|
+
}, {
|
|
167
|
+
disableTheme: !0
|
|
168
|
+
}),
|
|
169
|
+
BubbleInput = props => {
|
|
170
|
+
const {
|
|
171
|
+
control,
|
|
172
|
+
checked,
|
|
173
|
+
bubbles = !0,
|
|
174
|
+
...inputProps
|
|
175
|
+
} = props,
|
|
176
|
+
ref = React.useRef(null),
|
|
177
|
+
prevChecked = usePrevious(checked);
|
|
178
|
+
return React.useEffect(() => {
|
|
179
|
+
const input = ref.current,
|
|
180
|
+
inputProto = window.HTMLInputElement.prototype,
|
|
181
|
+
setChecked = Object.getOwnPropertyDescriptor(inputProto, "checked").set;
|
|
182
|
+
if (prevChecked !== checked && setChecked) {
|
|
183
|
+
const event = new Event("click", {
|
|
184
|
+
bubbles
|
|
185
|
+
});
|
|
186
|
+
setChecked.call(input, checked), input.dispatchEvent(event);
|
|
187
|
+
}
|
|
188
|
+
}, [prevChecked, checked, bubbles]),
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
/* @__PURE__ */
|
|
191
|
+
jsx("input", {
|
|
192
|
+
type: "checkbox",
|
|
193
|
+
"aria-hidden": !0,
|
|
194
|
+
defaultChecked: checked,
|
|
195
|
+
...inputProps,
|
|
196
|
+
tabIndex: -1,
|
|
197
|
+
ref,
|
|
198
|
+
style: {
|
|
199
|
+
...props.style,
|
|
200
|
+
// ...controlSize,
|
|
201
|
+
position: "absolute",
|
|
202
|
+
pointerEvents: "none",
|
|
203
|
+
opacity: 0,
|
|
204
|
+
margin: 0
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
function getState(checked) {
|
|
209
|
+
return checked ? "checked" : "unchecked";
|
|
210
|
+
}
|
|
211
|
+
return withStaticProperties(SwitchComponent, {
|
|
212
|
+
Thumb: SwitchThumbComponent
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
export { createSwitch };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createSwitch } from "./createSwitch.mjs";
|
|
2
|
+
import { SwitchFrame, SwitchThumb } from "./Switch.mjs";
|
|
3
|
+
export * from "./Switch.mjs";
|
|
4
|
+
export * from "./SwitchContext.mjs";
|
|
5
|
+
export * from "./createSwitch.mjs";
|
|
6
|
+
const Switch = createSwitch({
|
|
7
|
+
Frame: SwitchFrame,
|
|
8
|
+
Thumb: SwitchThumb
|
|
9
|
+
});
|
|
10
|
+
export { Switch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/switch",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.89.0-1706308641099",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"*.css"
|
|
6
6
|
],
|
|
@@ -32,23 +32,23 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@tamagui/compose-refs": "1.
|
|
36
|
-
"@tamagui/constants": "1.
|
|
37
|
-
"@tamagui/core": "1.
|
|
38
|
-
"@tamagui/focusable": "1.
|
|
39
|
-
"@tamagui/get-token": "1.
|
|
40
|
-
"@tamagui/helpers": "1.
|
|
41
|
-
"@tamagui/label": "1.
|
|
42
|
-
"@tamagui/stacks": "1.
|
|
43
|
-
"@tamagui/use-controllable-state": "1.
|
|
44
|
-
"@tamagui/use-previous": "1.
|
|
35
|
+
"@tamagui/compose-refs": "1.89.0-1706308641099",
|
|
36
|
+
"@tamagui/constants": "1.89.0-1706308641099",
|
|
37
|
+
"@tamagui/core": "1.89.0-1706308641099",
|
|
38
|
+
"@tamagui/focusable": "1.89.0-1706308641099",
|
|
39
|
+
"@tamagui/get-token": "1.89.0-1706308641099",
|
|
40
|
+
"@tamagui/helpers": "1.89.0-1706308641099",
|
|
41
|
+
"@tamagui/label": "1.89.0-1706308641099",
|
|
42
|
+
"@tamagui/stacks": "1.89.0-1706308641099",
|
|
43
|
+
"@tamagui/use-controllable-state": "1.89.0-1706308641099",
|
|
44
|
+
"@tamagui/use-previous": "1.89.0-1706308641099"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"react": "*",
|
|
48
48
|
"react-native": "*"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@tamagui/build": "1.
|
|
51
|
+
"@tamagui/build": "1.89.0-1706308641099",
|
|
52
52
|
"react": "^18.2.0",
|
|
53
53
|
"react-native": "^0.72.6"
|
|
54
54
|
},
|