rnnovaui 0.1.6 → 0.1.7

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.1.7",
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 };