rnnovaui 0.1.2 → 0.1.3

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.2",
3
+ "version": "0.1.3",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "react-native": "src/index.js",
@@ -1,10 +1,16 @@
1
1
  import React, { memo, useCallback } from "react";
2
2
 
3
- import { ActivityIndicator, Pressable, StyleSheet, View } from "react-native";
3
+ import {
4
+ ActivityIndicator,
5
+ Pressable,
6
+ StyleSheet,
7
+ Text,
8
+ View,
9
+ } from "react-native";
4
10
 
5
11
  import { useUITheme } from "../../theme";
6
12
 
7
- const BUTTON_VARIANTS = {
13
+ const VARIANTS = {
8
14
  solid: "solid",
9
15
  outline: "outline",
10
16
  ghost: "ghost",
@@ -13,14 +19,14 @@ const BUTTON_VARIANTS = {
13
19
  success: "success",
14
20
  };
15
21
 
16
- const BUTTON_SIZES = {
22
+ const SIZES = {
17
23
  sm: "sm",
18
24
  md: "md",
19
25
  lg: "lg",
20
26
  xl: "xl",
21
27
  };
22
28
 
23
- const UIButtonComponent = ({
29
+ function UIButtonComponent({
24
30
  title,
25
31
  children,
26
32
 
@@ -31,8 +37,8 @@ const UIButtonComponent = ({
31
37
  loading = false,
32
38
  fullWidth = false,
33
39
 
34
- leftIcon = null,
35
- rightIcon = null,
40
+ leftIcon,
41
+ rightIcon,
36
42
 
37
43
  onPress,
38
44
  onLongPress,
@@ -45,28 +51,33 @@ const UIButtonComponent = ({
45
51
 
46
52
  activeOpacity = 0.82,
47
53
 
48
- android_ripple = true,
49
-
50
- hitSlop,
51
-
54
+ testID,
52
55
  accessibilityLabel,
53
56
  accessibilityHint,
54
57
 
55
- testID,
56
-
57
58
  ...props
58
- }) => {
59
- const { theme } = useUITheme();
59
+ }) {
60
+ const themeResult = useUITheme();
60
61
 
61
- const safeVariant = BUTTON_VARIANTS[variant] || BUTTON_VARIANTS.solid;
62
+ /*
63
+ * Support both possible provider shapes:
64
+ *
65
+ * themeResult.theme.colors
66
+ * themeResult.colors
67
+ */
68
+ const theme = themeResult?.theme || themeResult || {};
62
69
 
63
- const safeSize = BUTTON_SIZES[size] || BUTTON_SIZES.md;
70
+ const colors = theme.colors || {};
64
71
 
65
- const isDisabled = disabled || loading;
72
+ const safeVariant = VARIANTS[variant] || VARIANTS.solid;
66
73
 
67
- const variantStyle = resolveVariant(safeVariant, theme.colors);
74
+ const safeSize = SIZES[size] || SIZES.md;
68
75
 
69
- const sizeStyle = resolveSize(safeSize, theme);
76
+ const buttonColors = getButtonColors(safeVariant, colors);
77
+
78
+ const dimensions = getButtonDimensions(safeSize);
79
+
80
+ const isDisabled = disabled || loading;
70
81
 
71
82
  const handlePress = useCallback(
72
83
  (event) => {
@@ -74,9 +85,7 @@ const UIButtonComponent = ({
74
85
  return;
75
86
  }
76
87
 
77
- if (typeof onPress === "function") {
78
- onPress(event);
79
- }
88
+ onPress?.(event);
80
89
  },
81
90
  [isDisabled, onPress],
82
91
  );
@@ -87,9 +96,7 @@ const UIButtonComponent = ({
87
96
  return;
88
97
  }
89
98
 
90
- if (typeof onLongPress === "function") {
91
- onLongPress(event);
92
- }
99
+ onLongPress?.(event);
93
100
  },
94
101
  [isDisabled, onLongPress],
95
102
  );
@@ -100,9 +107,7 @@ const UIButtonComponent = ({
100
107
  return;
101
108
  }
102
109
 
103
- if (typeof onPressIn === "function") {
104
- onPressIn(event);
105
- }
110
+ onPressIn?.(event);
106
111
  },
107
112
  [isDisabled, onPressIn],
108
113
  );
@@ -113,20 +118,11 @@ const UIButtonComponent = ({
113
118
  return;
114
119
  }
115
120
 
116
- if (typeof onPressOut === "function") {
117
- onPressOut(event);
118
- }
121
+ onPressOut?.(event);
119
122
  },
120
123
  [isDisabled, onPressOut],
121
124
  );
122
125
 
123
- const ripple = android_ripple
124
- ? {
125
- color: variantStyle.ripple,
126
- borderless: false,
127
- }
128
- : undefined;
129
-
130
126
  const hasChildren = children !== undefined && children !== null;
131
127
 
132
128
  return (
@@ -138,8 +134,6 @@ const UIButtonComponent = ({
138
134
  onLongPress={handleLongPress}
139
135
  onPressIn={handlePressIn}
140
136
  onPressOut={handlePressOut}
141
- hitSlop={hitSlop}
142
- android_ripple={ripple}
143
137
  accessibilityRole="button"
144
138
  accessibilityLabel={
145
139
  accessibilityLabel || (typeof title === "string" ? title : undefined)
@@ -153,17 +147,19 @@ const UIButtonComponent = ({
153
147
  styles.button,
154
148
 
155
149
  {
156
- minHeight: sizeStyle.height,
150
+ height: dimensions.height,
157
151
 
158
- paddingHorizontal: sizeStyle.paddingHorizontal,
152
+ minHeight: dimensions.height,
159
153
 
160
- borderRadius: sizeStyle.borderRadius,
154
+ paddingHorizontal: dimensions.paddingHorizontal,
161
155
 
162
- backgroundColor: variantStyle.background,
156
+ borderRadius: dimensions.borderRadius,
163
157
 
164
- borderColor: variantStyle.border,
158
+ backgroundColor: buttonColors.background,
165
159
 
166
- borderWidth: variantStyle.border ? 1 : 0,
160
+ borderColor: buttonColors.border,
161
+
162
+ borderWidth: buttonColors.border ? 1 : 0,
167
163
 
168
164
  width: fullWidth ? "100%" : undefined,
169
165
 
@@ -178,236 +174,164 @@ const UIButtonComponent = ({
178
174
  styles.content,
179
175
 
180
176
  {
181
- minHeight: sizeStyle.height - 2,
182
-
183
- gap: sizeStyle.gap,
177
+ gap: dimensions.gap,
184
178
  },
185
179
 
186
180
  contentStyle,
187
181
  ]}
188
182
  >
189
183
  {loading ? (
190
- <ActivityIndicator size="small" color={variantStyle.text} />
184
+ <ActivityIndicator size="small" color={buttonColors.text} />
191
185
  ) : leftIcon ? (
192
- <View style={styles.iconContainer}>{leftIcon}</View>
186
+ <View style={styles.icon}>{leftIcon}</View>
193
187
  ) : null}
194
188
 
195
189
  {hasChildren ? (
196
190
  <View style={styles.children}>{children}</View>
197
- ) : title !== undefined && title !== null ? (
198
- <ButtonText
199
- color={variantStyle.text}
200
- sizeStyle={sizeStyle}
201
- style={textStyle}
191
+ ) : title ? (
192
+ <Text
193
+ numberOfLines={1}
194
+ style={[
195
+ styles.text,
196
+
197
+ {
198
+ color: buttonColors.text,
199
+
200
+ fontSize: dimensions.fontSize,
201
+
202
+ lineHeight: dimensions.lineHeight,
203
+ },
204
+
205
+ textStyle,
206
+ ]}
202
207
  >
203
208
  {title}
204
- </ButtonText>
209
+ </Text>
205
210
  ) : null}
206
211
 
207
212
  {!loading && rightIcon ? (
208
- <View style={styles.iconContainer}>{rightIcon}</View>
213
+ <View style={styles.icon}>{rightIcon}</View>
209
214
  ) : null}
210
215
  </View>
211
216
  </Pressable>
212
217
  );
213
- };
214
-
215
- function ButtonText({ children, color, sizeStyle, style }) {
216
- return (
217
- <View style={styles.textWrapper}>
218
- <ButtonTextNative color={color} sizeStyle={sizeStyle} style={style}>
219
- {children}
220
- </ButtonTextNative>
221
- </View>
222
- );
223
218
  }
224
219
 
225
- function ButtonTextNative({ children, color, sizeStyle, style }) {
226
- const { theme } = useUITheme();
227
-
228
- const { Text } = require("react-native");
229
-
230
- return (
231
- <Text
232
- numberOfLines={1}
233
- style={[
234
- {
235
- color,
236
-
237
- fontSize: sizeStyle.fontSize,
238
-
239
- lineHeight: sizeStyle.lineHeight,
240
-
241
- fontWeight: "600",
242
-
243
- textAlign: "center",
244
- },
245
-
246
- style,
247
- ]}
248
- >
249
- {children}
250
- </Text>
251
- );
252
- }
253
-
254
- function resolveVariant(variant, colors) {
220
+ /**
221
+ * IMPORTANT:
222
+ *
223
+ * Variant resolution is completely independent
224
+ * from spacing/radius/typography.
225
+ *
226
+ * Therefore even if the theme is incomplete,
227
+ * variants still work.
228
+ */
229
+ function getButtonColors(variant, colors) {
255
230
  const primary = colors.primary || "#FF5A1F";
256
231
 
257
232
  const primarySoft = colors.primarySoft || "#FFF0EA";
258
233
 
259
- const primaryPressed = colors.primaryPressed || primary;
260
-
261
234
  const success = colors.success || "#16A34A";
262
235
 
263
236
  const danger = colors.danger || "#DC2626";
264
237
 
265
- const surface = colors.surface || "#F5F5F5";
266
-
267
- const border = colors.border || "#E5E5E5";
268
-
269
- const borderStrong = colors.borderStrong || "#D4D4D4";
270
-
271
238
  const text = colors.text || "#111111";
272
239
 
273
240
  const onPrimary = colors.onPrimary || "#FFFFFF";
274
241
 
242
+ const border = colors.border || "#E5E5E5";
243
+
275
244
  switch (variant) {
276
- case BUTTON_VARIANTS.outline:
245
+ case VARIANTS.outline:
277
246
  return {
278
- background: colors.transparent || "transparent",
279
-
247
+ background: "transparent",
280
248
  border: primary,
281
-
282
249
  text: primary,
283
-
284
- ripple: primarySoft,
285
250
  };
286
251
 
287
- case BUTTON_VARIANTS.ghost:
252
+ case VARIANTS.ghost:
288
253
  return {
289
- background: colors.transparent || "transparent",
290
-
254
+ background: "transparent",
291
255
  border: null,
292
-
293
256
  text: primary,
294
-
295
- ripple: primarySoft,
296
257
  };
297
258
 
298
- case BUTTON_VARIANTS.soft:
259
+ case VARIANTS.soft:
299
260
  return {
300
261
  background: primarySoft,
301
-
302
262
  border: null,
303
-
304
263
  text: primary,
305
-
306
- ripple: primary,
307
264
  };
308
265
 
309
- case BUTTON_VARIANTS.danger:
266
+ case VARIANTS.danger:
310
267
  return {
311
268
  background: danger,
312
-
313
269
  border: danger,
314
-
315
270
  text: onPrimary,
316
-
317
- ripple: danger,
318
271
  };
319
272
 
320
- case BUTTON_VARIANTS.success:
273
+ case VARIANTS.success:
321
274
  return {
322
275
  background: success,
323
-
324
276
  border: success,
325
-
326
277
  text: onPrimary,
327
-
328
- ripple: success,
329
278
  };
330
279
 
331
- case BUTTON_VARIANTS.solid:
280
+ case VARIANTS.solid:
332
281
  default:
333
282
  return {
334
283
  background: primary,
335
-
336
284
  border: primary,
337
-
338
285
  text: onPrimary,
339
-
340
- ripple: primaryPressed,
341
286
  };
342
287
  }
343
288
  }
344
289
 
345
- function resolveSize(size, theme) {
346
- const spacing = theme.spacing;
347
-
348
- const sizes = theme.sizes;
349
-
350
- const radius = theme.radius;
351
-
290
+ /**
291
+ * Sizes intentionally use fixed fallback
292
+ * values so the button cannot break when
293
+ * theme.sizes is missing.
294
+ */
295
+ function getButtonDimensions(size) {
352
296
  switch (size) {
353
- case BUTTON_SIZES.sm:
297
+ case SIZES.sm:
354
298
  return {
355
- height: sizes.button.sm,
356
-
357
- paddingHorizontal: spacing.md,
358
-
359
- gap: spacing.xs,
360
-
361
- borderRadius: radius.button,
362
-
299
+ height: 36,
300
+ paddingHorizontal: 14,
301
+ gap: 6,
302
+ borderRadius: 10,
363
303
  fontSize: 13,
364
-
365
304
  lineHeight: 18,
366
305
  };
367
306
 
368
- case BUTTON_SIZES.lg:
307
+ case SIZES.lg:
369
308
  return {
370
- height: sizes.button.lg,
371
-
372
- paddingHorizontal: spacing.xl,
373
-
374
- gap: spacing.sm,
375
-
376
- borderRadius: radius.button,
377
-
309
+ height: 52,
310
+ paddingHorizontal: 22,
311
+ gap: 8,
312
+ borderRadius: 14,
378
313
  fontSize: 16,
379
-
380
314
  lineHeight: 22,
381
315
  };
382
316
 
383
- case BUTTON_SIZES.xl:
317
+ case SIZES.xl:
384
318
  return {
385
- height: sizes.button.xl,
386
-
387
- paddingHorizontal: spacing.xl2,
388
-
389
- gap: spacing.sm,
390
-
391
- borderRadius: radius.button,
392
-
319
+ height: 60,
320
+ paddingHorizontal: 26,
321
+ gap: 8,
322
+ borderRadius: 16,
393
323
  fontSize: 17,
394
-
395
324
  lineHeight: 24,
396
325
  };
397
326
 
398
- case BUTTON_SIZES.md:
327
+ case SIZES.md:
399
328
  default:
400
329
  return {
401
- height: sizes.button.md,
402
-
403
- paddingHorizontal: spacing.lg,
404
-
405
- gap: spacing.sm,
406
-
407
- borderRadius: radius.button,
408
-
330
+ height: 44,
331
+ paddingHorizontal: 18,
332
+ gap: 8,
333
+ borderRadius: 12,
409
334
  fontSize: 14,
410
-
411
335
  lineHeight: 20,
412
336
  };
413
337
  }
@@ -415,14 +339,13 @@ function resolveSize(size, theme) {
415
339
 
416
340
  const styles = StyleSheet.create({
417
341
  button: {
342
+ flexShrink: 0,
418
343
  alignItems: "center",
419
344
  justifyContent: "center",
420
345
  overflow: "hidden",
421
- flexShrink: 0,
422
346
  },
423
347
 
424
348
  content: {
425
- width: "100%",
426
349
  flexDirection: "row",
427
350
  alignItems: "center",
428
351
  justifyContent: "center",
@@ -435,14 +358,17 @@ const styles = StyleSheet.create({
435
358
  justifyContent: "center",
436
359
  },
437
360
 
438
- iconContainer: {
361
+ icon: {
439
362
  alignItems: "center",
440
363
  justifyContent: "center",
441
364
  flexShrink: 0,
442
365
  },
443
366
 
444
- textWrapper: {
367
+ text: {
445
368
  flexShrink: 1,
369
+ fontWeight: "600",
370
+ textAlign: "center",
371
+ includeFontPadding: false,
446
372
  },
447
373
  });
448
374
 
@@ -450,4 +376,6 @@ export const UIButton = memo(UIButtonComponent);
450
376
 
451
377
  UIButton.displayName = "UIButton";
452
378
 
453
- export { BUTTON_VARIANTS as UIButtonVariants, BUTTON_SIZES as UIButtonSizes };
379
+ export const UIButtonVariants = VARIANTS;
380
+
381
+ export const UIButtonSizes = SIZES;