@minkyumdev/react-native-switch 1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 minkyumdev
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.
22
+
package/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # @minkyumdev/react-native-switch
2
+
3
+ A customizable and animated switch component for React Native built with `react-native-reanimated`.
4
+
5
+ ## Features
6
+
7
+ - 🎨 Fully customizable colors and sizes
8
+ - ✨ Smooth animations powered by react-native-reanimated
9
+ - 🎯 Customizable thumb scale animation
10
+ - 📳 Haptic feedback support (optional)
11
+ - ♿ Accessible and disabled state support
12
+ - 📱 Works on both iOS and Android
13
+ - 💪 Written in TypeScript with full type definitions
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @minkyumdev/react-native-switch
19
+ # or
20
+ yarn add @minkyumdev/react-native-switch
21
+ ```
22
+
23
+ ### Peer Dependencies
24
+
25
+ This library requires the following peer dependencies:
26
+
27
+ - `react` (>=16.8.0)
28
+ - `react-native` (>=0.60.0)
29
+ - `react-native-reanimated` (>=2.0.0)
30
+ - `@mhpdev/react-native-haptics` (optional, for haptic feedback)
31
+
32
+ Make sure to install these dependencies in your project:
33
+
34
+ ```bash
35
+ npm install react-native-reanimated
36
+ npm install @mhpdev/react-native-haptics
37
+ ```
38
+
39
+ ### iOS Setup
40
+
41
+ For iOS, you need to install pods:
42
+
43
+ ```bash
44
+ cd ios && pod install
45
+ ```
46
+
47
+ ### Android Setup
48
+
49
+ No additional setup required for Android.
50
+
51
+ ## Usage
52
+
53
+ ```tsx
54
+ import React, { useState } from 'react';
55
+ import { View } from 'react-native';
56
+ import Switch from '@minkyumdev/react-native-switch';
57
+
58
+ function App() {
59
+ const [isEnabled, setIsEnabled] = useState(false);
60
+
61
+ return (
62
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
63
+ <Switch
64
+ value={isEnabled}
65
+ onValueChange={setIsEnabled}
66
+ activeColor="#34C759"
67
+ inactiveColor="#E5E5EA"
68
+ />
69
+ </View>
70
+ );
71
+ }
72
+ ```
73
+
74
+ ## Props
75
+
76
+ | Prop | Type | Default | Description |
77
+ | -------------------- | -------------------------------- | ----------- | -------------------------------------------------------------- |
78
+ | `value` | `boolean` | `false` | Current state of the switch (on/off) |
79
+ | `onValueChange` | `(value: boolean) => void` | - | Callback function called when the switch value changes |
80
+ | `disabled` | `boolean` | `false` | Whether the switch is disabled |
81
+ | `activeColor` | `string` | `'#34C759'` | Color of the switch when active (on) |
82
+ | `inactiveColor` | `string` | `'#F6F6F6'` | Color of the switch when inactive (off) |
83
+ | `thumbColor` | `string` | `'#FFFFFF'` | Color of the thumb (the circular element) |
84
+ | `size` | `'small' \| 'medium' \| 'large'` | `'small'` | Predefined size of the switch (used when width/height not set) |
85
+ | `width` | `number` | - | Custom width of the switch (takes priority over size) |
86
+ | `height` | `number` | - | Custom height of the switch (takes priority over size) |
87
+ | `thumbSize` | `number` | - | Custom size of the thumb (auto-calculated if not provided) |
88
+ | `thumbScaleInactive` | `number` | `0.8` | Scale value of the thumb when inactive (off state) |
89
+ | `enableHaptics` | `boolean` | `true` | Whether to enable haptic feedback on toggle |
90
+ | `style` | `StyleProp<ViewStyle>` | - | Additional style for the switch container |
91
+ | `testID` | `string` | - | Test ID for testing purposes |
92
+
93
+ ## Examples
94
+
95
+ ### Basic Usage
96
+
97
+ ```tsx
98
+ <Switch value={isEnabled} onValueChange={setIsEnabled} />
99
+ ```
100
+
101
+ ### Custom Colors
102
+
103
+ ```tsx
104
+ <Switch
105
+ value={isEnabled}
106
+ onValueChange={setIsEnabled}
107
+ activeColor="#FF3B30"
108
+ inactiveColor="#C7C7CC"
109
+ thumbColor="#FFFFFF"
110
+ />
111
+ ```
112
+
113
+ ### Custom Size
114
+
115
+ ```tsx
116
+ // Using predefined sizes
117
+ <Switch value={isEnabled} onValueChange={setIsEnabled} size="large" />
118
+
119
+ // Using custom width and height
120
+ <Switch
121
+ value={isEnabled}
122
+ onValueChange={setIsEnabled}
123
+ width={80}
124
+ height={40}
125
+ />
126
+
127
+ // Custom width, height, and thumbSize
128
+ <Switch
129
+ value={isEnabled}
130
+ onValueChange={setIsEnabled}
131
+ width={100}
132
+ height={50}
133
+ thumbSize={35}
134
+ />
135
+ ```
136
+
137
+ ### Disabled State
138
+
139
+ ```tsx
140
+ <Switch value={isEnabled} onValueChange={setIsEnabled} disabled={true} />
141
+ ```
142
+
143
+ ### Disable Haptics
144
+
145
+ ```tsx
146
+ <Switch value={isEnabled} onValueChange={setIsEnabled} enableHaptics={false} />
147
+ ```
148
+
149
+ ### Custom Thumb Scale
150
+
151
+ ```tsx
152
+ // Custom scale for inactive state (default is 0.8)
153
+ <Switch
154
+ value={isEnabled}
155
+ onValueChange={setIsEnabled}
156
+ thumbScaleInactive={0.7} // Thumb will be smaller when off
157
+ />
158
+ ```
159
+
160
+ ## Development
161
+
162
+ ```bash
163
+ # Install dependencies
164
+ npm install
165
+
166
+ # Build the library
167
+ npm run build
168
+
169
+ # Watch mode for development
170
+ npm run build:watch
171
+ ```
172
+
173
+ ## API Reference
174
+
175
+ ### Switch Component
176
+
177
+ The main component exported from this library.
178
+
179
+ #### Props
180
+
181
+ See the [Props](#props) table above for detailed information.
182
+
183
+ #### Example
184
+
185
+ ```tsx
186
+ import Switch from '@minkyumdev/react-native-switch';
187
+
188
+ function MyComponent() {
189
+ const [enabled, setEnabled] = useState(false);
190
+
191
+ return (
192
+ <Switch
193
+ value={enabled}
194
+ onValueChange={setEnabled}
195
+ size="medium"
196
+ activeColor="#34C759"
197
+ inactiveColor="#E5E5EA"
198
+ />
199
+ );
200
+ }
201
+ ```
202
+
203
+ ## License
204
+
205
+ MIT
206
+
207
+ ## Contributing
208
+
209
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,93 @@
1
+ import React from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ export interface SwitchProps {
4
+ /**
5
+ * Current state of the switch (on/off)
6
+ */
7
+ value: boolean;
8
+ /**
9
+ * Callback function called when the switch value changes
10
+ */
11
+ onValueChange?: (value: boolean) => void;
12
+ /**
13
+ * Whether the switch is disabled
14
+ * @default false
15
+ */
16
+ disabled?: boolean;
17
+ /**
18
+ * Color of the switch when active (on)
19
+ * @default '#34C759'
20
+ */
21
+ activeColor?: string;
22
+ /**
23
+ * Color of the switch when inactive (off)
24
+ * @default '#F6F6F6'
25
+ */
26
+ inactiveColor?: string;
27
+ /**
28
+ * Color of the thumb (the circular element)
29
+ * @default '#FFFFFF'
30
+ */
31
+ thumbColor?: string;
32
+ /**
33
+ * Predefined size of the switch (used when width/height not set)
34
+ * @default 'small'
35
+ */
36
+ size?: 'small' | 'medium' | 'large';
37
+ /**
38
+ * Custom width of the switch (takes priority over size)
39
+ */
40
+ width?: number;
41
+ /**
42
+ * Custom height of the switch (takes priority over size)
43
+ */
44
+ height?: number;
45
+ /**
46
+ * Custom size of the thumb (auto-calculated if not provided)
47
+ */
48
+ thumbSize?: number;
49
+ /**
50
+ * Additional style for the switch container
51
+ */
52
+ style?: StyleProp<ViewStyle>;
53
+ /**
54
+ * Test ID for testing purposes
55
+ */
56
+ testID?: string;
57
+ /**
58
+ * Whether to enable haptic feedback on toggle
59
+ * @default true
60
+ */
61
+ enableHaptics?: boolean;
62
+ /**
63
+ * Scale value of the thumb when inactive (off state)
64
+ * @default 0.8
65
+ */
66
+ thumbScaleInactive?: number;
67
+ }
68
+ export declare const SWITCH_ANIMATION_DURATION = 150;
69
+ /**
70
+ * React Native용 커스텀 Switch 컴포넌트
71
+ * react-native-reanimated를 사용한 부드러운 애니메이션과 햅틱 피드백을 제공합니다.
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * import Switch from 'react-native-switch';
76
+ *
77
+ * function App() {
78
+ * const [isEnabled, setIsEnabled] = useState(false);
79
+ *
80
+ * return (
81
+ * <Switch
82
+ * value={isEnabled}
83
+ * onValueChange={setIsEnabled}
84
+ * size="medium"
85
+ * activeColor="#20A2F9"
86
+ * />
87
+ * );
88
+ * }
89
+ * ```
90
+ */
91
+ export declare const Switch: React.FC<SwitchProps>;
92
+ export default Switch;
93
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0C,MAAM,OAAO,CAAC;AAC/D,OAAO,EAAa,SAAS,EAAE,SAAS,EAAc,MAAM,cAAc,CAAC;AAe3E,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAYD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAY7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAwJxC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,138 @@
1
+ import React, { useCallback, useEffect, useMemo } from 'react';
2
+ import { Pressable, PixelRatio } from 'react-native';
3
+ import Animated, { interpolateColor, useAnimatedStyle, useSharedValue, withTiming, } from 'react-native-reanimated';
4
+ import Haptics from '@mhpdev/react-native-haptics';
5
+ import { styles } from './style';
6
+ // Helper function for pixel ratio
7
+ var pixelRatio = function (value) {
8
+ return PixelRatio.roundToNearestPixel(value);
9
+ };
10
+ var SWITCH_CONFIG = {
11
+ small: { width: 40, height: 24, thumbSize: 14 },
12
+ medium: { width: 50, height: 32, thumbSize: 20 },
13
+ large: { width: 60, height: 36, thumbSize: 26 },
14
+ };
15
+ // Thumb scale constants
16
+ var THUMB_SCALE_ACTIVE = 1.0;
17
+ // Animation constants
18
+ export var SWITCH_ANIMATION_DURATION = 150;
19
+ var ANIMATION_CONFIG = {
20
+ duration: SWITCH_ANIMATION_DURATION,
21
+ };
22
+ // Track padding
23
+ var TRACK_PADDING = 4;
24
+ // TranslateX values
25
+ var TRANSLATE_X_INACTIVE = 0;
26
+ var TRANSLATE_X_ACTIVE = 1;
27
+ /**
28
+ * React Native용 커스텀 Switch 컴포넌트
29
+ * react-native-reanimated를 사용한 부드러운 애니메이션과 햅틱 피드백을 제공합니다.
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * import Switch from 'react-native-switch';
34
+ *
35
+ * function App() {
36
+ * const [isEnabled, setIsEnabled] = useState(false);
37
+ *
38
+ * return (
39
+ * <Switch
40
+ * value={isEnabled}
41
+ * onValueChange={setIsEnabled}
42
+ * size="medium"
43
+ * activeColor="#20A2F9"
44
+ * />
45
+ * );
46
+ * }
47
+ * ```
48
+ */
49
+ export var Switch = React.memo(function (_a) {
50
+ var value = _a.value, onValueChange = _a.onValueChange, _b = _a.disabled, disabled = _b === void 0 ? false : _b, _c = _a.activeColor, activeColor = _c === void 0 ? '#34C759' : _c, _d = _a.inactiveColor, inactiveColor = _d === void 0 ? '#F6F6F6' : _d, _e = _a.thumbColor, thumbColor = _e === void 0 ? '#FFFFFF' : _e, _f = _a.size, size = _f === void 0 ? 'small' : _f, width = _a.width, height = _a.height, thumbSize = _a.thumbSize, style = _a.style, testID = _a.testID, _g = _a.enableHaptics, enableHaptics = _g === void 0 ? true : _g, _h = _a.thumbScaleInactive, thumbScaleInactive = _h === void 0 ? 0.8 : _h;
51
+ var translateX = useSharedValue(value ? TRANSLATE_X_ACTIVE : TRANSLATE_X_INACTIVE);
52
+ var switchConfig = useMemo(function () {
53
+ if (width !== undefined || height !== undefined) {
54
+ var configWidth = width !== null && width !== void 0 ? width : SWITCH_CONFIG[size].width;
55
+ var configHeight = height !== null && height !== void 0 ? height : SWITCH_CONFIG[size].height;
56
+ var calculatedThumbSize_1 = thumbSize !== null && thumbSize !== void 0 ? thumbSize : configHeight * 0.7;
57
+ return {
58
+ width: configWidth,
59
+ height: configHeight,
60
+ thumbSize: calculatedThumbSize_1,
61
+ };
62
+ }
63
+ return SWITCH_CONFIG[size];
64
+ }, [size, width, height, thumbSize]);
65
+ var thumbScaleActive = THUMB_SCALE_ACTIVE;
66
+ var thumbScaleDiff = thumbScaleActive - thumbScaleInactive;
67
+ var scaleOffsetPadding = useMemo(function () { return (switchConfig.thumbSize * (1 - thumbScaleInactive)) / 2; }, [switchConfig.thumbSize, thumbScaleInactive]);
68
+ var maxTranslate = useMemo(function () {
69
+ return switchConfig.width - switchConfig.thumbSize - TRACK_PADDING * 2;
70
+ }, [switchConfig.width, switchConfig.thumbSize]);
71
+ useEffect(function () {
72
+ translateX.value = withTiming(value ? TRANSLATE_X_ACTIVE : TRANSLATE_X_INACTIVE, ANIMATION_CONFIG);
73
+ }, [value, translateX]);
74
+ var handlePress = useCallback(function () {
75
+ if (disabled)
76
+ return;
77
+ if (enableHaptics) {
78
+ Haptics.impact('soft');
79
+ }
80
+ var newValue = !value;
81
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(newValue);
82
+ }, [disabled, value, onValueChange, enableHaptics]);
83
+ var trackAnimatedStyle = useAnimatedStyle(function () {
84
+ var backgroundColor = interpolateColor(translateX.value, [0, 1], [inactiveColor, activeColor]);
85
+ return {
86
+ backgroundColor: backgroundColor,
87
+ };
88
+ }, [inactiveColor, activeColor]);
89
+ var thumbAnimatedStyle = useAnimatedStyle(function () {
90
+ var scale = thumbScaleInactive + translateX.value * thumbScaleDiff;
91
+ var currentScaleOffset = scaleOffsetPadding * (1 - translateX.value);
92
+ var baseTranslateX = TRACK_PADDING + translateX.value * maxTranslate;
93
+ var translateXValue = baseTranslateX - currentScaleOffset;
94
+ return {
95
+ transform: [
96
+ {
97
+ translateX: translateXValue,
98
+ },
99
+ {
100
+ scale: scale,
101
+ },
102
+ ],
103
+ };
104
+ }, [maxTranslate, scaleOffsetPadding, thumbScaleInactive, thumbScaleDiff]);
105
+ var trackStyle = useMemo(function () { return ({
106
+ width: switchConfig.width,
107
+ height: switchConfig.height,
108
+ borderRadius: switchConfig.height / 2,
109
+ opacity: disabled ? 0.5 : 1,
110
+ }); }, [switchConfig.width, switchConfig.height, disabled]);
111
+ var calculatedThumbSize = useMemo(function () { return pixelRatio(switchConfig.thumbSize); }, [switchConfig.thumbSize]);
112
+ var thumbStyle = useMemo(function () { return ({
113
+ width: calculatedThumbSize,
114
+ height: calculatedThumbSize,
115
+ borderRadius: pixelRatio(switchConfig.thumbSize / 2),
116
+ backgroundColor: thumbColor,
117
+ }); }, [calculatedThumbSize, switchConfig.thumbSize, thumbColor]);
118
+ return (<Pressable onPress={handlePress} disabled={disabled} style={[style]} testID={testID}>
119
+ <Animated.View style={[styles.track, trackAnimatedStyle, trackStyle]}>
120
+ <Animated.View style={[styles.thumb, thumbAnimatedStyle, thumbStyle]}/>
121
+ </Animated.View>
122
+ </Pressable>);
123
+ }, function (prevProps, nextProps) {
124
+ // Custom comparison for React.memo - prevent unnecessary re-renders
125
+ return (prevProps.value === nextProps.value &&
126
+ prevProps.disabled === nextProps.disabled &&
127
+ prevProps.activeColor === nextProps.activeColor &&
128
+ prevProps.inactiveColor === nextProps.inactiveColor &&
129
+ prevProps.thumbColor === nextProps.thumbColor &&
130
+ prevProps.size === nextProps.size &&
131
+ prevProps.width === nextProps.width &&
132
+ prevProps.height === nextProps.height &&
133
+ prevProps.thumbSize === nextProps.thumbSize &&
134
+ prevProps.enableHaptics === nextProps.enableHaptics &&
135
+ prevProps.onValueChange === nextProps.onValueChange);
136
+ });
137
+ export default Switch;
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare const styles: {
2
+ track: {
3
+ justifyContent: "center";
4
+ };
5
+ thumb: {
6
+ shadowColor: string;
7
+ shadowOffset: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ shadowOpacity: number;
12
+ shadowRadius: number;
13
+ elevation: number;
14
+ };
15
+ };
16
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;CAejB,CAAC"}
package/dist/style.js ADDED
@@ -0,0 +1,18 @@
1
+ import { StyleSheet } from 'react-native';
2
+ export var styles = StyleSheet.create({
3
+ track: {
4
+ justifyContent: 'center',
5
+ // padding: 2,
6
+ },
7
+ thumb: {
8
+ shadowColor: '#000',
9
+ shadowOffset: {
10
+ width: 0,
11
+ height: 2,
12
+ },
13
+ shadowOpacity: 0.1,
14
+ shadowRadius: 2,
15
+ elevation: 2,
16
+ },
17
+ });
18
+ //# sourceMappingURL=style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.js","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,IAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IACtC,KAAK,EAAE;QACL,cAAc,EAAE,QAAQ;QACxB,cAAc;KACf;IACD,KAAK,EAAE;QACL,WAAW,EAAE,MAAM;QACnB,YAAY,EAAE;YACZ,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;SACV;QACD,aAAa,EAAE,GAAG;QAClB,YAAY,EAAE,CAAC;QACf,SAAS,EAAE,CAAC;KACb;CACF,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@minkyumdev/react-native-switch",
3
+ "version": "1.0.0",
4
+ "description": "A customizable switch component for React Native",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "src",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "keywords": [
14
+ "react-native",
15
+ "switch",
16
+ "toggle",
17
+ "component",
18
+ "ui"
19
+ ],
20
+ "author": "",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/minkyumdev/react-native-switch.git"
25
+ },
26
+ "scripts": {
27
+ "build": "rm -rf dist && tsc",
28
+ "build:watch": "rm -rf dist && tsc -w",
29
+ "prepublishOnly": "npm run build",
30
+ "android": "react-native run-android",
31
+ "ios": "react-native run-ios",
32
+ "lint": "eslint .",
33
+ "start": "react-native start",
34
+ "test": "jest"
35
+ },
36
+ "peerDependencies": {
37
+ "@mhpdev/react-native-haptics": "*",
38
+ "react": ">=16.8.0",
39
+ "react-native": ">=0.60.0",
40
+ "react-native-reanimated": ">=2.0.0"
41
+ },
42
+ "dependencies": {},
43
+ "devDependencies": {
44
+ "@babel/core": "^7.25.2",
45
+ "@babel/preset-env": "^7.25.3",
46
+ "@babel/runtime": "^7.25.0",
47
+ "@mhpdev/react-native-haptics": "1.0.1",
48
+ "@react-native-community/cli": "20.0.0",
49
+ "@react-native-community/cli-platform-android": "20.0.0",
50
+ "@react-native-community/cli-platform-ios": "20.0.0",
51
+ "@react-native/babel-preset": "0.82.1",
52
+ "@react-native/eslint-config": "0.82.1",
53
+ "@react-native/metro-config": "0.82.1",
54
+ "@react-native/typescript-config": "0.82.1",
55
+ "@types/jest": "^29.5.13",
56
+ "@types/react": "^19.1.1",
57
+ "@types/react-test-renderer": "^19.1.0",
58
+ "eslint": "^8.19.0",
59
+ "jest": "^29.6.3",
60
+ "prettier": "2.8.8",
61
+ "react-native-reanimated": "4.1.3",
62
+ "react-native-worklets": "0.6.1",
63
+ "react-test-renderer": "19.1.1",
64
+ "typescript": "^5.8.3"
65
+ },
66
+ "engines": {
67
+ "node": ">=20"
68
+ }
69
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,281 @@
1
+ import React, { useCallback, useEffect, useMemo } from 'react';
2
+ import { Pressable, StyleProp, ViewStyle, PixelRatio } from 'react-native';
3
+ import Animated, {
4
+ interpolateColor,
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ withTiming,
8
+ } from 'react-native-reanimated';
9
+ import Haptics from '@mhpdev/react-native-haptics';
10
+ import { styles } from './style';
11
+
12
+ // Helper function for pixel ratio
13
+ const pixelRatio = (value: number): number => {
14
+ return PixelRatio.roundToNearestPixel(value);
15
+ };
16
+
17
+ export interface SwitchProps {
18
+ /**
19
+ * Current state of the switch (on/off)
20
+ */
21
+ value: boolean;
22
+ /**
23
+ * Callback function called when the switch value changes
24
+ */
25
+ onValueChange?: (value: boolean) => void;
26
+ /**
27
+ * Whether the switch is disabled
28
+ * @default false
29
+ */
30
+ disabled?: boolean;
31
+ /**
32
+ * Color of the switch when active (on)
33
+ * @default '#34C759'
34
+ */
35
+ activeColor?: string;
36
+ /**
37
+ * Color of the switch when inactive (off)
38
+ * @default '#F6F6F6'
39
+ */
40
+ inactiveColor?: string;
41
+ /**
42
+ * Color of the thumb (the circular element)
43
+ * @default '#FFFFFF'
44
+ */
45
+ thumbColor?: string;
46
+ /**
47
+ * Predefined size of the switch (used when width/height not set)
48
+ * @default 'small'
49
+ */
50
+ size?: 'small' | 'medium' | 'large';
51
+ /**
52
+ * Custom width of the switch (takes priority over size)
53
+ */
54
+ width?: number;
55
+ /**
56
+ * Custom height of the switch (takes priority over size)
57
+ */
58
+ height?: number;
59
+ /**
60
+ * Custom size of the thumb (auto-calculated if not provided)
61
+ */
62
+ thumbSize?: number;
63
+ /**
64
+ * Additional style for the switch container
65
+ */
66
+ style?: StyleProp<ViewStyle>;
67
+ /**
68
+ * Test ID for testing purposes
69
+ */
70
+ testID?: string;
71
+ /**
72
+ * Whether to enable haptic feedback on toggle
73
+ * @default true
74
+ */
75
+ enableHaptics?: boolean;
76
+ /**
77
+ * Scale value of the thumb when inactive (off state)
78
+ * @default 0.8
79
+ */
80
+ thumbScaleInactive?: number;
81
+ }
82
+
83
+ const SWITCH_CONFIG = {
84
+ small: { width: 40, height: 24, thumbSize: 14 },
85
+ medium: { width: 50, height: 32, thumbSize: 20 },
86
+ large: { width: 60, height: 36, thumbSize: 26 },
87
+ };
88
+
89
+ // Thumb scale constants
90
+ const THUMB_SCALE_ACTIVE = 1.0;
91
+
92
+ // Animation constants
93
+ export const SWITCH_ANIMATION_DURATION = 150;
94
+ const ANIMATION_CONFIG = {
95
+ duration: SWITCH_ANIMATION_DURATION,
96
+ };
97
+
98
+ // Track padding
99
+ const TRACK_PADDING = 4;
100
+
101
+ // TranslateX values
102
+ const TRANSLATE_X_INACTIVE = 0;
103
+ const TRANSLATE_X_ACTIVE = 1;
104
+
105
+ /**
106
+ * React Native용 커스텀 Switch 컴포넌트
107
+ * react-native-reanimated를 사용한 부드러운 애니메이션과 햅틱 피드백을 제공합니다.
108
+ *
109
+ * @example
110
+ * ```tsx
111
+ * import Switch from 'react-native-switch';
112
+ *
113
+ * function App() {
114
+ * const [isEnabled, setIsEnabled] = useState(false);
115
+ *
116
+ * return (
117
+ * <Switch
118
+ * value={isEnabled}
119
+ * onValueChange={setIsEnabled}
120
+ * size="medium"
121
+ * activeColor="#20A2F9"
122
+ * />
123
+ * );
124
+ * }
125
+ * ```
126
+ */
127
+ export const Switch: React.FC<SwitchProps> = React.memo<SwitchProps>(
128
+ ({
129
+ value,
130
+ onValueChange,
131
+ disabled = false,
132
+ activeColor = '#34C759',
133
+ inactiveColor = '#F6F6F6',
134
+ thumbColor = '#FFFFFF',
135
+ size = 'small',
136
+ width,
137
+ height,
138
+ thumbSize,
139
+ style,
140
+ testID,
141
+ enableHaptics = true,
142
+ thumbScaleInactive = 0.8,
143
+ }) => {
144
+ const translateX = useSharedValue(
145
+ value ? TRANSLATE_X_ACTIVE : TRANSLATE_X_INACTIVE,
146
+ );
147
+
148
+ const switchConfig = useMemo(() => {
149
+ if (width !== undefined || height !== undefined) {
150
+ const configWidth = width ?? SWITCH_CONFIG[size].width;
151
+ const configHeight = height ?? SWITCH_CONFIG[size].height;
152
+ const calculatedThumbSize = thumbSize ?? configHeight * 0.7;
153
+ return {
154
+ width: configWidth,
155
+ height: configHeight,
156
+ thumbSize: calculatedThumbSize,
157
+ };
158
+ }
159
+ return SWITCH_CONFIG[size];
160
+ }, [size, width, height, thumbSize]);
161
+
162
+ const thumbScaleActive = THUMB_SCALE_ACTIVE;
163
+ const thumbScaleDiff = thumbScaleActive - thumbScaleInactive;
164
+
165
+ const scaleOffsetPadding = useMemo(
166
+ () => (switchConfig.thumbSize * (1 - thumbScaleInactive)) / 2,
167
+ [switchConfig.thumbSize, thumbScaleInactive],
168
+ );
169
+
170
+ const maxTranslate = useMemo(() => {
171
+ return switchConfig.width - switchConfig.thumbSize - TRACK_PADDING * 2;
172
+ }, [switchConfig.width, switchConfig.thumbSize]);
173
+
174
+ useEffect(() => {
175
+ translateX.value = withTiming(
176
+ value ? TRANSLATE_X_ACTIVE : TRANSLATE_X_INACTIVE,
177
+ ANIMATION_CONFIG,
178
+ );
179
+ }, [value, translateX]);
180
+
181
+ const handlePress = useCallback(() => {
182
+ if (disabled) return;
183
+ if (enableHaptics) {
184
+ Haptics.impact('soft');
185
+ }
186
+ const newValue = !value;
187
+ onValueChange?.(newValue);
188
+ }, [disabled, value, onValueChange, enableHaptics]);
189
+
190
+ const trackAnimatedStyle = useAnimatedStyle(() => {
191
+ const backgroundColor = interpolateColor(
192
+ translateX.value,
193
+ [0, 1],
194
+ [inactiveColor, activeColor],
195
+ );
196
+
197
+ return {
198
+ backgroundColor,
199
+ };
200
+ }, [inactiveColor, activeColor]);
201
+
202
+ const thumbAnimatedStyle = useAnimatedStyle(() => {
203
+ const scale = thumbScaleInactive + translateX.value * thumbScaleDiff;
204
+
205
+ const currentScaleOffset = scaleOffsetPadding * (1 - translateX.value);
206
+
207
+ const baseTranslateX = TRACK_PADDING + translateX.value * maxTranslate;
208
+
209
+ const translateXValue = baseTranslateX - currentScaleOffset;
210
+
211
+ return {
212
+ transform: [
213
+ {
214
+ translateX: translateXValue,
215
+ },
216
+ {
217
+ scale,
218
+ },
219
+ ],
220
+ };
221
+ }, [maxTranslate, scaleOffsetPadding, thumbScaleInactive, thumbScaleDiff]);
222
+
223
+ const trackStyle = useMemo(
224
+ () => ({
225
+ width: switchConfig.width,
226
+ height: switchConfig.height,
227
+ borderRadius: switchConfig.height / 2,
228
+ opacity: disabled ? 0.5 : 1,
229
+ }),
230
+ [switchConfig.width, switchConfig.height, disabled],
231
+ );
232
+
233
+ const calculatedThumbSize = useMemo(
234
+ () => pixelRatio(switchConfig.thumbSize),
235
+ [switchConfig.thumbSize],
236
+ );
237
+
238
+ const thumbStyle = useMemo(
239
+ () => ({
240
+ width: calculatedThumbSize,
241
+ height: calculatedThumbSize,
242
+ borderRadius: pixelRatio(switchConfig.thumbSize / 2),
243
+ backgroundColor: thumbColor,
244
+ }),
245
+ [calculatedThumbSize, switchConfig.thumbSize, thumbColor],
246
+ );
247
+
248
+ return (
249
+ <Pressable
250
+ onPress={handlePress}
251
+ disabled={disabled}
252
+ style={[style]}
253
+ testID={testID}
254
+ >
255
+ <Animated.View style={[styles.track, trackAnimatedStyle, trackStyle]}>
256
+ <Animated.View
257
+ style={[styles.thumb, thumbAnimatedStyle, thumbStyle]}
258
+ />
259
+ </Animated.View>
260
+ </Pressable>
261
+ );
262
+ },
263
+ (prevProps, nextProps) => {
264
+ // Custom comparison for React.memo - prevent unnecessary re-renders
265
+ return (
266
+ prevProps.value === nextProps.value &&
267
+ prevProps.disabled === nextProps.disabled &&
268
+ prevProps.activeColor === nextProps.activeColor &&
269
+ prevProps.inactiveColor === nextProps.inactiveColor &&
270
+ prevProps.thumbColor === nextProps.thumbColor &&
271
+ prevProps.size === nextProps.size &&
272
+ prevProps.width === nextProps.width &&
273
+ prevProps.height === nextProps.height &&
274
+ prevProps.thumbSize === nextProps.thumbSize &&
275
+ prevProps.enableHaptics === nextProps.enableHaptics &&
276
+ prevProps.onValueChange === nextProps.onValueChange
277
+ );
278
+ },
279
+ );
280
+
281
+ export default Switch;
package/src/style.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const styles = StyleSheet.create({
4
+ track: {
5
+ justifyContent: 'center',
6
+ // padding: 2,
7
+ },
8
+ thumb: {
9
+ shadowColor: '#000',
10
+ shadowOffset: {
11
+ width: 0,
12
+ height: 2,
13
+ },
14
+ shadowOpacity: 0.1,
15
+ shadowRadius: 2,
16
+ elevation: 2,
17
+ },
18
+ });