rnnovaui 0.2.0 → 0.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnnovaui",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "react-native": "src/index.js",
@@ -1,7 +1,9 @@
1
- import React, { memo, useCallback, useMemo } from "react";
1
+ import React, { memo, useCallback, useMemo, useRef } from "react";
2
2
 
3
3
  import {
4
4
  ActivityIndicator,
5
+ Animated,
6
+ Easing,
5
7
  Pressable,
6
8
  StyleSheet,
7
9
  Text,
@@ -10,7 +12,7 @@ import {
10
12
 
11
13
  import { useUITheme } from "../../theme";
12
14
 
13
- const VARIANTS = {
15
+ const BUTTON_VARIANTS = {
14
16
  solid: "solid",
15
17
  outline: "outline",
16
18
  ghost: "ghost",
@@ -19,14 +21,14 @@ const VARIANTS = {
19
21
  success: "success",
20
22
  };
21
23
 
22
- const SIZES = {
24
+ const BUTTON_SIZES = {
23
25
  sm: "sm",
24
26
  md: "md",
25
27
  lg: "lg",
26
28
  xl: "xl",
27
29
  };
28
30
 
29
- const FALLBACK = {
31
+ const FALLBACK_COLORS = {
30
32
  primary: "#FF5A1F",
31
33
  primaryPressed: "#E94D17",
32
34
  primarySoft: "#FFF0EA",
@@ -41,9 +43,10 @@ const FALLBACK = {
41
43
 
42
44
  disabledBackground: "#E5E5E5",
43
45
  disabledText: "#A3A3A3",
46
+ disabledBorder: "#E5E5E5",
44
47
  };
45
48
 
46
- function UIButton({
49
+ function UIButtonComponent({
47
50
  title,
48
51
  children,
49
52
 
@@ -55,136 +58,146 @@ function UIButton({
55
58
 
56
59
  fullWidth = false,
57
60
 
58
- leftIcon,
59
- rightIcon,
61
+ leftIcon = null,
62
+ rightIcon = null,
60
63
 
61
64
  onPress,
62
65
  onLongPress,
66
+ onPressIn,
67
+ onPressOut,
63
68
 
64
69
  style,
65
70
  contentStyle,
66
71
  textStyle,
67
72
 
68
- testID,
69
-
70
- ...props
71
- }) {
72
- const { theme } = useUITheme();
73
+ activeOpacity = 0.82,
73
74
 
74
- const colors = theme?.colors || {};
75
-
76
- const primary = colors.primary || FALLBACK.primary;
77
-
78
- const primaryPressed = colors.primaryPressed || FALLBACK.primaryPressed;
75
+ pressAnimation = true,
79
76
 
80
- const primarySoft = colors.primarySoft || FALLBACK.primarySoft;
77
+ pressScale = 0.97,
81
78
 
82
- const success = colors.success || FALLBACK.success;
79
+ pressAnimationDuration = 100,
83
80
 
84
- const successPressed = colors.successPressed || FALLBACK.successPressed;
81
+ testID,
85
82
 
86
- const danger = colors.danger || FALLBACK.danger;
83
+ accessibilityLabel,
84
+ accessibilityHint,
87
85
 
88
- const dangerPressed = colors.dangerPressed || FALLBACK.dangerPressed;
86
+ ...props
87
+ }) {
88
+ const { theme } = useUITheme();
89
89
 
90
- const white = colors.onPrimary || FALLBACK.white;
90
+ const colors = theme?.colors || {};
91
91
 
92
92
  const isDisabled = disabled || loading;
93
93
 
94
- const buttonColors = useMemo(() => {
95
- if (isDisabled) {
96
- return {
97
- background:
98
- colors.buttonDisabledBackground || FALLBACK.disabledBackground,
99
-
100
- border: colors.buttonDisabledBorder || FALLBACK.disabledBackground,
101
-
102
- text: colors.buttonDisabledText || FALLBACK.disabledText,
103
-
104
- borderWidth: 1,
105
- };
106
- }
94
+ /*
95
+ * Native Animated value.
96
+ *
97
+ * Created once and reused.
98
+ * This avoids creating animation
99
+ * objects on every render.
100
+ */
101
+ const scale = useRef(new Animated.Value(1)).current;
107
102
 
108
- switch (variant) {
109
- case "outline":
110
- return {
111
- background: "transparent",
103
+ const animationRef = useRef(null);
112
104
 
113
- border: colors.buttonOutlineBorder || primary,
105
+ const safeVariant = BUTTON_VARIANTS[variant]
106
+ ? variant
107
+ : BUTTON_VARIANTS.solid;
114
108
 
115
- text: colors.buttonOutlineText || primary,
109
+ const safeSize = BUTTON_SIZES[size] ? size : BUTTON_SIZES.md;
116
110
 
117
- borderWidth: 1,
118
- };
111
+ const buttonColors = useMemo(
112
+ () => getVariantColors(safeVariant, colors, isDisabled),
113
+ [safeVariant, colors, isDisabled],
114
+ );
119
115
 
120
- case "ghost":
121
- return {
122
- background: "transparent",
116
+ const dimensions = useMemo(
117
+ () => getDimensions(safeSize, theme),
118
+ [safeSize, theme],
119
+ );
123
120
 
124
- border: "transparent",
121
+ const stopAnimation = useCallback(() => {
122
+ if (animationRef.current) {
123
+ animationRef.current.stop();
125
124
 
126
- text: colors.buttonGhostText || primary,
125
+ animationRef.current = null;
126
+ }
127
+ }, []);
127
128
 
128
- borderWidth: 0,
129
- };
129
+ const animateScale = useCallback(
130
+ (targetScale) => {
131
+ if (!pressAnimation || isDisabled) {
132
+ return;
133
+ }
130
134
 
131
- case "soft":
132
- return {
133
- background: colors.buttonSoftBackground || primarySoft,
135
+ stopAnimation();
134
136
 
135
- border: colors.buttonSoftBackground || primarySoft,
137
+ animationRef.current = Animated.timing(scale, {
138
+ toValue: targetScale,
136
139
 
137
- text: colors.buttonSoftText || primary,
140
+ duration: pressAnimationDuration,
138
141
 
139
- borderWidth: 1,
140
- };
142
+ easing: Easing.out(Easing.quad),
141
143
 
142
- case "danger":
143
- return {
144
- background: colors.buttonDangerBackground || danger,
144
+ useNativeDriver: true,
145
+ });
145
146
 
146
- border: colors.buttonDangerBackground || danger,
147
+ animationRef.current.start(() => {
148
+ animationRef.current = null;
149
+ });
150
+ },
151
+ [pressAnimation, isDisabled, stopAnimation, scale, pressAnimationDuration],
152
+ );
147
153
 
148
- text: colors.buttonDangerText || white,
154
+ const handlePressIn = useCallback(
155
+ (event) => {
156
+ if (isDisabled) {
157
+ return;
158
+ }
149
159
 
150
- borderWidth: 1,
151
- };
160
+ animateScale(pressScale);
152
161
 
153
- case "success":
154
- return {
155
- background: colors.buttonSuccessBackground || success,
162
+ onPressIn?.(event);
163
+ },
164
+ [isDisabled, animateScale, pressScale, onPressIn],
165
+ );
156
166
 
157
- border: colors.buttonSuccessBackground || success,
167
+ const handlePressOut = useCallback(
168
+ (event) => {
169
+ if (isDisabled) {
170
+ return;
171
+ }
158
172
 
159
- text: colors.buttonSuccessText || white,
173
+ animateScale(1);
160
174
 
161
- borderWidth: 1,
162
- };
175
+ onPressOut?.(event);
176
+ },
177
+ [isDisabled, animateScale, onPressOut],
178
+ );
163
179
 
164
- case "solid":
165
- default:
166
- return {
167
- background: colors.buttonPrimaryBackground || primary,
180
+ const handlePress = useCallback(
181
+ (event) => {
182
+ if (isDisabled) {
183
+ return;
184
+ }
168
185
 
169
- border: colors.buttonPrimaryBackground || primary,
186
+ onPress?.(event);
187
+ },
188
+ [isDisabled, onPress],
189
+ );
170
190
 
171
- text: colors.buttonPrimaryText || white,
191
+ const handleLongPress = useCallback(
192
+ (event) => {
193
+ if (isDisabled) {
194
+ return;
195
+ }
172
196
 
173
- borderWidth: 1,
174
- };
175
- }
176
- }, [
177
- variant,
178
- isDisabled,
179
- colors,
180
- primary,
181
- primarySoft,
182
- success,
183
- danger,
184
- white,
185
- ]);
186
-
187
- const dimensions = useMemo(() => getDimensions(size, theme), [size, theme]);
197
+ onLongPress?.(event);
198
+ },
199
+ [isDisabled, onLongPress],
200
+ );
188
201
 
189
202
  const buttonStyle = useMemo(
190
203
  () => [
@@ -208,88 +221,187 @@ function UIButton({
208
221
  width: fullWidth ? "100%" : undefined,
209
222
 
210
223
  opacity: isDisabled ? 0.55 : 1,
224
+
225
+ transform: [
226
+ {
227
+ scale,
228
+ },
229
+ ],
211
230
  },
212
231
 
213
232
  style,
214
233
  ],
215
- [dimensions, buttonColors, fullWidth, isDisabled, style],
234
+ [dimensions, buttonColors, fullWidth, isDisabled, scale, style],
216
235
  );
217
236
 
218
- const handlePress = useCallback(
219
- (event) => {
220
- if (isDisabled) {
221
- return;
222
- }
223
-
224
- onPress?.(event);
225
- },
226
- [isDisabled, onPress],
237
+ return (
238
+ <Animated.View style={buttonStyle}>
239
+ <Pressable
240
+ {...props}
241
+ testID={testID}
242
+ disabled={isDisabled}
243
+ onPress={handlePress}
244
+ onLongPress={handleLongPress}
245
+ onPressIn={handlePressIn}
246
+ onPressOut={handlePressOut}
247
+ accessibilityRole="button"
248
+ accessibilityLabel={
249
+ accessibilityLabel || (typeof title === "string" ? title : undefined)
250
+ }
251
+ accessibilityHint={accessibilityHint}
252
+ accessibilityState={{
253
+ disabled: isDisabled,
254
+
255
+ busy: loading,
256
+ }}
257
+ style={styles.pressable}
258
+ >
259
+ <View
260
+ style={[
261
+ styles.content,
262
+
263
+ {
264
+ gap: dimensions.gap,
265
+ },
266
+
267
+ contentStyle,
268
+ ]}
269
+ >
270
+ {loading ? (
271
+ <ActivityIndicator size="small" color={buttonColors.text} />
272
+ ) : (
273
+ leftIcon && <View style={styles.icon}>{leftIcon}</View>
274
+ )}
275
+
276
+ {children !== undefined && children !== null ? (
277
+ <View style={styles.children}>{children}</View>
278
+ ) : title !== undefined && title !== null ? (
279
+ <Text
280
+ numberOfLines={1}
281
+ style={[
282
+ styles.text,
283
+
284
+ {
285
+ color: buttonColors.text,
286
+
287
+ fontSize: dimensions.fontSize,
288
+
289
+ lineHeight: dimensions.lineHeight,
290
+ },
291
+
292
+ textStyle,
293
+ ]}
294
+ >
295
+ {title}
296
+ </Text>
297
+ ) : null}
298
+
299
+ {!loading && rightIcon && (
300
+ <View style={styles.icon}>{rightIcon}</View>
301
+ )}
302
+ </View>
303
+ </Pressable>
304
+ </Animated.View>
227
305
  );
306
+ }
228
307
 
229
- const handleLongPress = useCallback(
230
- (event) => {
231
- if (isDisabled) {
232
- return;
233
- }
308
+ function getVariantColors(variant, colors, disabled) {
309
+ const primary = colors.primary || FALLBACK_COLORS.primary;
234
310
 
235
- onLongPress?.(event);
236
- },
237
- [isDisabled, onLongPress],
238
- );
311
+ const primarySoft = colors.primarySoft || FALLBACK_COLORS.primarySoft;
239
312
 
240
- return (
241
- <Pressable
242
- {...props}
243
- testID={testID}
244
- disabled={isDisabled}
245
- onPress={handlePress}
246
- onLongPress={handleLongPress}
247
- style={buttonStyle}
248
- >
249
- <View
250
- style={[
251
- styles.content,
313
+ const success = colors.success || FALLBACK_COLORS.success;
252
314
 
253
- {
254
- gap: dimensions.gap,
255
- },
315
+ const successPressed =
316
+ colors.successPressed || FALLBACK_COLORS.successPressed;
256
317
 
257
- contentStyle,
258
- ]}
259
- >
260
- {loading ? (
261
- <ActivityIndicator size="small" color={buttonColors.text} />
262
- ) : (
263
- leftIcon && <View style={styles.icon}>{leftIcon}</View>
264
- )}
265
-
266
- {children !== undefined && children !== null ? (
267
- <View style={styles.children}>{children}</View>
268
- ) : title !== undefined && title !== null ? (
269
- <Text
270
- numberOfLines={1}
271
- style={[
272
- styles.text,
273
-
274
- {
275
- color: buttonColors.text,
276
-
277
- fontSize: dimensions.fontSize,
278
-
279
- lineHeight: dimensions.lineHeight,
280
- },
281
-
282
- textStyle,
283
- ]}
284
- >
285
- {title}
286
- </Text>
287
- ) : null}
288
-
289
- {!loading && rightIcon && <View style={styles.icon}>{rightIcon}</View>}
290
- </View>
291
- </Pressable>
292
- );
318
+ const danger = colors.danger || FALLBACK_COLORS.danger;
319
+
320
+ const dangerPressed = colors.dangerPressed || FALLBACK_COLORS.dangerPressed;
321
+
322
+ const white = colors.onPrimary || FALLBACK_COLORS.white;
323
+
324
+ if (disabled) {
325
+ return {
326
+ background:
327
+ colors.buttonDisabledBackground || FALLBACK_COLORS.disabledBackground,
328
+
329
+ border: colors.buttonDisabledBorder || FALLBACK_COLORS.disabledBorder,
330
+
331
+ borderWidth: 1,
332
+
333
+ text: colors.buttonDisabledText || FALLBACK_COLORS.disabledText,
334
+ };
335
+ }
336
+
337
+ switch (variant) {
338
+ case BUTTON_VARIANTS.outline:
339
+ return {
340
+ background: colors.buttonOutlineBackground || "transparent",
341
+
342
+ border: colors.buttonOutlineBorder || primary,
343
+
344
+ borderWidth: 1,
345
+
346
+ text: colors.buttonOutlineText || primary,
347
+ };
348
+
349
+ case BUTTON_VARIANTS.ghost:
350
+ return {
351
+ background: colors.buttonGhostBackground || "transparent",
352
+
353
+ border: "transparent",
354
+
355
+ borderWidth: 0,
356
+
357
+ text: colors.buttonGhostText || primary,
358
+ };
359
+
360
+ case BUTTON_VARIANTS.soft:
361
+ return {
362
+ background: colors.buttonSoftBackground || primarySoft,
363
+
364
+ border: colors.buttonSoftBackground || primarySoft,
365
+
366
+ borderWidth: 1,
367
+
368
+ text: colors.buttonSoftText || primary,
369
+ };
370
+
371
+ case BUTTON_VARIANTS.danger:
372
+ return {
373
+ background: colors.buttonDangerBackground || danger,
374
+
375
+ border: colors.buttonDangerBackground || danger,
376
+
377
+ borderWidth: 1,
378
+
379
+ text: colors.buttonDangerText || white,
380
+ };
381
+
382
+ case BUTTON_VARIANTS.success:
383
+ return {
384
+ background: colors.buttonSuccessBackground || success,
385
+
386
+ border: colors.buttonSuccessBackground || success,
387
+
388
+ borderWidth: 1,
389
+
390
+ text: colors.buttonSuccessText || white,
391
+ };
392
+
393
+ case BUTTON_VARIANTS.solid:
394
+ default:
395
+ return {
396
+ background: colors.buttonPrimaryBackground || primary,
397
+
398
+ border: colors.buttonPrimaryBackground || primary,
399
+
400
+ borderWidth: 1,
401
+
402
+ text: colors.buttonPrimaryText || white,
403
+ };
404
+ }
293
405
  }
294
406
 
295
407
  function getDimensions(size, theme) {
@@ -301,7 +413,7 @@ function getDimensions(size, theme) {
301
413
  const spacing = theme?.spacing || {};
302
414
 
303
415
  switch (size) {
304
- case "sm":
416
+ case BUTTON_SIZES.sm:
305
417
  return {
306
418
  height: buttonSizes.sm || 36,
307
419
 
@@ -316,7 +428,7 @@ function getDimensions(size, theme) {
316
428
  lineHeight: 18,
317
429
  };
318
430
 
319
- case "lg":
431
+ case BUTTON_SIZES.lg:
320
432
  return {
321
433
  height: buttonSizes.lg || 52,
322
434
 
@@ -331,7 +443,7 @@ function getDimensions(size, theme) {
331
443
  lineHeight: 22,
332
444
  };
333
445
 
334
- case "xl":
446
+ case BUTTON_SIZES.xl:
335
447
  return {
336
448
  height: buttonSizes.xl || 60,
337
449
 
@@ -346,7 +458,7 @@ function getDimensions(size, theme) {
346
458
  lineHeight: 24,
347
459
  };
348
460
 
349
- case "md":
461
+ case BUTTON_SIZES.md:
350
462
  default:
351
463
  return {
352
464
  height: buttonSizes.md || 44,
@@ -366,18 +478,28 @@ function getDimensions(size, theme) {
366
478
 
367
479
  const styles = StyleSheet.create({
368
480
  button: {
369
- flexDirection: "row",
481
+ flexShrink: 0,
370
482
 
371
483
  alignItems: "center",
372
484
 
373
485
  justifyContent: "center",
486
+ },
374
487
 
375
- overflow: "hidden",
488
+ pressable: {
489
+ width: "100%",
376
490
 
377
- flexShrink: 0,
491
+ height: "100%",
492
+
493
+ alignItems: "center",
494
+
495
+ justifyContent: "center",
378
496
  },
379
497
 
380
498
  content: {
499
+ width: "100%",
500
+
501
+ height: "100%",
502
+
381
503
  flexDirection: "row",
382
504
 
383
505
  alignItems: "center",
@@ -404,16 +526,20 @@ const styles = StyleSheet.create({
404
526
  },
405
527
 
406
528
  text: {
529
+ flexShrink: 1,
530
+
407
531
  fontWeight: "600",
408
532
 
409
533
  textAlign: "center",
410
534
 
411
535
  includeFontPadding: false,
412
-
413
- flexShrink: 1,
414
536
  },
415
537
  });
416
538
 
417
- export default memo(UIButton);
539
+ export const UIButton = memo(UIButtonComponent);
540
+
541
+ UIButton.displayName = "UIButton";
542
+
543
+ export { BUTTON_VARIANTS as UIButtonVariants, BUTTON_SIZES as UIButtonSizes };
418
544
 
419
- export { UIButton, VARIANTS as UIButtonVariants, SIZES as UIButtonSizes };
545
+ export default UIButton;
@@ -1,6 +1,13 @@
1
- import React, { memo, useCallback, useMemo } from "react";
1
+ import React, { memo, useCallback, useMemo, useRef } from "react";
2
2
 
3
- import { ActivityIndicator, Pressable, StyleSheet, View } from "react-native";
3
+ import {
4
+ ActivityIndicator,
5
+ Animated,
6
+ Easing,
7
+ Pressable,
8
+ StyleSheet,
9
+ View,
10
+ } from "react-native";
4
11
 
5
12
  import { useUITheme } from "../../theme";
6
13
 
@@ -41,9 +48,8 @@ const FALLBACK_COLORS = {
41
48
 
42
49
  white: "#FFFFFF",
43
50
 
44
- border: "#E5E5E5",
45
-
46
51
  disabledBackground: "#E5E5E5",
52
+ disabledText: "#A3A3A3",
47
53
  disabledBorder: "#E5E5E5",
48
54
  };
49
55
 
@@ -74,6 +80,12 @@ function UIIconButtonComponent({
74
80
 
75
81
  hitSlop,
76
82
 
83
+ pressAnimation = true,
84
+
85
+ pressScale = 0.94,
86
+
87
+ pressAnimationDuration = 100,
88
+
77
89
  testID,
78
90
 
79
91
  accessibilityLabel,
@@ -88,58 +100,113 @@ function UIIconButtonComponent({
88
100
 
89
101
  const isDisabled = disabled || loading;
90
102
 
91
- const resolvedColors = useMemo(
92
- () => getVariantColors(variant, colors, isDisabled),
93
- [variant, colors, isDisabled],
103
+ /*
104
+ * Reusable native animation value.
105
+ *
106
+ * Created once for the lifetime
107
+ * of this component instance.
108
+ */
109
+ const scale = useRef(new Animated.Value(1)).current;
110
+
111
+ const animationRef = useRef(null);
112
+
113
+ const safeVariant = VARIANTS[variant] ? variant : VARIANTS.ghost;
114
+
115
+ const safeSize = SIZES[size] ? size : SIZES.md;
116
+
117
+ const safeShape = SHAPES[shape] ? shape : SHAPES.circle;
118
+
119
+ const variantColors = useMemo(
120
+ () => getVariantColors(safeVariant, colors, isDisabled),
121
+ [safeVariant, colors, isDisabled],
94
122
  );
95
123
 
96
124
  const dimensions = useMemo(
97
- () => getDimensions(size, shape, theme),
98
- [size, shape, theme],
125
+ () => getDimensions(safeSize, safeShape, theme),
126
+ [safeSize, safeShape, theme],
99
127
  );
100
128
 
101
- const handlePress = useCallback(
129
+ const stopAnimation = useCallback(() => {
130
+ if (animationRef.current) {
131
+ animationRef.current.stop();
132
+
133
+ animationRef.current = null;
134
+ }
135
+ }, []);
136
+
137
+ const animateScale = useCallback(
138
+ (targetScale) => {
139
+ if (!pressAnimation || isDisabled) {
140
+ return;
141
+ }
142
+
143
+ stopAnimation();
144
+
145
+ const animation = Animated.timing(scale, {
146
+ toValue: targetScale,
147
+
148
+ duration: pressAnimationDuration,
149
+
150
+ easing: Easing.out(Easing.quad),
151
+
152
+ useNativeDriver: true,
153
+ });
154
+
155
+ animationRef.current = animation;
156
+
157
+ animation.start(() => {
158
+ animationRef.current = null;
159
+ });
160
+ },
161
+ [pressAnimation, isDisabled, stopAnimation, scale, pressAnimationDuration],
162
+ );
163
+
164
+ const handlePressIn = useCallback(
102
165
  (event) => {
103
166
  if (isDisabled) {
104
167
  return;
105
168
  }
106
169
 
107
- onPress?.(event);
170
+ animateScale(pressScale);
171
+
172
+ onPressIn?.(event);
108
173
  },
109
- [isDisabled, onPress],
174
+ [isDisabled, animateScale, pressScale, onPressIn],
110
175
  );
111
176
 
112
- const handleLongPress = useCallback(
177
+ const handlePressOut = useCallback(
113
178
  (event) => {
114
179
  if (isDisabled) {
115
180
  return;
116
181
  }
117
182
 
118
- onLongPress?.(event);
183
+ animateScale(1);
184
+
185
+ onPressOut?.(event);
119
186
  },
120
- [isDisabled, onLongPress],
187
+ [isDisabled, animateScale, onPressOut],
121
188
  );
122
189
 
123
- const handlePressIn = useCallback(
190
+ const handlePress = useCallback(
124
191
  (event) => {
125
192
  if (isDisabled) {
126
193
  return;
127
194
  }
128
195
 
129
- onPressIn?.(event);
196
+ onPress?.(event);
130
197
  },
131
- [isDisabled, onPressIn],
198
+ [isDisabled, onPress],
132
199
  );
133
200
 
134
- const handlePressOut = useCallback(
201
+ const handleLongPress = useCallback(
135
202
  (event) => {
136
203
  if (isDisabled) {
137
204
  return;
138
205
  }
139
206
 
140
- onPressOut?.(event);
207
+ onLongPress?.(event);
141
208
  },
142
- [isDisabled, onPressOut],
209
+ [isDisabled, onLongPress],
143
210
  );
144
211
 
145
212
  const buttonStyle = useMemo(
@@ -157,48 +224,56 @@ function UIIconButtonComponent({
157
224
 
158
225
  borderRadius: dimensions.borderRadius,
159
226
 
160
- backgroundColor: resolvedColors.background,
227
+ backgroundColor: variantColors.background,
161
228
 
162
- borderColor: resolvedColors.border,
229
+ borderColor: variantColors.border,
163
230
 
164
- borderWidth: resolvedColors.borderWidth,
231
+ borderWidth: variantColors.borderWidth,
165
232
 
166
233
  opacity: isDisabled ? 0.55 : 1,
234
+
235
+ transform: [
236
+ {
237
+ scale,
238
+ },
239
+ ],
167
240
  },
168
241
 
169
242
  style,
170
243
  ],
171
- [dimensions, resolvedColors, isDisabled, style],
244
+ [dimensions, variantColors, isDisabled, scale, style],
172
245
  );
173
246
 
174
247
  return (
175
- <Pressable
176
- {...props}
177
- testID={testID}
178
- disabled={isDisabled}
179
- onPress={handlePress}
180
- onLongPress={handleLongPress}
181
- onPressIn={handlePressIn}
182
- onPressOut={handlePressOut}
183
- hitSlop={hitSlop}
184
- accessibilityRole="button"
185
- accessibilityLabel={accessibilityLabel}
186
- accessibilityHint={accessibilityHint}
187
- accessibilityState={{
188
- disabled: isDisabled,
189
-
190
- busy: loading,
191
- }}
192
- style={buttonStyle}
193
- >
194
- <View style={[styles.iconContainer, iconContainerStyle]}>
195
- {loading ? (
196
- <ActivityIndicator size="small" color={resolvedColors.icon} />
197
- ) : (
198
- icon
199
- )}
200
- </View>
201
- </Pressable>
248
+ <Animated.View style={buttonStyle}>
249
+ <Pressable
250
+ {...props}
251
+ testID={testID}
252
+ disabled={isDisabled}
253
+ onPress={handlePress}
254
+ onLongPress={handleLongPress}
255
+ onPressIn={handlePressIn}
256
+ onPressOut={handlePressOut}
257
+ hitSlop={hitSlop}
258
+ accessibilityRole="button"
259
+ accessibilityLabel={accessibilityLabel}
260
+ accessibilityHint={accessibilityHint}
261
+ accessibilityState={{
262
+ disabled: isDisabled,
263
+
264
+ busy: loading,
265
+ }}
266
+ style={styles.pressable}
267
+ >
268
+ <View style={[styles.iconContainer, iconContainerStyle]}>
269
+ {loading ? (
270
+ <ActivityIndicator size="small" color={variantColors.icon} />
271
+ ) : (
272
+ icon
273
+ )}
274
+ </View>
275
+ </Pressable>
276
+ </Animated.View>
202
277
  );
203
278
  }
204
279
 
@@ -230,10 +305,7 @@ function getVariantColors(variant, colors, disabled) {
230
305
 
231
306
  borderWidth: 1,
232
307
 
233
- icon: colors.buttonDisabledText || "#A3A3A3",
234
-
235
- pressed:
236
- colors.buttonDisabledBackground || FALLBACK_COLORS.disabledBackground,
308
+ icon: colors.buttonDisabledText || FALLBACK_COLORS.disabledText,
237
309
  };
238
310
  }
239
311
 
@@ -247,21 +319,17 @@ function getVariantColors(variant, colors, disabled) {
247
319
  borderWidth: 1,
248
320
 
249
321
  icon: colors.buttonPrimaryText || white,
250
-
251
- pressed: colors.buttonPrimaryPressed || primaryPressed,
252
322
  };
253
323
 
254
324
  case VARIANTS.outline:
255
325
  return {
256
- background: "transparent",
326
+ background: colors.buttonOutlineBackground || "transparent",
257
327
 
258
328
  border: colors.buttonOutlineBorder || primary,
259
329
 
260
330
  borderWidth: 1,
261
331
 
262
332
  icon: colors.buttonOutlineText || primary,
263
-
264
- pressed: colors.buttonSoftBackground || primarySoft,
265
333
  };
266
334
 
267
335
  case VARIANTS.soft:
@@ -273,8 +341,6 @@ function getVariantColors(variant, colors, disabled) {
273
341
  borderWidth: 1,
274
342
 
275
343
  icon: colors.buttonSoftText || primary,
276
-
277
- pressed: colors.primaryMuted || primarySoft,
278
344
  };
279
345
 
280
346
  case VARIANTS.danger:
@@ -286,8 +352,6 @@ function getVariantColors(variant, colors, disabled) {
286
352
  borderWidth: 1,
287
353
 
288
354
  icon: colors.buttonDangerText || white,
289
-
290
- pressed: colors.buttonDangerPressed || dangerPressed,
291
355
  };
292
356
 
293
357
  case VARIANTS.success:
@@ -299,22 +363,18 @@ function getVariantColors(variant, colors, disabled) {
299
363
  borderWidth: 1,
300
364
 
301
365
  icon: colors.buttonSuccessText || white,
302
-
303
- pressed: colors.buttonSuccessPressed || successPressed,
304
366
  };
305
367
 
306
368
  case VARIANTS.ghost:
307
369
  default:
308
370
  return {
309
- background: "transparent",
371
+ background: colors.buttonGhostBackground || "transparent",
310
372
 
311
373
  border: "transparent",
312
374
 
313
375
  borderWidth: 0,
314
376
 
315
377
  icon: colors.buttonGhostText || primary,
316
-
317
- pressed: colors.buttonSoftBackground || primarySoft,
318
378
  };
319
379
  }
320
380
  }
@@ -383,11 +443,19 @@ const styles = StyleSheet.create({
383
443
 
384
444
  justifyContent: "center",
385
445
 
386
- overflow: "hidden",
387
-
388
446
  flexShrink: 0,
389
447
  },
390
448
 
449
+ pressable: {
450
+ width: "100%",
451
+
452
+ height: "100%",
453
+
454
+ alignItems: "center",
455
+
456
+ justifyContent: "center",
457
+ },
458
+
391
459
  iconContainer: {
392
460
  width: "100%",
393
461