rnnovaui 0.1.6 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnnovaui",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "react-native": "src/index.js",
@@ -1,4 +1,4 @@
1
- import React, { memo, useCallback } from "react";
1
+ import React, { memo, useCallback, useMemo } from "react";
2
2
 
3
3
  import {
4
4
  ActivityIndicator,
@@ -10,7 +10,7 @@ import {
10
10
 
11
11
  import { useUITheme } from "../../theme";
12
12
 
13
- const BUTTON_VARIANTS = {
13
+ const VARIANTS = {
14
14
  solid: "solid",
15
15
  outline: "outline",
16
16
  ghost: "ghost",
@@ -19,171 +19,224 @@ const BUTTON_VARIANTS = {
19
19
  success: "success",
20
20
  };
21
21
 
22
- const BUTTON_SIZES = {
22
+ const SIZES = {
23
23
  sm: "sm",
24
24
  md: "md",
25
25
  lg: "lg",
26
26
  xl: "xl",
27
27
  };
28
28
 
29
- const DEFAULT_COLORS = {
30
- buttonPrimaryBackground: "#FF5A1F",
29
+ const FALLBACK = {
30
+ primary: "#FF5A1F",
31
+ primaryPressed: "#E94D17",
32
+ primarySoft: "#FFF0EA",
31
33
 
32
- buttonPrimaryPressed: "#E94D17",
34
+ success: "#16A34A",
35
+ successPressed: "#128238",
33
36
 
34
- buttonPrimaryText: "#FFFFFF",
37
+ danger: "#DC2626",
38
+ dangerPressed: "#B91C1C",
35
39
 
36
- buttonOutlineBackground: "transparent",
40
+ white: "#FFFFFF",
37
41
 
38
- buttonOutlineBorder: "#FF5A1F",
42
+ disabledBackground: "#E5E5E5",
43
+ disabledText: "#A3A3A3",
44
+ };
39
45
 
40
- buttonOutlineText: "#FF5A1F",
46
+ function UIButton({
47
+ title,
48
+ children,
41
49
 
42
- buttonGhostBackground: "transparent",
50
+ variant = "solid",
51
+ size = "md",
43
52
 
44
- buttonGhostText: "#FF5A1F",
53
+ disabled = false,
54
+ loading = false,
45
55
 
46
- buttonSoftBackground: "#FFF0EA",
56
+ fullWidth = false,
47
57
 
48
- buttonSoftText: "#FF5A1F",
58
+ leftIcon,
59
+ rightIcon,
49
60
 
50
- buttonDangerBackground: "#DC2626",
61
+ onPress,
62
+ onLongPress,
51
63
 
52
- buttonDangerPressed: "#B91C1C",
64
+ style,
65
+ contentStyle,
66
+ textStyle,
53
67
 
54
- buttonDangerText: "#FFFFFF",
68
+ testID,
55
69
 
56
- buttonSuccessBackground: "#16A34A",
70
+ ...props
71
+ }) {
72
+ const { theme } = useUITheme();
57
73
 
58
- buttonSuccessPressed: "#128238",
74
+ const colors = theme?.colors || {};
59
75
 
60
- buttonSuccessText: "#FFFFFF",
76
+ const primary = colors.primary || FALLBACK.primary;
61
77
 
62
- buttonDisabledBackground: "#E5E5E5",
78
+ const primaryPressed = colors.primaryPressed || FALLBACK.primaryPressed;
63
79
 
64
- buttonDisabledText: "#A3A3A3",
80
+ const primarySoft = colors.primarySoft || FALLBACK.primarySoft;
65
81
 
66
- buttonDisabledBorder: "#E5E5E5",
82
+ const success = colors.success || FALLBACK.success;
67
83
 
68
- buttonRipple: "rgba(255,255,255,0.20)",
69
- };
84
+ const successPressed = colors.successPressed || FALLBACK.successPressed;
70
85
 
71
- const UIButtonComponent = ({
72
- title,
86
+ const danger = colors.danger || FALLBACK.danger;
73
87
 
74
- children,
88
+ const dangerPressed = colors.dangerPressed || FALLBACK.dangerPressed;
75
89
 
76
- variant = "solid",
90
+ const white = colors.onPrimary || FALLBACK.white;
77
91
 
78
- size = "md",
92
+ const isDisabled = disabled || loading;
79
93
 
80
- disabled = false,
94
+ const buttonColors = useMemo(() => {
95
+ if (isDisabled) {
96
+ return {
97
+ background:
98
+ colors.buttonDisabledBackground || FALLBACK.disabledBackground,
81
99
 
82
- loading = false,
100
+ border: colors.buttonDisabledBorder || FALLBACK.disabledBackground,
83
101
 
84
- fullWidth = false,
102
+ text: colors.buttonDisabledText || FALLBACK.disabledText,
85
103
 
86
- leftIcon = null,
104
+ borderWidth: 1,
105
+ };
106
+ }
87
107
 
88
- rightIcon = null,
108
+ switch (variant) {
109
+ case "outline":
110
+ return {
111
+ background: "transparent",
89
112
 
90
- onPress,
113
+ border: colors.buttonOutlineBorder || primary,
91
114
 
92
- onLongPress,
115
+ text: colors.buttonOutlineText || primary,
93
116
 
94
- onPressIn,
117
+ borderWidth: 1,
118
+ };
95
119
 
96
- onPressOut,
120
+ case "ghost":
121
+ return {
122
+ background: "transparent",
97
123
 
98
- style,
124
+ border: "transparent",
99
125
 
100
- contentStyle,
126
+ text: colors.buttonGhostText || primary,
101
127
 
102
- textStyle,
128
+ borderWidth: 0,
129
+ };
103
130
 
104
- activeOpacity = 0.82,
131
+ case "soft":
132
+ return {
133
+ background: colors.buttonSoftBackground || primarySoft,
105
134
 
106
- testID,
135
+ border: colors.buttonSoftBackground || primarySoft,
107
136
 
108
- accessibilityLabel,
137
+ text: colors.buttonSoftText || primary,
109
138
 
110
- accessibilityHint,
139
+ borderWidth: 1,
140
+ };
111
141
 
112
- ...props
113
- }) => {
114
- const { theme } = useUITheme();
142
+ case "danger":
143
+ return {
144
+ background: colors.buttonDangerBackground || danger,
115
145
 
116
- const colors = {
117
- ...DEFAULT_COLORS,
118
- ...(theme?.colors || {}),
119
- };
146
+ border: colors.buttonDangerBackground || danger,
120
147
 
121
- const safeVariant = BUTTON_VARIANTS[variant]
122
- ? variant
123
- : BUTTON_VARIANTS.solid;
148
+ text: colors.buttonDangerText || white,
124
149
 
125
- const safeSize = BUTTON_SIZES[size] ? size : BUTTON_SIZES.md;
150
+ borderWidth: 1,
151
+ };
126
152
 
127
- const isDisabled = disabled || loading;
153
+ case "success":
154
+ return {
155
+ background: colors.buttonSuccessBackground || success,
128
156
 
129
- const variantStyle = getVariantStyle(safeVariant, colors, isDisabled);
157
+ border: colors.buttonSuccessBackground || success,
130
158
 
131
- const sizeStyle = getSizeStyle(safeSize, theme);
159
+ text: colors.buttonSuccessText || white,
132
160
 
133
- const handlePress = useCallback(
134
- (event) => {
135
- if (isDisabled) {
136
- return;
137
- }
161
+ borderWidth: 1,
162
+ };
138
163
 
139
- if (typeof onPress === "function") {
140
- onPress(event);
141
- }
142
- },
143
- [isDisabled, onPress],
144
- );
164
+ case "solid":
165
+ default:
166
+ return {
167
+ background: colors.buttonPrimaryBackground || primary,
145
168
 
146
- const handleLongPress = useCallback(
147
- (event) => {
148
- if (isDisabled) {
149
- return;
150
- }
169
+ border: colors.buttonPrimaryBackground || primary,
151
170
 
152
- if (typeof onLongPress === "function") {
153
- onLongPress(event);
154
- }
155
- },
156
- [isDisabled, onLongPress],
171
+ text: colors.buttonPrimaryText || white,
172
+
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]);
188
+
189
+ const buttonStyle = useMemo(
190
+ () => [
191
+ styles.button,
192
+
193
+ {
194
+ height: dimensions.height,
195
+
196
+ minHeight: dimensions.height,
197
+
198
+ paddingHorizontal: dimensions.paddingHorizontal,
199
+
200
+ borderRadius: dimensions.borderRadius,
201
+
202
+ backgroundColor: buttonColors.background,
203
+
204
+ borderColor: buttonColors.border,
205
+
206
+ borderWidth: buttonColors.borderWidth,
207
+
208
+ width: fullWidth ? "100%" : undefined,
209
+
210
+ opacity: isDisabled ? 0.55 : 1,
211
+ },
212
+
213
+ style,
214
+ ],
215
+ [dimensions, buttonColors, fullWidth, isDisabled, style],
157
216
  );
158
217
 
159
- const handlePressIn = useCallback(
218
+ const handlePress = useCallback(
160
219
  (event) => {
161
220
  if (isDisabled) {
162
221
  return;
163
222
  }
164
223
 
165
- if (typeof onPressIn === "function") {
166
- onPressIn(event);
167
- }
224
+ onPress?.(event);
168
225
  },
169
- [isDisabled, onPressIn],
226
+ [isDisabled, onPress],
170
227
  );
171
228
 
172
- const handlePressOut = useCallback(
229
+ const handleLongPress = useCallback(
173
230
  (event) => {
174
231
  if (isDisabled) {
175
232
  return;
176
233
  }
177
234
 
178
- if (typeof onPressOut === "function") {
179
- onPressOut(event);
180
- }
235
+ onLongPress?.(event);
181
236
  },
182
- [isDisabled, onPressOut],
237
+ [isDisabled, onLongPress],
183
238
  );
184
239
 
185
- const hasChildren = children !== undefined && children !== null;
186
-
187
240
  return (
188
241
  <Pressable
189
242
  {...props}
@@ -191,281 +244,118 @@ const UIButtonComponent = ({
191
244
  disabled={isDisabled}
192
245
  onPress={handlePress}
193
246
  onLongPress={handleLongPress}
194
- onPressIn={handlePressIn}
195
- onPressOut={handlePressOut}
196
- accessibilityRole="button"
197
- accessibilityLabel={
198
- accessibilityLabel || (typeof title === "string" ? title : undefined)
199
- }
200
- accessibilityHint={accessibilityHint}
201
- accessibilityState={{
202
- disabled: isDisabled,
203
-
204
- busy: loading,
205
- }}
206
- style={({ pressed }) => {
207
- const backgroundColor = isDisabled
208
- ? colors.buttonDisabledBackground
209
- : pressed
210
- ? variantStyle.pressedBackground
211
- : variantStyle.backgroundColor;
212
-
213
- const borderColor = isDisabled
214
- ? colors.buttonDisabledBorder
215
- : variantStyle.borderColor;
216
-
217
- const textColor = isDisabled
218
- ? colors.buttonDisabledText
219
- : variantStyle.textColor;
220
-
221
- return [
222
- styles.button,
223
-
224
- {
225
- height: sizeStyle.height,
226
-
227
- minHeight: sizeStyle.height,
228
-
229
- paddingHorizontal: sizeStyle.paddingHorizontal,
230
-
231
- borderRadius: sizeStyle.borderRadius,
232
-
233
- backgroundColor,
234
-
235
- borderColor,
236
-
237
- borderWidth: variantStyle.borderWidth,
238
-
239
- width: fullWidth ? "100%" : undefined,
240
-
241
- opacity: isDisabled ? 0.55 : 1,
242
- },
243
-
244
- style,
245
- ];
246
- }}
247
+ style={buttonStyle}
247
248
  >
248
249
  <View
249
250
  style={[
250
251
  styles.content,
251
252
 
252
253
  {
253
- gap: sizeStyle.gap,
254
+ gap: dimensions.gap,
254
255
  },
255
256
 
256
257
  contentStyle,
257
258
  ]}
258
259
  >
259
260
  {loading ? (
260
- <ActivityIndicator size="small" color={variantStyle.textColor} />
261
+ <ActivityIndicator size="small" color={buttonColors.text} />
261
262
  ) : (
262
263
  leftIcon && <View style={styles.icon}>{leftIcon}</View>
263
264
  )}
264
265
 
265
- {hasChildren ? (
266
+ {children !== undefined && children !== null ? (
266
267
  <View style={styles.children}>{children}</View>
267
- ) : (
268
- title !== undefined &&
269
- title !== null && (
270
- <Text
271
- numberOfLines={1}
272
- style={[
273
- styles.text,
274
-
275
- {
276
- color: isDisabled
277
- ? colors.buttonDisabledText
278
- : variantStyle.textColor,
279
-
280
- fontSize: sizeStyle.fontSize,
281
-
282
- lineHeight: sizeStyle.lineHeight,
283
- },
284
-
285
- textStyle,
286
- ]}
287
- >
288
- {title}
289
- </Text>
290
- )
291
- )}
292
-
293
- {!loading && rightIcon && <View style={styles.icon}>{rightIcon}</View>}
294
- </View>
295
- </Pressable>
296
- );
297
- };
298
-
299
- function getVariantStyle(variant, colors, disabled) {
300
- if (disabled) {
301
- return {
302
- backgroundColor: colors.buttonDisabledBackground,
303
-
304
- pressedBackground: colors.buttonDisabledBackground,
305
-
306
- borderColor: colors.buttonDisabledBorder,
307
-
308
- borderWidth: 1,
309
-
310
- textColor: colors.buttonDisabledText,
311
- };
312
- }
313
-
314
- switch (variant) {
315
- case BUTTON_VARIANTS.outline:
316
- return {
317
- backgroundColor: colors.buttonOutlineBackground,
318
-
319
- pressedBackground: colors.buttonSoftBackground,
320
-
321
- borderColor: colors.buttonOutlineBorder,
268
+ ) : title !== undefined && title !== null ? (
269
+ <Text
270
+ numberOfLines={1}
271
+ style={[
272
+ styles.text,
322
273
 
323
- borderWidth: 1,
324
-
325
- textColor: colors.buttonOutlineText,
326
- };
327
-
328
- case BUTTON_VARIANTS.ghost:
329
- return {
330
- backgroundColor: colors.buttonGhostBackground,
331
-
332
- pressedBackground: colors.buttonSoftBackground,
274
+ {
275
+ color: buttonColors.text,
333
276
 
334
- borderColor: colors.transparent,
335
-
336
- borderWidth: 0,
337
-
338
- textColor: colors.buttonGhostText,
339
- };
340
-
341
- case BUTTON_VARIANTS.soft:
342
- return {
343
- backgroundColor: colors.buttonSoftBackground,
277
+ fontSize: dimensions.fontSize,
344
278
 
345
- pressedBackground: colors.primaryMuted || colors.buttonSoftBackground,
279
+ lineHeight: dimensions.lineHeight,
280
+ },
346
281
 
347
- borderColor: colors.buttonSoftBackground,
348
-
349
- borderWidth: 1,
350
-
351
- textColor: colors.buttonSoftText,
352
- };
353
-
354
- case BUTTON_VARIANTS.danger:
355
- return {
356
- backgroundColor: colors.buttonDangerBackground,
357
-
358
- pressedBackground: colors.buttonDangerPressed,
359
-
360
- borderColor: colors.buttonDangerBackground,
361
-
362
- borderWidth: 1,
282
+ textStyle,
283
+ ]}
284
+ >
285
+ {title}
286
+ </Text>
287
+ ) : null}
363
288
 
364
- textColor: colors.buttonDangerText,
365
- };
366
-
367
- case BUTTON_VARIANTS.success:
368
- return {
369
- backgroundColor: colors.buttonSuccessBackground,
370
-
371
- pressedBackground: colors.buttonSuccessPressed,
372
-
373
- borderColor: colors.buttonSuccessBackground,
374
-
375
- borderWidth: 1,
376
-
377
- textColor: colors.buttonSuccessText,
378
- };
379
-
380
- case BUTTON_VARIANTS.solid:
381
- default:
382
- return {
383
- backgroundColor: colors.buttonPrimaryBackground,
384
-
385
- pressedBackground: colors.buttonPrimaryPressed,
386
-
387
- borderColor: colors.buttonPrimaryBackground,
388
-
389
- borderWidth: 1,
390
-
391
- textColor: colors.buttonPrimaryText,
392
- };
393
- }
289
+ {!loading && rightIcon && <View style={styles.icon}>{rightIcon}</View>}
290
+ </View>
291
+ </Pressable>
292
+ );
394
293
  }
395
294
 
396
- function getSizeStyle(size, theme) {
295
+ function getDimensions(size, theme) {
397
296
  const buttonSizes = theme?.sizes?.button || {};
398
297
 
399
- const themeRadius = theme?.radius?.button;
400
-
401
- const buttonRadius = typeof themeRadius === "number" ? themeRadius : 12;
298
+ const radius =
299
+ typeof theme?.radius?.button === "number" ? theme.radius.button : 12;
402
300
 
403
301
  const spacing = theme?.spacing || {};
404
302
 
405
- const spacingSM = typeof spacing.sm === "number" ? spacing.sm : 8;
406
-
407
- const spacingMD = typeof spacing.md === "number" ? spacing.md : 16;
408
-
409
- const spacingLG = typeof spacing.lg === "number" ? spacing.lg : 20;
410
-
411
- const spacingXL = typeof spacing.xl === "number" ? spacing.xl : 24;
412
-
413
303
  switch (size) {
414
- case BUTTON_SIZES.sm:
304
+ case "sm":
415
305
  return {
416
- height: buttonSizes.sm ?? 36,
306
+ height: buttonSizes.sm || 36,
417
307
 
418
- paddingHorizontal: spacingMD,
308
+ paddingHorizontal: spacing.md || 16,
419
309
 
420
- gap: spacingSM,
310
+ gap: 6,
421
311
 
422
- borderRadius: buttonRadius,
312
+ borderRadius: radius,
423
313
 
424
314
  fontSize: 13,
425
315
 
426
316
  lineHeight: 18,
427
317
  };
428
318
 
429
- case BUTTON_SIZES.lg:
319
+ case "lg":
430
320
  return {
431
- height: buttonSizes.lg ?? 52,
321
+ height: buttonSizes.lg || 52,
432
322
 
433
- paddingHorizontal: spacingLG,
323
+ paddingHorizontal: spacing.lg || 20,
434
324
 
435
- gap: spacingSM,
325
+ gap: 8,
436
326
 
437
- borderRadius: buttonRadius,
327
+ borderRadius: radius,
438
328
 
439
329
  fontSize: 16,
440
330
 
441
331
  lineHeight: 22,
442
332
  };
443
333
 
444
- case BUTTON_SIZES.xl:
334
+ case "xl":
445
335
  return {
446
- height: buttonSizes.xl ?? 60,
336
+ height: buttonSizes.xl || 60,
447
337
 
448
- paddingHorizontal: spacingXL,
338
+ paddingHorizontal: spacing.xl || 24,
449
339
 
450
- gap: spacingSM,
340
+ gap: 8,
451
341
 
452
- borderRadius: buttonRadius,
342
+ borderRadius: radius,
453
343
 
454
344
  fontSize: 17,
455
345
 
456
346
  lineHeight: 24,
457
347
  };
458
348
 
459
- case BUTTON_SIZES.md:
349
+ case "md":
460
350
  default:
461
351
  return {
462
- height: buttonSizes.md ?? 44,
352
+ height: buttonSizes.md || 44,
463
353
 
464
- paddingHorizontal: spacingLG,
354
+ paddingHorizontal: spacing.md || 16,
465
355
 
466
- gap: spacingSM,
356
+ gap: 8,
467
357
 
468
- borderRadius: buttonRadius,
358
+ borderRadius: radius,
469
359
 
470
360
  fontSize: 14,
471
361
 
@@ -476,13 +366,15 @@ function getSizeStyle(size, theme) {
476
366
 
477
367
  const styles = StyleSheet.create({
478
368
  button: {
479
- flexShrink: 0,
369
+ flexDirection: "row",
480
370
 
481
371
  alignItems: "center",
482
372
 
483
373
  justifyContent: "center",
484
374
 
485
375
  overflow: "hidden",
376
+
377
+ flexShrink: 0,
486
378
  },
487
379
 
488
380
  content: {
@@ -496,11 +388,11 @@ const styles = StyleSheet.create({
496
388
  },
497
389
 
498
390
  children: {
499
- flexShrink: 1,
500
-
501
391
  alignItems: "center",
502
392
 
503
393
  justifyContent: "center",
394
+
395
+ flexShrink: 1,
504
396
  },
505
397
 
506
398
  icon: {
@@ -512,18 +404,16 @@ const styles = StyleSheet.create({
512
404
  },
513
405
 
514
406
  text: {
515
- flexShrink: 1,
516
-
517
407
  fontWeight: "600",
518
408
 
519
409
  textAlign: "center",
520
410
 
521
411
  includeFontPadding: false,
412
+
413
+ flexShrink: 1,
522
414
  },
523
415
  });
524
416
 
525
- export const UIButton = memo(UIButtonComponent);
526
-
527
- UIButton.displayName = "UIButton";
417
+ export default memo(UIButton);
528
418
 
529
- export { BUTTON_VARIANTS as UIButtonVariants, BUTTON_SIZES as UIButtonSizes };
419
+ export { UIButton, VARIANTS as UIButtonVariants, SIZES as UIButtonSizes };
@@ -1,17 +1,9 @@
1
- import React, { memo, useCallback } from "react";
1
+ import React, { memo, useCallback, useMemo } from "react";
2
2
 
3
3
  import { ActivityIndicator, Pressable, StyleSheet, View } from "react-native";
4
4
 
5
5
  import { useUITheme } from "../../theme";
6
6
 
7
- const SIZES = {
8
- xs: "xs",
9
- sm: "sm",
10
- md: "md",
11
- lg: "lg",
12
- xl: "xl",
13
- };
14
-
15
7
  const VARIANTS = {
16
8
  solid: "solid",
17
9
  outline: "outline",
@@ -21,19 +13,47 @@ const VARIANTS = {
21
13
  success: "success",
22
14
  };
23
15
 
16
+ const SIZES = {
17
+ xs: "xs",
18
+ sm: "sm",
19
+ md: "md",
20
+ lg: "lg",
21
+ xl: "xl",
22
+ xxl: "xxl",
23
+ };
24
+
24
25
  const SHAPES = {
25
26
  circle: "circle",
26
27
  rounded: "rounded",
27
28
  square: "square",
28
29
  };
29
30
 
30
- const UIIconButtonComponent = ({
31
- icon,
31
+ const FALLBACK_COLORS = {
32
+ primary: "#FF5A1F",
33
+ primarySoft: "#FFF0EA",
34
+ primaryPressed: "#E94D17",
32
35
 
33
- size = "md",
36
+ success: "#16A34A",
37
+ successPressed: "#128238",
38
+
39
+ danger: "#DC2626",
40
+ dangerPressed: "#B91C1C",
41
+
42
+ white: "#FFFFFF",
43
+
44
+ border: "#E5E5E5",
45
+
46
+ disabledBackground: "#E5E5E5",
47
+ disabledBorder: "#E5E5E5",
48
+ };
49
+
50
+ function UIIconButtonComponent({
51
+ icon,
34
52
 
35
53
  variant = "ghost",
36
54
 
55
+ size = "md",
56
+
37
57
  shape = "circle",
38
58
 
39
59
  disabled = false,
@@ -52,35 +72,31 @@ const UIIconButtonComponent = ({
52
72
 
53
73
  iconContainerStyle,
54
74
 
55
- activeOpacity = 0.82,
56
-
57
- android_ripple = true,
75
+ hitSlop,
58
76
 
59
- hitSlop = 8,
77
+ testID,
60
78
 
61
79
  accessibilityLabel,
62
80
 
63
81
  accessibilityHint,
64
82
 
65
- testID,
66
-
67
83
  ...props
68
- }) => {
84
+ }) {
69
85
  const { theme } = useUITheme();
70
86
 
71
- const safeSize = SIZES[size] ? size : SIZES.md;
72
-
73
- const safeVariant = VARIANTS[variant] ? variant : VARIANTS.ghost;
74
-
75
- const safeShape = SHAPES[shape] ? shape : SHAPES.circle;
87
+ const colors = theme?.colors || {};
76
88
 
77
89
  const isDisabled = disabled || loading;
78
90
 
79
- const dimensions = getDimensions(safeSize, theme);
80
-
81
- const colors = getColors(safeVariant, theme.colors);
91
+ const resolvedColors = useMemo(
92
+ () => getVariantColors(variant, colors, isDisabled),
93
+ [variant, colors, isDisabled],
94
+ );
82
95
 
83
- const borderRadius = getBorderRadius(safeShape, theme);
96
+ const dimensions = useMemo(
97
+ () => getDimensions(size, shape, theme),
98
+ [size, shape, theme],
99
+ );
84
100
 
85
101
  const handlePress = useCallback(
86
102
  (event) => {
@@ -126,12 +142,34 @@ const UIIconButtonComponent = ({
126
142
  [isDisabled, onPressOut],
127
143
  );
128
144
 
129
- const ripple = android_ripple
130
- ? {
131
- color: colors.ripple,
132
- borderless: false,
133
- }
134
- : undefined;
145
+ const buttonStyle = useMemo(
146
+ () => [
147
+ styles.button,
148
+
149
+ {
150
+ width: dimensions.size,
151
+
152
+ height: dimensions.size,
153
+
154
+ minWidth: dimensions.size,
155
+
156
+ minHeight: dimensions.size,
157
+
158
+ borderRadius: dimensions.borderRadius,
159
+
160
+ backgroundColor: resolvedColors.background,
161
+
162
+ borderColor: resolvedColors.border,
163
+
164
+ borderWidth: resolvedColors.borderWidth,
165
+
166
+ opacity: isDisabled ? 0.55 : 1,
167
+ },
168
+
169
+ style,
170
+ ],
171
+ [dimensions, resolvedColors, isDisabled, style],
172
+ );
135
173
 
136
174
  return (
137
175
  <Pressable
@@ -143,173 +181,221 @@ const UIIconButtonComponent = ({
143
181
  onPressIn={handlePressIn}
144
182
  onPressOut={handlePressOut}
145
183
  hitSlop={hitSlop}
146
- android_ripple={ripple}
147
184
  accessibilityRole="button"
148
185
  accessibilityLabel={accessibilityLabel}
149
186
  accessibilityHint={accessibilityHint}
150
187
  accessibilityState={{
151
188
  disabled: isDisabled,
189
+
152
190
  busy: loading,
153
191
  }}
154
- style={({ pressed }) => [
155
- styles.button,
156
-
157
- {
158
- width: dimensions.size,
159
-
160
- height: dimensions.size,
161
-
162
- borderRadius,
163
-
164
- backgroundColor: colors.background,
165
-
166
- borderColor: colors.border,
167
-
168
- borderWidth: colors.border ? 1 : 0,
169
-
170
- opacity: isDisabled ? 0.5 : pressed ? activeOpacity : 1,
171
- },
172
-
173
- style,
174
- ]}
192
+ style={buttonStyle}
175
193
  >
176
194
  <View style={[styles.iconContainer, iconContainerStyle]}>
177
195
  {loading ? (
178
- <ActivityIndicator size="small" color={colors.icon} />
196
+ <ActivityIndicator size="small" color={resolvedColors.icon} />
179
197
  ) : (
180
198
  icon
181
199
  )}
182
200
  </View>
183
201
  </Pressable>
184
202
  );
185
- };
203
+ }
186
204
 
187
- function getDimensions(size, theme) {
188
- switch (size) {
189
- case SIZES.xs:
190
- return {
191
- size: theme.sizes.icon.lg + theme.spacing.sm,
192
- };
205
+ function getVariantColors(variant, colors, disabled) {
206
+ const primary = colors.primary || FALLBACK_COLORS.primary;
193
207
 
194
- case SIZES.sm:
195
- return {
196
- size: theme.sizes.button.sm,
197
- };
208
+ const primarySoft = colors.primarySoft || FALLBACK_COLORS.primarySoft;
198
209
 
199
- case SIZES.lg:
200
- return {
201
- size: theme.sizes.button.lg,
202
- };
210
+ const primaryPressed =
211
+ colors.primaryPressed || FALLBACK_COLORS.primaryPressed;
203
212
 
204
- case SIZES.xl:
205
- return {
206
- size: theme.sizes.button.xl,
207
- };
213
+ const success = colors.success || FALLBACK_COLORS.success;
208
214
 
209
- case SIZES.md:
210
- default:
211
- return {
212
- size: theme.sizes.button.md,
213
- };
214
- }
215
- }
215
+ const successPressed =
216
+ colors.successPressed || FALLBACK_COLORS.successPressed;
216
217
 
217
- function getBorderRadius(shape, theme) {
218
- switch (shape) {
219
- case SHAPES.rounded:
220
- return theme.radius.lg;
218
+ const danger = colors.danger || FALLBACK_COLORS.danger;
221
219
 
222
- case SHAPES.square:
223
- return theme.radius.sm;
220
+ const dangerPressed = colors.dangerPressed || FALLBACK_COLORS.dangerPressed;
224
221
 
225
- case SHAPES.circle:
226
- default:
227
- return theme.radius.circle;
222
+ const white = colors.onPrimary || FALLBACK_COLORS.white;
223
+
224
+ if (disabled) {
225
+ return {
226
+ background:
227
+ colors.buttonDisabledBackground || FALLBACK_COLORS.disabledBackground,
228
+
229
+ border: colors.buttonDisabledBorder || FALLBACK_COLORS.disabledBorder,
230
+
231
+ borderWidth: 1,
232
+
233
+ icon: colors.buttonDisabledText || "#A3A3A3",
234
+
235
+ pressed:
236
+ colors.buttonDisabledBackground || FALLBACK_COLORS.disabledBackground,
237
+ };
228
238
  }
229
- }
230
239
 
231
- function getColors(variant, colors) {
232
240
  switch (variant) {
233
241
  case VARIANTS.solid:
234
242
  return {
235
- background: colors.primary,
243
+ background: colors.buttonPrimaryBackground || primary,
236
244
 
237
- border: colors.primary,
245
+ border: colors.buttonPrimaryBackground || primary,
238
246
 
239
- icon: colors.onPrimary,
247
+ borderWidth: 1,
240
248
 
241
- ripple: colors.primaryPressed,
249
+ icon: colors.buttonPrimaryText || white,
250
+
251
+ pressed: colors.buttonPrimaryPressed || primaryPressed,
242
252
  };
243
253
 
244
254
  case VARIANTS.outline:
245
255
  return {
246
- background: colors.transparent,
256
+ background: "transparent",
257
+
258
+ border: colors.buttonOutlineBorder || primary,
247
259
 
248
- border: colors.borderStrong,
260
+ borderWidth: 1,
249
261
 
250
- icon: colors.text,
262
+ icon: colors.buttonOutlineText || primary,
251
263
 
252
- ripple: colors.surfaceSecondary,
264
+ pressed: colors.buttonSoftBackground || primarySoft,
253
265
  };
254
266
 
255
267
  case VARIANTS.soft:
256
268
  return {
257
- background: colors.primarySoft,
269
+ background: colors.buttonSoftBackground || primarySoft,
258
270
 
259
- border: null,
271
+ border: colors.buttonSoftBackground || primarySoft,
260
272
 
261
- icon: colors.primary,
273
+ borderWidth: 1,
262
274
 
263
- ripple: colors.primary,
275
+ icon: colors.buttonSoftText || primary,
276
+
277
+ pressed: colors.primaryMuted || primarySoft,
264
278
  };
265
279
 
266
280
  case VARIANTS.danger:
267
281
  return {
268
- background: colors.danger,
282
+ background: colors.buttonDangerBackground || danger,
283
+
284
+ border: colors.buttonDangerBackground || danger,
269
285
 
270
- border: colors.danger,
286
+ borderWidth: 1,
271
287
 
272
- icon: colors.onPrimary,
288
+ icon: colors.buttonDangerText || white,
273
289
 
274
- ripple: colors.dangerSoft,
290
+ pressed: colors.buttonDangerPressed || dangerPressed,
275
291
  };
276
292
 
277
293
  case VARIANTS.success:
278
294
  return {
279
- background: colors.success,
295
+ background: colors.buttonSuccessBackground || success,
280
296
 
281
- border: colors.success,
297
+ border: colors.buttonSuccessBackground || success,
282
298
 
283
- icon: colors.onPrimary,
299
+ borderWidth: 1,
284
300
 
285
- ripple: colors.successSoft,
301
+ icon: colors.buttonSuccessText || white,
302
+
303
+ pressed: colors.buttonSuccessPressed || successPressed,
286
304
  };
287
305
 
288
306
  case VARIANTS.ghost:
289
307
  default:
290
308
  return {
291
- background: colors.transparent,
309
+ background: "transparent",
310
+
311
+ border: "transparent",
292
312
 
293
- border: null,
313
+ borderWidth: 0,
294
314
 
295
- icon: colors.text,
315
+ icon: colors.buttonGhostText || primary,
296
316
 
297
- ripple: colors.surfaceSecondary,
317
+ pressed: colors.buttonSoftBackground || primarySoft,
298
318
  };
299
319
  }
300
320
  }
301
321
 
322
+ function getDimensions(size, shape, theme) {
323
+ const iconSizes = theme?.sizes?.icon || {};
324
+
325
+ const radius = theme?.radius || {};
326
+
327
+ let resolvedSize;
328
+
329
+ switch (size) {
330
+ case SIZES.xs:
331
+ resolvedSize = iconSizes.xs ? iconSizes.xs + 16 : 32;
332
+ break;
333
+
334
+ case SIZES.sm:
335
+ resolvedSize = iconSizes.sm ? iconSizes.sm + 16 : 40;
336
+ break;
337
+
338
+ case SIZES.lg:
339
+ resolvedSize = iconSizes.lg ? iconSizes.lg + 20 : 52;
340
+ break;
341
+
342
+ case SIZES.xl:
343
+ resolvedSize = iconSizes.xl ? iconSizes.xl + 24 : 60;
344
+ break;
345
+
346
+ case SIZES.xxl:
347
+ resolvedSize = iconSizes.xxl ? iconSizes.xxl + 28 : 72;
348
+ break;
349
+
350
+ case SIZES.md:
351
+ default:
352
+ resolvedSize = iconSizes.md ? iconSizes.md + 20 : 44;
353
+ break;
354
+ }
355
+
356
+ let borderRadius;
357
+
358
+ switch (shape) {
359
+ case SHAPES.square:
360
+ borderRadius = radius.sm ?? 6;
361
+ break;
362
+
363
+ case SHAPES.rounded:
364
+ borderRadius = radius.button ?? 12;
365
+ break;
366
+
367
+ case SHAPES.circle:
368
+ default:
369
+ borderRadius = resolvedSize / 2;
370
+ break;
371
+ }
372
+
373
+ return {
374
+ size: resolvedSize,
375
+
376
+ borderRadius,
377
+ };
378
+ }
379
+
302
380
  const styles = StyleSheet.create({
303
381
  button: {
304
382
  alignItems: "center",
383
+
305
384
  justifyContent: "center",
385
+
306
386
  overflow: "hidden",
387
+
388
+ flexShrink: 0,
307
389
  },
308
390
 
309
391
  iconContainer: {
392
+ width: "100%",
393
+
394
+ height: "100%",
395
+
310
396
  alignItems: "center",
397
+
311
398
  justifyContent: "center",
312
- flex: 1,
313
399
  },
314
400
  });
315
401
 
@@ -318,7 +404,9 @@ export const UIIconButton = memo(UIIconButtonComponent);
318
404
  UIIconButton.displayName = "UIIconButton";
319
405
 
320
406
  export {
321
- SIZES as UIIconButtonSizes,
322
407
  VARIANTS as UIIconButtonVariants,
408
+ SIZES as UIIconButtonSizes,
323
409
  SHAPES as UIIconButtonShapes,
324
410
  };
411
+
412
+ export default UIIconButton;
@@ -1,6 +1,6 @@
1
1
  export {
2
2
  UIIconButton,
3
- UIIconButtonSizes,
4
3
  UIIconButtonVariants,
4
+ UIIconButtonSizes,
5
5
  UIIconButtonShapes,
6
6
  } from "./UIIconButton";
@@ -2,7 +2,7 @@ export { UIText } from "./Text";
2
2
  export { UIButton, UIButtonVariants, UIButtonSizes } from "./Button";
3
3
  export {
4
4
  UIIconButton,
5
- UIIconButtonSizes,
6
5
  UIIconButtonVariants,
6
+ UIIconButtonSizes,
7
7
  UIIconButtonShapes,
8
8
  } from "./IconButton";
package/src/index.js CHANGED
@@ -21,7 +21,7 @@ export {
21
21
  UIButtonVariants,
22
22
  UIButtonSizes,
23
23
  UIIconButton,
24
- UIIconButtonSizes,
25
24
  UIIconButtonVariants,
25
+ UIIconButtonSizes,
26
26
  UIIconButtonShapes,
27
27
  } from "./components";