@impulse-ui-native/switch 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @impulse-ui-native/switch
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Token-aware animated switch controls for React Native mobile applications.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -27,7 +27,6 @@ export function NotificationsSwitch() {
|
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<Switch
|
|
30
|
-
accessibilityLabel="Notifications"
|
|
31
30
|
checked={checked}
|
|
32
31
|
onCheckedChange={setChecked}
|
|
33
32
|
size="medium"
|
|
@@ -37,8 +36,6 @@ export function NotificationsSwitch() {
|
|
|
37
36
|
}
|
|
38
37
|
```
|
|
39
38
|
|
|
40
|
-
Use `defaultChecked` for uncontrolled state. The thumb position and track colors animate when the state changes.
|
|
39
|
+
Use `defaultChecked` for uncontrolled state. The thumb position and track colors animate when the state changes.
|
|
41
40
|
|
|
42
|
-
Set `loading` while an update is pending. Loading switches
|
|
43
|
-
|
|
44
|
-
The standalone switch does not render a label, so provide `accessibilityLabel` unless a surrounding labelled control supplies an accessible name.
|
|
41
|
+
Set `loading` while an update is pending. Loading switches show an activity indicator and block further presses until loading ends. Disabled switches also block interaction.
|
|
@@ -4,6 +4,6 @@ import { SwitchProps } from '../types/switch.types.mjs';
|
|
|
4
4
|
import '@impulse-ui-native/primitives';
|
|
5
5
|
import '@impulse-ui-native/theme';
|
|
6
6
|
|
|
7
|
-
declare const Switch: react.MemoExoticComponent<({
|
|
7
|
+
declare const Switch: react.MemoExoticComponent<({ checked: checkedProp, defaultChecked, disabled, hitSlop, loading, onCheckedChange, onPress, size, style, variant, ...props }: SwitchProps) => react_jsx_runtime.JSX.Element>;
|
|
8
8
|
|
|
9
9
|
export { Switch };
|
|
@@ -8,7 +8,6 @@ import { useThemedStyles } from "@impulse-ui-native/theme";
|
|
|
8
8
|
import { useSwitchAnimation, useSwitchTokens } from "../hooks";
|
|
9
9
|
import { switchStyles } from "./switch.styles";
|
|
10
10
|
const Switch = memo(function Switch2({
|
|
11
|
-
accessibilityState,
|
|
12
11
|
checked: checkedProp,
|
|
13
12
|
defaultChecked = false,
|
|
14
13
|
disabled,
|
|
@@ -42,15 +41,6 @@ const Switch = memo(function Switch2({
|
|
|
42
41
|
colors,
|
|
43
42
|
sizeTokens
|
|
44
43
|
});
|
|
45
|
-
const resolvedAccessibilityState = useMemo(
|
|
46
|
-
() => ({
|
|
47
|
-
...accessibilityState,
|
|
48
|
-
busy: loading,
|
|
49
|
-
checked,
|
|
50
|
-
disabled: interactionDisabled
|
|
51
|
-
}),
|
|
52
|
-
[accessibilityState, checked, interactionDisabled, loading]
|
|
53
|
-
);
|
|
54
44
|
const switchStyle = useCallback(
|
|
55
45
|
(state) => StyleSheet.flatten([
|
|
56
46
|
styles.root,
|
|
@@ -77,8 +67,6 @@ const Switch = memo(function Switch2({
|
|
|
77
67
|
Pressable,
|
|
78
68
|
{
|
|
79
69
|
...props,
|
|
80
|
-
accessibilityRole: "switch",
|
|
81
|
-
accessibilityState: resolvedAccessibilityState,
|
|
82
70
|
disabled: interactionDisabled,
|
|
83
71
|
hitSlop: hitSlop ?? sizeTokens.hitSlop,
|
|
84
72
|
onPress: handlePress,
|
|
@@ -86,7 +74,6 @@ const Switch = memo(function Switch2({
|
|
|
86
74
|
children: /* @__PURE__ */ jsx(Animated.View, { pointerEvents: "none", style: trackAnimatedStyle, children: /* @__PURE__ */ jsx(Animated.View, { style: thumbAnimatedStyle, children: loading ? /* @__PURE__ */ jsx(
|
|
87
75
|
Spinner,
|
|
88
76
|
{
|
|
89
|
-
accessible: false,
|
|
90
77
|
color: loadingIndicatorColor,
|
|
91
78
|
size: "medium",
|
|
92
79
|
style: styles.loadingIndicator
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/switch.tsx"],"sourcesContent":["import type {\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/switch.tsx"],"sourcesContent":["import type {\n GestureResponderEvent,\n PressableStateCallbackType,\n StyleProp,\n ViewStyle,\n} from \"react-native\";\nimport { memo, useCallback, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport Animated from \"react-native-reanimated\";\n\nimport { useControllableState } from \"@impulse-ui-native/core\";\nimport { Pressable, Spinner } from \"@impulse-ui-native/primitives\";\nimport { useThemedStyles } from \"@impulse-ui-native/theme\";\n\nimport type { SwitchProps } from \"../types\";\nimport { useSwitchAnimation, useSwitchTokens } from \"../hooks\";\nimport { switchStyles } from \"./switch.styles\";\n\nexport const Switch = memo(function Switch({\n checked: checkedProp,\n defaultChecked = false,\n disabled,\n hitSlop,\n loading = false,\n onCheckedChange,\n onPress,\n size = \"medium\",\n style,\n variant = \"filled\",\n ...props\n}: SwitchProps) {\n const [checked, setChecked] = useControllableState<boolean>({\n prop: checkedProp,\n defaultProp: defaultChecked,\n onChange: onCheckedChange,\n });\n const interactionDisabled = disabled === true || loading;\n const {\n animationDuration,\n borderWidth,\n colors,\n loadingIndicatorColor,\n sizeTokens,\n } = useSwitchTokens({ disabled: interactionDisabled, size, variant });\n const styles = useThemedStyles(switchStyles, { size }, [size]);\n const { thumbStyle, trackStyle } = useSwitchAnimation({\n animationDuration,\n borderWidth,\n checked,\n colors,\n sizeTokens,\n });\n\n const switchStyle = useCallback(\n (state: PressableStateCallbackType): StyleProp<ViewStyle> =>\n StyleSheet.flatten([\n styles.root,\n typeof style === \"function\" ? style(state) : style,\n ]),\n [style, styles.root],\n );\n\n const handlePress = useCallback(\n (event: GestureResponderEvent) => {\n setChecked((current) => !current);\n onPress?.(event);\n },\n [onPress, setChecked],\n );\n\n const trackAnimatedStyle = useMemo(\n () => [styles.track, trackStyle],\n [styles.track, trackStyle],\n );\n\n const thumbAnimatedStyle = useMemo(\n () => [styles.thumb, thumbStyle],\n [styles.thumb, thumbStyle],\n );\n\n return (\n <Pressable\n {...props}\n disabled={interactionDisabled}\n hitSlop={hitSlop ?? sizeTokens.hitSlop}\n onPress={handlePress}\n style={switchStyle}\n >\n <Animated.View pointerEvents=\"none\" style={trackAnimatedStyle}>\n <Animated.View style={thumbAnimatedStyle}>\n {loading ? (\n <Spinner\n color={loadingIndicatorColor}\n size=\"medium\"\n style={styles.loadingIndicator}\n />\n ) : null}\n </Animated.View>\n </Animated.View>\n </Pressable>\n );\n});\n"],"mappings":"AA2FY;AArFZ,SAAS,MAAM,aAAa,eAAe;AAC3C,SAAS,kBAAkB;AAC3B,OAAO,cAAc;AAErB,SAAS,4BAA4B;AACrC,SAAS,WAAW,eAAe;AACnC,SAAS,uBAAuB;AAGhC,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,oBAAoB;AAEtB,MAAM,SAAS,KAAK,SAASA,QAAO;AAAA,EACzC,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA,UAAU;AAAA,EACV,GAAG;AACL,GAAgB;AACd,QAAM,CAAC,SAAS,UAAU,IAAI,qBAA8B;AAAA,IAC1D,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ,CAAC;AACD,QAAM,sBAAsB,aAAa,QAAQ;AACjD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,gBAAgB,EAAE,UAAU,qBAAqB,MAAM,QAAQ,CAAC;AACpE,QAAM,SAAS,gBAAgB,cAAc,EAAE,KAAK,GAAG,CAAC,IAAI,CAAC;AAC7D,QAAM,EAAE,YAAY,WAAW,IAAI,mBAAmB;AAAA,IACpD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,cAAc;AAAA,IAClB,CAAC,UACC,WAAW,QAAQ;AAAA,MACjB,OAAO;AAAA,MACP,OAAO,UAAU,aAAa,MAAM,KAAK,IAAI;AAAA,IAC/C,CAAC;AAAA,IACH,CAAC,OAAO,OAAO,IAAI;AAAA,EACrB;AAEA,QAAM,cAAc;AAAA,IAClB,CAAC,UAAiC;AAChC,iBAAW,CAAC,YAAY,CAAC,OAAO;AAChC,gBAAU,KAAK;AAAA,IACjB;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,EACtB;AAEA,QAAM,qBAAqB;AAAA,IACzB,MAAM,CAAC,OAAO,OAAO,UAAU;AAAA,IAC/B,CAAC,OAAO,OAAO,UAAU;AAAA,EAC3B;AAEA,QAAM,qBAAqB;AAAA,IACzB,MAAM,CAAC,OAAO,OAAO,UAAU;AAAA,IAC/B,CAAC,OAAO,OAAO,UAAU;AAAA,EAC3B;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,UAAU;AAAA,MACV,SAAS,WAAW,WAAW;AAAA,MAC/B,SAAS;AAAA,MACT,OAAO;AAAA,MAEP,8BAAC,SAAS,MAAT,EAAc,eAAc,QAAO,OAAO,oBACzC,8BAAC,SAAS,MAAT,EAAc,OAAO,oBACnB,oBACC;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,MAAK;AAAA,UACL,OAAO,OAAO;AAAA;AAAA,MAChB,IACE,MACN,GACF;AAAA;AAAA,EACF;AAEJ,CAAC;","names":["Switch"]}
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
Easing,
|
|
5
5
|
interpolateColor,
|
|
6
6
|
useAnimatedStyle,
|
|
7
|
-
useReducedMotion,
|
|
8
7
|
useSharedValue,
|
|
9
8
|
withTiming
|
|
10
9
|
} from "react-native-reanimated";
|
|
@@ -15,7 +14,6 @@ function useSwitchAnimation({
|
|
|
15
14
|
colors,
|
|
16
15
|
sizeTokens
|
|
17
16
|
}) {
|
|
18
|
-
const reduceMotion = useReducedMotion();
|
|
19
17
|
const progress = useSharedValue(checked ? 1 : 0);
|
|
20
18
|
const thumbTravel = sizeTokens.width - sizeTokens.thumbSize - sizeTokens.trackPadding * 2 - borderWidth * 2;
|
|
21
19
|
const direction = I18nManager.isRTL ? -1 : 1;
|
|
@@ -51,10 +49,10 @@ function useSwitchAnimation({
|
|
|
51
49
|
);
|
|
52
50
|
useEffect(() => {
|
|
53
51
|
progress.value = withTiming(checked ? 1 : 0, {
|
|
54
|
-
duration:
|
|
52
|
+
duration: animationDuration,
|
|
55
53
|
easing: Easing.out(Easing.cubic)
|
|
56
54
|
});
|
|
57
|
-
}, [animationDuration, checked, progress
|
|
55
|
+
}, [animationDuration, checked, progress]);
|
|
58
56
|
return useMemo(() => ({ thumbStyle, trackStyle }), [thumbStyle, trackStyle]);
|
|
59
57
|
}
|
|
60
58
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/use-switch-animation.hook.ts"],"sourcesContent":["import { useEffect, useMemo } from \"react\";\nimport { I18nManager } from \"react-native\";\nimport {\n Easing,\n interpolateColor,\n useAnimatedStyle,\n
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-switch-animation.hook.ts"],"sourcesContent":["import { useEffect, useMemo } from \"react\";\nimport { I18nManager } from \"react-native\";\nimport {\n Easing,\n interpolateColor,\n useAnimatedStyle,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\n\nimport type { SwitchSizeTokens } from \"@impulse-ui-native/theme\";\n\nimport type { SwitchAnimationColors } from \"./use-switch-tokens.hook\";\n\ninterface UseSwitchAnimationOptions {\n animationDuration: number;\n borderWidth: number;\n checked: boolean;\n colors: SwitchAnimationColors;\n sizeTokens: SwitchSizeTokens[keyof SwitchSizeTokens];\n}\n\nexport function useSwitchAnimation({\n animationDuration,\n borderWidth,\n checked,\n colors,\n sizeTokens,\n}: UseSwitchAnimationOptions) {\n const progress = useSharedValue(checked ? 1 : 0);\n\n const thumbTravel =\n sizeTokens.width -\n sizeTokens.thumbSize -\n sizeTokens.trackPadding * 2 -\n borderWidth * 2;\n const direction = I18nManager.isRTL ? -1 : 1;\n\n const trackStyle = useAnimatedStyle(\n () => ({\n backgroundColor: interpolateColor(\n progress.value,\n [0, 1],\n [colors.inactiveBackgroundColor, colors.activeBackgroundColor],\n ),\n borderColor: interpolateColor(\n progress.value,\n [0, 1],\n [colors.inactiveBorderColor, colors.activeBorderColor],\n ),\n }),\n [colors],\n );\n\n const thumbStyle = useAnimatedStyle(\n () => ({\n backgroundColor: interpolateColor(\n progress.value,\n [0, 1],\n [colors.inactiveThumbColor, colors.activeThumbColor],\n ),\n transform: [\n {\n translateX: progress.value * thumbTravel * direction,\n },\n ],\n }),\n [colors, direction, thumbTravel],\n );\n\n useEffect(() => {\n // Reanimated shared values are mutable handles updated from React effects.\n // eslint-disable-next-line react-hooks/immutability\n progress.value = withTiming(checked ? 1 : 0, {\n duration: animationDuration,\n easing: Easing.out(Easing.cubic),\n });\n }, [animationDuration, checked, progress]);\n\n return useMemo(() => ({ thumbStyle, trackStyle }), [thumbStyle, trackStyle]);\n}\n"],"mappings":"AAAA,SAAS,WAAW,eAAe;AACnC,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAcA,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA8B;AAC5B,QAAM,WAAW,eAAe,UAAU,IAAI,CAAC;AAE/C,QAAM,cACJ,WAAW,QACX,WAAW,YACX,WAAW,eAAe,IAC1B,cAAc;AAChB,QAAM,YAAY,YAAY,QAAQ,KAAK;AAE3C,QAAM,aAAa;AAAA,IACjB,OAAO;AAAA,MACL,iBAAiB;AAAA,QACf,SAAS;AAAA,QACT,CAAC,GAAG,CAAC;AAAA,QACL,CAAC,OAAO,yBAAyB,OAAO,qBAAqB;AAAA,MAC/D;AAAA,MACA,aAAa;AAAA,QACX,SAAS;AAAA,QACT,CAAC,GAAG,CAAC;AAAA,QACL,CAAC,OAAO,qBAAqB,OAAO,iBAAiB;AAAA,MACvD;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,aAAa;AAAA,IACjB,OAAO;AAAA,MACL,iBAAiB;AAAA,QACf,SAAS;AAAA,QACT,CAAC,GAAG,CAAC;AAAA,QACL,CAAC,OAAO,oBAAoB,OAAO,gBAAgB;AAAA,MACrD;AAAA,MACA,WAAW;AAAA,QACT;AAAA,UACE,YAAY,SAAS,QAAQ,cAAc;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,WAAW,WAAW;AAAA,EACjC;AAEA,YAAU,MAAM;AAGd,aAAS,QAAQ,WAAW,UAAU,IAAI,GAAG;AAAA,MAC3C,UAAU;AAAA,MACV,QAAQ,OAAO,IAAI,OAAO,KAAK;AAAA,IACjC,CAAC;AAAA,EACH,GAAG,CAAC,mBAAmB,SAAS,QAAQ,CAAC;AAEzC,SAAO,QAAQ,OAAO,EAAE,YAAY,WAAW,IAAI,CAAC,YAAY,UAAU,CAAC;AAC7E;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@impulse-ui-native/switch",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Animated switch controls for ImpulseUI Native applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@impulse-ui-native/
|
|
33
|
-
"@impulse-ui-native/
|
|
34
|
-
"@impulse-ui-native/theme": "
|
|
32
|
+
"@impulse-ui-native/primitives": "5.0.0",
|
|
33
|
+
"@impulse-ui-native/core": "5.0.0",
|
|
34
|
+
"@impulse-ui-native/theme": "5.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/react": "~19.2.14",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"react-native-worklets": "0.10.1",
|
|
44
44
|
"typescript": "~6.0.3",
|
|
45
45
|
"@impulse-ui-native/eslint-config": "1.0.0",
|
|
46
|
-
"@impulse-ui-native/
|
|
47
|
-
"@impulse-ui-native/
|
|
46
|
+
"@impulse-ui-native/tsconfig": "1.0.0",
|
|
47
|
+
"@impulse-ui-native/prettier-config": "1.0.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"react": ">=18",
|