@xaui/native 0.0.6 → 0.0.8

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.
@@ -0,0 +1,357 @@
1
+ import {
2
+ useXUITheme
3
+ } from "../chunk-ORMNMNOK.js";
4
+
5
+ // src/components/switch/switch.tsx
6
+ import React, { useEffect, useMemo as useMemo2, useRef, useState } from "react";
7
+ import { Animated as Animated2, Pressable, Text, View } from "react-native";
8
+
9
+ // src/components/switch/switch.hook.ts
10
+ import { useMemo } from "react";
11
+ import { getSafeThemeColor } from "@xaui/core";
12
+ var useSwitchColorScheme = (themeColor) => {
13
+ const theme = useXUITheme();
14
+ const safeThemeColor = getSafeThemeColor(themeColor);
15
+ return theme.colors[safeThemeColor];
16
+ };
17
+ var useSwitchSizeStyles = (variant, size) => {
18
+ const theme = useXUITheme();
19
+ const sizeStyles = useMemo(() => {
20
+ if (variant === "overlap") {
21
+ const sizes2 = {
22
+ sm: {
23
+ trackWidth: 40,
24
+ trackHeight: 16,
25
+ thumbSize: 22,
26
+ fontSize: theme.fontSizes.sm,
27
+ padding: 0
28
+ },
29
+ md: {
30
+ trackWidth: 48,
31
+ trackHeight: 18,
32
+ thumbSize: 26,
33
+ fontSize: theme.fontSizes.md,
34
+ padding: 0
35
+ },
36
+ lg: {
37
+ trackWidth: 56,
38
+ trackHeight: 20,
39
+ thumbSize: 30,
40
+ fontSize: theme.fontSizes.lg,
41
+ padding: 0
42
+ }
43
+ };
44
+ return sizes2[size];
45
+ }
46
+ const sizes = {
47
+ sm: {
48
+ trackWidth: 40,
49
+ trackHeight: 24,
50
+ thumbSize: 18,
51
+ fontSize: theme.fontSizes.sm,
52
+ padding: 3
53
+ },
54
+ md: {
55
+ trackWidth: 48,
56
+ trackHeight: 28,
57
+ thumbSize: 22,
58
+ fontSize: theme.fontSizes.md,
59
+ padding: 3
60
+ },
61
+ lg: {
62
+ trackWidth: 56,
63
+ trackHeight: 32,
64
+ thumbSize: 26,
65
+ fontSize: theme.fontSizes.lg,
66
+ padding: 3
67
+ }
68
+ };
69
+ return sizes[size];
70
+ }, [size, theme, variant]);
71
+ return sizeStyles;
72
+ };
73
+ var useSwitchRadiusStyles = (radius) => {
74
+ const theme = useXUITheme();
75
+ const radiusStyles = useMemo(() => {
76
+ const radii = {
77
+ none: theme.borderRadius.none,
78
+ sm: theme.borderRadius.sm,
79
+ md: theme.borderRadius.md,
80
+ lg: theme.borderRadius.lg,
81
+ full: theme.borderRadius.full
82
+ };
83
+ return { borderRadius: radii[radius] };
84
+ }, [radius, theme]);
85
+ const thumbRadius = useMemo(() => {
86
+ const radii = {
87
+ none: theme.borderRadius.none,
88
+ sm: theme.borderRadius.sm,
89
+ md: theme.borderRadius.md,
90
+ lg: theme.borderRadius.lg,
91
+ full: theme.borderRadius.full
92
+ };
93
+ return radii[radius];
94
+ }, [radius, theme]);
95
+ return { radiusStyles, thumbRadius };
96
+ };
97
+ var useSwitchTrackStyles = ({
98
+ colorScheme,
99
+ isSelected,
100
+ variant,
101
+ sizeStyles,
102
+ radiusStyles
103
+ }) => {
104
+ const theme = useXUITheme();
105
+ const trackStyles = useMemo(() => {
106
+ const backgroundColor = isSelected ? variant === "overlap" ? colorScheme.background : colorScheme.main : theme.colors.default.background;
107
+ return {
108
+ width: sizeStyles.trackWidth,
109
+ height: sizeStyles.trackHeight,
110
+ backgroundColor,
111
+ paddingHorizontal: sizeStyles.padding,
112
+ ...radiusStyles
113
+ };
114
+ }, [colorScheme, isSelected, radiusStyles, sizeStyles, theme, variant]);
115
+ return trackStyles;
116
+ };
117
+ var useSwitchThumbStyles = ({
118
+ colorScheme,
119
+ isSelected,
120
+ variant,
121
+ sizeStyles,
122
+ thumbRadius
123
+ }) => {
124
+ const theme = useXUITheme();
125
+ const thumbStyles = useMemo(() => {
126
+ const baseStyle = {
127
+ width: sizeStyles.thumbSize,
128
+ height: sizeStyles.thumbSize,
129
+ borderRadius: thumbRadius,
130
+ backgroundColor: variant === "overlap" && isSelected ? colorScheme.main : theme.colors.background
131
+ };
132
+ if (variant !== "overlap") return baseStyle;
133
+ return {
134
+ ...baseStyle,
135
+ ...theme.shadows.sm
136
+ };
137
+ }, [colorScheme, isSelected, sizeStyles, theme, thumbRadius, variant]);
138
+ return thumbStyles;
139
+ };
140
+ var useSwitchContainerStyles = (labelAlignment) => {
141
+ const containerStyles = useMemo(() => {
142
+ const isJustified = labelAlignment === "justify-left" || labelAlignment === "justify-right";
143
+ return {
144
+ flexDirection: labelAlignment === "left" || labelAlignment === "justify-left" ? "row-reverse" : "row",
145
+ justifyContent: isJustified ? "space-between" : "flex-start"
146
+ };
147
+ }, [labelAlignment]);
148
+ return containerStyles;
149
+ };
150
+
151
+ // src/components/switch/switch.animation.ts
152
+ import { Animated } from "react-native";
153
+ var runThumbPositionAnimation = (thumbPosition, isSelected) => {
154
+ Animated.spring(thumbPosition, {
155
+ toValue: isSelected ? 1 : 0,
156
+ useNativeDriver: true,
157
+ damping: 15,
158
+ stiffness: 150
159
+ }).start();
160
+ };
161
+ var runSwitchPressInAnimation = (animatedScale, animatedThumbScale, isOverlap) => {
162
+ Animated.parallel([
163
+ Animated.spring(animatedScale, {
164
+ toValue: 0.95,
165
+ useNativeDriver: true
166
+ }),
167
+ Animated.spring(animatedThumbScale, {
168
+ toValue: isOverlap ? 1.1 : 1.2,
169
+ useNativeDriver: true
170
+ })
171
+ ]).start();
172
+ };
173
+ var runSwitchPressOutAnimation = (animatedScale, animatedThumbScale) => {
174
+ Animated.parallel([
175
+ Animated.spring(animatedScale, {
176
+ toValue: 1,
177
+ useNativeDriver: true
178
+ }),
179
+ Animated.spring(animatedThumbScale, {
180
+ toValue: 1,
181
+ useNativeDriver: true
182
+ })
183
+ ]).start();
184
+ };
185
+
186
+ // src/components/switch/switch.style.ts
187
+ import { StyleSheet } from "react-native";
188
+ var styles = StyleSheet.create({
189
+ container: {
190
+ flexDirection: "row",
191
+ alignItems: "center",
192
+ gap: 8
193
+ },
194
+ fullWidth: {
195
+ width: "100%"
196
+ },
197
+ track: {
198
+ justifyContent: "center",
199
+ position: "relative"
200
+ },
201
+ thumbContainer: {
202
+ position: "relative",
203
+ width: "100%",
204
+ height: "100%",
205
+ alignItems: "center",
206
+ justifyContent: "center"
207
+ },
208
+ thumb: {
209
+ position: "absolute",
210
+ left: 0
211
+ },
212
+ label: {
213
+ fontWeight: "400"
214
+ },
215
+ disabled: {
216
+ opacity: 0.5
217
+ },
218
+ disabledText: {
219
+ opacity: 0.7
220
+ }
221
+ });
222
+
223
+ // src/components/switch/switch.tsx
224
+ var Switch = ({
225
+ label,
226
+ labelAlignment = "right",
227
+ themeColor = "primary",
228
+ variant = "inside",
229
+ size = "md",
230
+ radius = "full",
231
+ fullWidth = false,
232
+ isSelected: isSelectedProp,
233
+ isDisabled = false,
234
+ labelStyle,
235
+ style,
236
+ onValueChange
237
+ }) => {
238
+ const theme = useXUITheme();
239
+ const isControlled = typeof isSelectedProp === "boolean";
240
+ const [internalSelected, setInternalSelected] = useState(isSelectedProp ?? false);
241
+ const isSelected = isControlled ? isSelectedProp : internalSelected;
242
+ const scale = useRef(new Animated2.Value(1)).current;
243
+ const thumbPosition = useRef(new Animated2.Value(isSelected ? 1 : 0)).current;
244
+ const thumbScale = useRef(new Animated2.Value(1)).current;
245
+ const colorScheme = useSwitchColorScheme(themeColor);
246
+ const sizeStyles = useSwitchSizeStyles(variant, size);
247
+ const { radiusStyles, thumbRadius } = useSwitchRadiusStyles(radius);
248
+ const trackStyles = useSwitchTrackStyles({
249
+ colorScheme,
250
+ isSelected,
251
+ variant,
252
+ sizeStyles,
253
+ radiusStyles
254
+ });
255
+ const thumbStyles = useSwitchThumbStyles({
256
+ colorScheme,
257
+ isSelected,
258
+ variant,
259
+ sizeStyles,
260
+ thumbRadius
261
+ });
262
+ const containerStyles = useSwitchContainerStyles(labelAlignment);
263
+ const maxTranslateX = useMemo2(() => {
264
+ if (variant === "overlap") {
265
+ return sizeStyles.trackWidth - sizeStyles.thumbSize;
266
+ }
267
+ return sizeStyles.trackWidth - sizeStyles.thumbSize - sizeStyles.padding * 2;
268
+ }, [sizeStyles, variant]);
269
+ const translateX = useMemo2(
270
+ () => thumbPosition.interpolate({
271
+ inputRange: [0, 1],
272
+ outputRange: [0, maxTranslateX]
273
+ }),
274
+ [maxTranslateX, thumbPosition]
275
+ );
276
+ useEffect(() => {
277
+ runThumbPositionAnimation(thumbPosition, isSelected);
278
+ }, [isSelected, thumbPosition]);
279
+ const handlePress = () => {
280
+ if (isDisabled) return;
281
+ const nextValue = !isSelected;
282
+ onValueChange?.(nextValue);
283
+ if (!isControlled) {
284
+ setInternalSelected(nextValue);
285
+ }
286
+ };
287
+ const handlePressIn = () => {
288
+ if (isDisabled) return;
289
+ runSwitchPressInAnimation(scale, thumbScale, variant === "overlap");
290
+ };
291
+ const handlePressOut = () => {
292
+ if (isDisabled) return;
293
+ runSwitchPressOutAnimation(scale, thumbScale);
294
+ };
295
+ return /* @__PURE__ */ React.createElement(
296
+ Pressable,
297
+ {
298
+ onPress: handlePress,
299
+ onPressIn: handlePressIn,
300
+ onPressOut: handlePressOut,
301
+ disabled: isDisabled,
302
+ accessible: true,
303
+ accessibilityRole: "switch",
304
+ accessibilityLabel: label,
305
+ accessibilityState: {
306
+ disabled: isDisabled,
307
+ checked: isSelected
308
+ },
309
+ style: [
310
+ styles.container,
311
+ containerStyles,
312
+ fullWidth && styles.fullWidth,
313
+ isDisabled && styles.disabled,
314
+ style
315
+ ]
316
+ },
317
+ /* @__PURE__ */ React.createElement(
318
+ Animated2.View,
319
+ {
320
+ style: [
321
+ styles.track,
322
+ trackStyles,
323
+ {
324
+ transform: [{ scale }]
325
+ }
326
+ ]
327
+ },
328
+ /* @__PURE__ */ React.createElement(View, { style: styles.thumbContainer }, /* @__PURE__ */ React.createElement(
329
+ Animated2.View,
330
+ {
331
+ style: [
332
+ styles.thumb,
333
+ thumbStyles,
334
+ {
335
+ transform: [{ translateX }, { scale: thumbScale }]
336
+ }
337
+ ]
338
+ }
339
+ ))
340
+ ),
341
+ label && /* @__PURE__ */ React.createElement(
342
+ Text,
343
+ {
344
+ style: [
345
+ styles.label,
346
+ { fontSize: sizeStyles.fontSize, color: theme.colors.foreground },
347
+ isDisabled && styles.disabledText,
348
+ labelStyle
349
+ ]
350
+ },
351
+ label
352
+ )
353
+ );
354
+ };
355
+ export {
356
+ Switch
357
+ };