@xaui/native 0.0.2

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,90 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { TextStyle, ViewStyle, GestureResponderEvent } from 'react-native';
3
+ import { T as ThemeColor } from '../theme-qvIXI4kF.cjs';
4
+
5
+ type ButtonVariant = 'solid' | 'outlined' | 'flat' | 'light' | 'elevated' | 'faded';
6
+ type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
7
+ type ButtonRadius = 'none' | 'sm' | 'md' | 'lg' | 'full';
8
+ type SpinnerPlacement = 'start' | 'end';
9
+ type ButtonProps = {
10
+ /**
11
+ * The content to display in the button.
12
+ */
13
+ children: ReactNode;
14
+ /**
15
+ * The theme color of the button.
16
+ * @default 'default'
17
+ */
18
+ themeColor?: ThemeColor;
19
+ /**
20
+ * The variant of the button.
21
+ * @default 'solid'
22
+ */
23
+ variant?: ButtonVariant;
24
+ /**
25
+ * The size of the button.
26
+ * @default 'md'
27
+ */
28
+ size?: ButtonSize;
29
+ /**
30
+ * The border radius of the button.
31
+ * @default 'md'
32
+ */
33
+ radius?: ButtonRadius;
34
+ /**
35
+ * Content to display at the start of the button.
36
+ */
37
+ startContent?: ReactNode;
38
+ /**
39
+ * Content to display at the end of the button.
40
+ */
41
+ endContent?: ReactNode;
42
+ /**
43
+ * The placement of the spinner when isLoading is true.
44
+ * @default 'start'
45
+ */
46
+ spinnerPlacement?: SpinnerPlacement;
47
+ /**
48
+ * Whether the button should take the full width of its container.
49
+ * @default false
50
+ */
51
+ fullWidth?: boolean;
52
+ /**
53
+ * Whether the button is disabled.
54
+ * @default false
55
+ */
56
+ isDisabled?: boolean;
57
+ /**
58
+ * Whether the button is in a loading state.
59
+ * @default false
60
+ */
61
+ isLoading?: boolean;
62
+ /**
63
+ * Custom text style for the button label.
64
+ */
65
+ textStyle?: TextStyle;
66
+ /**
67
+ * Custom style for the button container.
68
+ */
69
+ style?: ViewStyle;
70
+ /**
71
+ * Callback fired when the button is pressed.
72
+ */
73
+ onPress?: (event: GestureResponderEvent) => void;
74
+ /**
75
+ * Callback fired when the button is long pressed.
76
+ */
77
+ onLongPress?: (event: GestureResponderEvent) => void;
78
+ /**
79
+ * Callback fired when the button press starts.
80
+ */
81
+ onPressIn?: (event: GestureResponderEvent) => void;
82
+ /**
83
+ * Callback fired when the button press ends.
84
+ */
85
+ onPressOut?: (event: GestureResponderEvent) => void;
86
+ };
87
+
88
+ declare const Button: React.FC<ButtonProps>;
89
+
90
+ export { Button, type ButtonProps, type ButtonRadius, type ButtonSize, type ButtonVariant, type SpinnerPlacement };
@@ -0,0 +1,90 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { TextStyle, ViewStyle, GestureResponderEvent } from 'react-native';
3
+ import { T as ThemeColor } from '../theme-qvIXI4kF.js';
4
+
5
+ type ButtonVariant = 'solid' | 'outlined' | 'flat' | 'light' | 'elevated' | 'faded';
6
+ type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
7
+ type ButtonRadius = 'none' | 'sm' | 'md' | 'lg' | 'full';
8
+ type SpinnerPlacement = 'start' | 'end';
9
+ type ButtonProps = {
10
+ /**
11
+ * The content to display in the button.
12
+ */
13
+ children: ReactNode;
14
+ /**
15
+ * The theme color of the button.
16
+ * @default 'default'
17
+ */
18
+ themeColor?: ThemeColor;
19
+ /**
20
+ * The variant of the button.
21
+ * @default 'solid'
22
+ */
23
+ variant?: ButtonVariant;
24
+ /**
25
+ * The size of the button.
26
+ * @default 'md'
27
+ */
28
+ size?: ButtonSize;
29
+ /**
30
+ * The border radius of the button.
31
+ * @default 'md'
32
+ */
33
+ radius?: ButtonRadius;
34
+ /**
35
+ * Content to display at the start of the button.
36
+ */
37
+ startContent?: ReactNode;
38
+ /**
39
+ * Content to display at the end of the button.
40
+ */
41
+ endContent?: ReactNode;
42
+ /**
43
+ * The placement of the spinner when isLoading is true.
44
+ * @default 'start'
45
+ */
46
+ spinnerPlacement?: SpinnerPlacement;
47
+ /**
48
+ * Whether the button should take the full width of its container.
49
+ * @default false
50
+ */
51
+ fullWidth?: boolean;
52
+ /**
53
+ * Whether the button is disabled.
54
+ * @default false
55
+ */
56
+ isDisabled?: boolean;
57
+ /**
58
+ * Whether the button is in a loading state.
59
+ * @default false
60
+ */
61
+ isLoading?: boolean;
62
+ /**
63
+ * Custom text style for the button label.
64
+ */
65
+ textStyle?: TextStyle;
66
+ /**
67
+ * Custom style for the button container.
68
+ */
69
+ style?: ViewStyle;
70
+ /**
71
+ * Callback fired when the button is pressed.
72
+ */
73
+ onPress?: (event: GestureResponderEvent) => void;
74
+ /**
75
+ * Callback fired when the button is long pressed.
76
+ */
77
+ onLongPress?: (event: GestureResponderEvent) => void;
78
+ /**
79
+ * Callback fired when the button press starts.
80
+ */
81
+ onPressIn?: (event: GestureResponderEvent) => void;
82
+ /**
83
+ * Callback fired when the button press ends.
84
+ */
85
+ onPressOut?: (event: GestureResponderEvent) => void;
86
+ };
87
+
88
+ declare const Button: React.FC<ButtonProps>;
89
+
90
+ export { Button, type ButtonProps, type ButtonRadius, type ButtonSize, type ButtonVariant, type SpinnerPlacement };
@@ -0,0 +1,264 @@
1
+ import {
2
+ ActivityIndicator
3
+ } from "../chunk-6ITFLLAM.js";
4
+ import {
5
+ useXUITheme
6
+ } from "../chunk-SHT66VET.js";
7
+
8
+ // src/components/button/button.tsx
9
+ import React from "react";
10
+ import { Pressable, Text, View, Animated } from "react-native";
11
+
12
+ // src/components/button/button.style.ts
13
+ import { StyleSheet } from "react-native";
14
+ var styles = StyleSheet.create({
15
+ button: {
16
+ flexDirection: "row",
17
+ alignItems: "center",
18
+ justifyContent: "center",
19
+ overflow: "hidden"
20
+ },
21
+ contentContainer: {
22
+ flexDirection: "row",
23
+ alignItems: "center",
24
+ justifyContent: "center",
25
+ gap: 8
26
+ },
27
+ text: {
28
+ fontWeight: "500",
29
+ textAlign: "center"
30
+ },
31
+ startContent: {
32
+ marginRight: 4
33
+ },
34
+ endContent: {
35
+ marginLeft: 4
36
+ },
37
+ spinner: {
38
+ marginHorizontal: 4
39
+ },
40
+ fullWidth: {
41
+ width: "100%"
42
+ },
43
+ disabled: {
44
+ opacity: 0.5
45
+ },
46
+ disabledText: {
47
+ opacity: 0.7
48
+ }
49
+ });
50
+
51
+ // src/components/button/button.hook.ts
52
+ import { useMemo } from "react";
53
+ import { getSafeThemeColor } from "@xaui/core";
54
+ var useButtonStyles = (themeColor, variant, size, radius) => {
55
+ const theme = useXUITheme();
56
+ const safeThemeColor = getSafeThemeColor(themeColor);
57
+ const colorScheme = theme.colors[safeThemeColor];
58
+ const sizeStyles = useMemo(() => {
59
+ const sizes = {
60
+ xs: {
61
+ paddingHorizontal: theme.spacing.sm,
62
+ paddingVertical: theme.spacing.xs,
63
+ minHeight: 34,
64
+ fontSize: theme.fontSizes.xs
65
+ },
66
+ sm: {
67
+ paddingHorizontal: theme.spacing.md,
68
+ paddingVertical: theme.spacing.xs,
69
+ minHeight: 38,
70
+ fontSize: theme.fontSizes.sm
71
+ },
72
+ md: {
73
+ paddingHorizontal: theme.spacing.md,
74
+ paddingVertical: theme.spacing.sm,
75
+ minHeight: 42,
76
+ fontSize: theme.fontSizes.md
77
+ },
78
+ lg: {
79
+ paddingHorizontal: theme.spacing.lg,
80
+ paddingVertical: theme.spacing.md,
81
+ minHeight: 50,
82
+ fontSize: theme.fontSizes.lg
83
+ }
84
+ };
85
+ return sizes[size];
86
+ }, [size, theme]);
87
+ const radiusStyles = useMemo(() => {
88
+ const radii = {
89
+ none: theme.borderRadius.none,
90
+ sm: theme.borderRadius.sm,
91
+ md: theme.borderRadius.md,
92
+ lg: theme.borderRadius.lg,
93
+ full: theme.borderRadius.full
94
+ };
95
+ return { borderRadius: radii[radius] };
96
+ }, [radius, theme]);
97
+ const variantStyles = useMemo(() => {
98
+ const styles2 = {
99
+ solid: {
100
+ backgroundColor: colorScheme.main,
101
+ borderWidth: 0
102
+ },
103
+ outlined: {
104
+ backgroundColor: "transparent",
105
+ borderWidth: theme.borderWidth.md,
106
+ borderColor: colorScheme.main
107
+ },
108
+ flat: {
109
+ backgroundColor: colorScheme.background,
110
+ borderWidth: 0
111
+ },
112
+ light: {
113
+ backgroundColor: "transparent",
114
+ borderWidth: 0
115
+ },
116
+ elevated: {
117
+ backgroundColor: colorScheme.main,
118
+ borderWidth: 0,
119
+ ...theme.shadows.md
120
+ },
121
+ faded: {
122
+ backgroundColor: `${colorScheme.background}90`,
123
+ borderWidth: theme.borderWidth.md,
124
+ borderColor: colorScheme.main
125
+ }
126
+ };
127
+ return styles2[variant];
128
+ }, [variant, colorScheme, theme]);
129
+ const textColor = useMemo(() => {
130
+ if (variant === "solid" || variant === "elevated") {
131
+ return colorScheme.foreground;
132
+ }
133
+ return colorScheme.main;
134
+ }, [variant, colorScheme]);
135
+ const spinnerSize = useMemo(() => {
136
+ const sizes = {
137
+ xs: 14,
138
+ sm: 16,
139
+ md: 18,
140
+ lg: 20
141
+ };
142
+ return sizes[size];
143
+ }, [size]);
144
+ return {
145
+ sizeStyles,
146
+ radiusStyles,
147
+ variantStyles,
148
+ textColor,
149
+ spinnerSize
150
+ };
151
+ };
152
+
153
+ // src/components/button/button.tsx
154
+ var Button = ({
155
+ children,
156
+ themeColor = "default",
157
+ variant = "solid",
158
+ size = "md",
159
+ radius = "md",
160
+ startContent,
161
+ endContent,
162
+ spinnerPlacement = "start",
163
+ fullWidth = false,
164
+ isDisabled = false,
165
+ isLoading = false,
166
+ textStyle,
167
+ style,
168
+ onPress,
169
+ onLongPress,
170
+ onPressIn,
171
+ onPressOut
172
+ }) => {
173
+ const animatedScale = React.useRef(new Animated.Value(1)).current;
174
+ const animatedOpacity = React.useRef(new Animated.Value(1)).current;
175
+ const { sizeStyles, radiusStyles, variantStyles, textColor, spinnerSize } = useButtonStyles(themeColor, variant, size, radius);
176
+ const handlePressIn = (event) => {
177
+ if (!isDisabled && !isLoading) {
178
+ Animated.parallel([
179
+ Animated.spring(animatedScale, {
180
+ toValue: 0.975,
181
+ useNativeDriver: true,
182
+ speed: 50,
183
+ bounciness: 0
184
+ }),
185
+ Animated.timing(animatedOpacity, {
186
+ toValue: 0.9,
187
+ duration: 100,
188
+ useNativeDriver: true
189
+ })
190
+ ]).start();
191
+ }
192
+ onPressIn?.(event);
193
+ };
194
+ const handlePressOut = (event) => {
195
+ if (!isDisabled && !isLoading) {
196
+ Animated.parallel([
197
+ Animated.spring(animatedScale, {
198
+ toValue: 1,
199
+ useNativeDriver: true,
200
+ speed: 50,
201
+ bounciness: 0
202
+ }),
203
+ Animated.timing(animatedOpacity, {
204
+ toValue: 1,
205
+ duration: 100,
206
+ useNativeDriver: true
207
+ })
208
+ ]).start();
209
+ }
210
+ onPressOut?.(event);
211
+ };
212
+ const spinner = /* @__PURE__ */ React.createElement(
213
+ ActivityIndicator,
214
+ {
215
+ variant: "circular",
216
+ themeColor: variant === "solid" || variant === "elevated" ? void 0 : themeColor,
217
+ color: variant === "solid" || variant === "elevated" ? textColor : void 0,
218
+ size: spinnerSize
219
+ }
220
+ );
221
+ return /* @__PURE__ */ React.createElement(View, { style: [fullWidth && styles.fullWidth] }, /* @__PURE__ */ React.createElement(
222
+ Pressable,
223
+ {
224
+ onPress: isDisabled || isLoading ? void 0 : onPress,
225
+ onLongPress: isDisabled || isLoading ? void 0 : onLongPress,
226
+ onPressIn: handlePressIn,
227
+ onPressOut: handlePressOut,
228
+ disabled: isDisabled || isLoading
229
+ },
230
+ /* @__PURE__ */ React.createElement(
231
+ Animated.View,
232
+ {
233
+ style: [
234
+ styles.button,
235
+ sizeStyles,
236
+ radiusStyles,
237
+ variantStyles,
238
+ fullWidth && styles.fullWidth,
239
+ isDisabled && styles.disabled,
240
+ {
241
+ transform: [{ scale: animatedScale }],
242
+ opacity: animatedOpacity
243
+ },
244
+ style
245
+ ]
246
+ },
247
+ /* @__PURE__ */ React.createElement(View, { style: styles.contentContainer }, startContent && !isLoading && /* @__PURE__ */ React.createElement(View, { style: styles.startContent }, startContent), isLoading && spinnerPlacement === "start" && /* @__PURE__ */ React.createElement(View, { style: styles.spinner }, spinner), /* @__PURE__ */ React.createElement(
248
+ Text,
249
+ {
250
+ style: [
251
+ styles.text,
252
+ { fontSize: sizeStyles.fontSize, color: textColor },
253
+ isDisabled && styles.disabledText,
254
+ textStyle
255
+ ]
256
+ },
257
+ children
258
+ ), isLoading && spinnerPlacement === "end" && /* @__PURE__ */ React.createElement(View, { style: styles.spinner }, spinner), endContent && !isLoading && /* @__PURE__ */ React.createElement(View, { style: styles.endContent }, endContent))
259
+ )
260
+ ));
261
+ };
262
+ export {
263
+ Button
264
+ };