rnnovaui 0.1.1 → 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 +1 -1
- package/src/components/Button/UIButton.js +160 -184
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import React, { memo, useCallback } from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
const BUTTON_VARIANTS = {
|
|
13
|
+
const VARIANTS = {
|
|
10
14
|
solid: "solid",
|
|
11
15
|
outline: "outline",
|
|
12
16
|
ghost: "ghost",
|
|
@@ -15,77 +19,65 @@ const BUTTON_VARIANTS = {
|
|
|
15
19
|
success: "success",
|
|
16
20
|
};
|
|
17
21
|
|
|
18
|
-
const
|
|
22
|
+
const SIZES = {
|
|
19
23
|
sm: "sm",
|
|
20
24
|
md: "md",
|
|
21
25
|
lg: "lg",
|
|
22
26
|
xl: "xl",
|
|
23
27
|
};
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
function UIButtonComponent({
|
|
26
30
|
title,
|
|
27
|
-
|
|
28
31
|
children,
|
|
29
32
|
|
|
30
33
|
variant = "solid",
|
|
31
|
-
|
|
32
34
|
size = "md",
|
|
33
35
|
|
|
34
36
|
disabled = false,
|
|
35
|
-
|
|
36
37
|
loading = false,
|
|
37
|
-
|
|
38
38
|
fullWidth = false,
|
|
39
39
|
|
|
40
|
-
leftIcon
|
|
41
|
-
|
|
42
|
-
rightIcon = null,
|
|
40
|
+
leftIcon,
|
|
41
|
+
rightIcon,
|
|
43
42
|
|
|
44
43
|
onPress,
|
|
45
|
-
|
|
46
44
|
onLongPress,
|
|
47
|
-
|
|
48
45
|
onPressIn,
|
|
49
|
-
|
|
50
46
|
onPressOut,
|
|
51
47
|
|
|
52
48
|
style,
|
|
53
|
-
|
|
54
49
|
contentStyle,
|
|
55
|
-
|
|
56
50
|
textStyle,
|
|
57
51
|
|
|
58
|
-
|
|
52
|
+
activeOpacity = 0.82,
|
|
59
53
|
|
|
54
|
+
testID,
|
|
60
55
|
accessibilityLabel,
|
|
61
|
-
|
|
62
56
|
accessibilityHint,
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
pressRetentionOffset,
|
|
58
|
+
...props
|
|
59
|
+
}) {
|
|
60
|
+
const themeResult = useUITheme();
|
|
69
61
|
|
|
70
|
-
|
|
62
|
+
/*
|
|
63
|
+
* Support both possible provider shapes:
|
|
64
|
+
*
|
|
65
|
+
* themeResult.theme.colors
|
|
66
|
+
* themeResult.colors
|
|
67
|
+
*/
|
|
68
|
+
const theme = themeResult?.theme || themeResult || {};
|
|
71
69
|
|
|
72
|
-
|
|
70
|
+
const colors = theme.colors || {};
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
}) => {
|
|
76
|
-
const { theme } = useUITheme();
|
|
72
|
+
const safeVariant = VARIANTS[variant] || VARIANTS.solid;
|
|
77
73
|
|
|
78
|
-
const
|
|
79
|
-
? variant
|
|
80
|
-
: BUTTON_VARIANTS.solid;
|
|
74
|
+
const safeSize = SIZES[size] || SIZES.md;
|
|
81
75
|
|
|
82
|
-
const
|
|
76
|
+
const buttonColors = getButtonColors(safeVariant, colors);
|
|
83
77
|
|
|
84
|
-
const
|
|
78
|
+
const dimensions = getButtonDimensions(safeSize);
|
|
85
79
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
const dimensions = getSizeDimensions(safeSize, theme);
|
|
80
|
+
const isDisabled = disabled || loading;
|
|
89
81
|
|
|
90
82
|
const handlePress = useCallback(
|
|
91
83
|
(event) => {
|
|
@@ -93,9 +85,7 @@ const UIButtonComponent = ({
|
|
|
93
85
|
return;
|
|
94
86
|
}
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
onPress(event);
|
|
98
|
-
}
|
|
88
|
+
onPress?.(event);
|
|
99
89
|
},
|
|
100
90
|
[isDisabled, onPress],
|
|
101
91
|
);
|
|
@@ -106,9 +96,7 @@ const UIButtonComponent = ({
|
|
|
106
96
|
return;
|
|
107
97
|
}
|
|
108
98
|
|
|
109
|
-
|
|
110
|
-
onLongPress(event);
|
|
111
|
-
}
|
|
99
|
+
onLongPress?.(event);
|
|
112
100
|
},
|
|
113
101
|
[isDisabled, onLongPress],
|
|
114
102
|
);
|
|
@@ -119,9 +107,7 @@ const UIButtonComponent = ({
|
|
|
119
107
|
return;
|
|
120
108
|
}
|
|
121
109
|
|
|
122
|
-
|
|
123
|
-
onPressIn(event);
|
|
124
|
-
}
|
|
110
|
+
onPressIn?.(event);
|
|
125
111
|
},
|
|
126
112
|
[isDisabled, onPressIn],
|
|
127
113
|
);
|
|
@@ -132,34 +118,12 @@ const UIButtonComponent = ({
|
|
|
132
118
|
return;
|
|
133
119
|
}
|
|
134
120
|
|
|
135
|
-
|
|
136
|
-
onPressOut(event);
|
|
137
|
-
}
|
|
121
|
+
onPressOut?.(event);
|
|
138
122
|
},
|
|
139
123
|
[isDisabled, onPressOut],
|
|
140
124
|
);
|
|
141
125
|
|
|
142
|
-
const
|
|
143
|
-
? {
|
|
144
|
-
color: colors.ripple,
|
|
145
|
-
borderless: false,
|
|
146
|
-
}
|
|
147
|
-
: undefined;
|
|
148
|
-
|
|
149
|
-
/*
|
|
150
|
-
* Important:
|
|
151
|
-
*
|
|
152
|
-
* title = text
|
|
153
|
-
*
|
|
154
|
-
* children = arbitrary JSX
|
|
155
|
-
*
|
|
156
|
-
* We NEVER put arbitrary children
|
|
157
|
-
* inside UIText.
|
|
158
|
-
*/
|
|
159
|
-
const hasCustomChildren = children !== undefined && children !== null;
|
|
160
|
-
|
|
161
|
-
const accessibilityText =
|
|
162
|
-
accessibilityLabel ?? (typeof title === "string" ? title : undefined);
|
|
126
|
+
const hasChildren = children !== undefined && children !== null;
|
|
163
127
|
|
|
164
128
|
return (
|
|
165
129
|
<Pressable
|
|
@@ -170,35 +134,36 @@ const UIButtonComponent = ({
|
|
|
170
134
|
onLongPress={handleLongPress}
|
|
171
135
|
onPressIn={handlePressIn}
|
|
172
136
|
onPressOut={handlePressOut}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
accessibilityLabel={accessibilityText}
|
|
137
|
+
accessibilityRole="button"
|
|
138
|
+
accessibilityLabel={
|
|
139
|
+
accessibilityLabel || (typeof title === "string" ? title : undefined)
|
|
140
|
+
}
|
|
178
141
|
accessibilityHint={accessibilityHint}
|
|
179
142
|
accessibilityState={{
|
|
180
143
|
disabled: isDisabled,
|
|
181
|
-
busy:
|
|
144
|
+
busy: loading,
|
|
182
145
|
}}
|
|
183
146
|
style={({ pressed }) => [
|
|
184
147
|
styles.button,
|
|
185
148
|
|
|
186
149
|
{
|
|
150
|
+
height: dimensions.height,
|
|
151
|
+
|
|
187
152
|
minHeight: dimensions.height,
|
|
188
153
|
|
|
189
154
|
paddingHorizontal: dimensions.paddingHorizontal,
|
|
190
155
|
|
|
191
|
-
borderRadius:
|
|
156
|
+
borderRadius: dimensions.borderRadius,
|
|
192
157
|
|
|
193
|
-
backgroundColor:
|
|
158
|
+
backgroundColor: buttonColors.background,
|
|
194
159
|
|
|
195
|
-
borderColor:
|
|
160
|
+
borderColor: buttonColors.border,
|
|
196
161
|
|
|
197
|
-
borderWidth:
|
|
162
|
+
borderWidth: buttonColors.border ? 1 : 0,
|
|
198
163
|
|
|
199
164
|
width: fullWidth ? "100%" : undefined,
|
|
200
165
|
|
|
201
|
-
opacity: isDisabled ? 0.
|
|
166
|
+
opacity: isDisabled ? 0.5 : pressed ? activeOpacity : 1,
|
|
202
167
|
},
|
|
203
168
|
|
|
204
169
|
style,
|
|
@@ -209,8 +174,6 @@ const UIButtonComponent = ({
|
|
|
209
174
|
styles.content,
|
|
210
175
|
|
|
211
176
|
{
|
|
212
|
-
minHeight: dimensions.height - 2,
|
|
213
|
-
|
|
214
177
|
gap: dimensions.gap,
|
|
215
178
|
},
|
|
216
179
|
|
|
@@ -218,162 +181,171 @@ const UIButtonComponent = ({
|
|
|
218
181
|
]}
|
|
219
182
|
>
|
|
220
183
|
{loading ? (
|
|
221
|
-
<ActivityIndicator size="small" color={
|
|
222
|
-
) : (
|
|
223
|
-
leftIcon
|
|
224
|
-
)}
|
|
184
|
+
<ActivityIndicator size="small" color={buttonColors.text} />
|
|
185
|
+
) : leftIcon ? (
|
|
186
|
+
<View style={styles.icon}>{leftIcon}</View>
|
|
187
|
+
) : null}
|
|
225
188
|
|
|
226
|
-
{
|
|
189
|
+
{hasChildren ? (
|
|
227
190
|
<View style={styles.children}>{children}</View>
|
|
228
|
-
) : title
|
|
229
|
-
<
|
|
230
|
-
variant={dimensions.textVariant}
|
|
231
|
-
color={colors.text}
|
|
232
|
-
style={[styles.title, textStyle]}
|
|
191
|
+
) : title ? (
|
|
192
|
+
<Text
|
|
233
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
|
+
]}
|
|
234
207
|
>
|
|
235
208
|
{title}
|
|
236
|
-
</
|
|
209
|
+
</Text>
|
|
237
210
|
) : null}
|
|
238
211
|
|
|
239
212
|
{!loading && rightIcon ? (
|
|
240
|
-
<View style={styles.
|
|
213
|
+
<View style={styles.icon}>{rightIcon}</View>
|
|
241
214
|
) : null}
|
|
242
215
|
</View>
|
|
243
216
|
</Pressable>
|
|
244
217
|
);
|
|
245
|
-
}
|
|
218
|
+
}
|
|
246
219
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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) {
|
|
230
|
+
const primary = colors.primary || "#FF5A1F";
|
|
252
231
|
|
|
253
|
-
|
|
232
|
+
const primarySoft = colors.primarySoft || "#FFF0EA";
|
|
254
233
|
|
|
255
|
-
|
|
234
|
+
const success = colors.success || "#16A34A";
|
|
256
235
|
|
|
257
|
-
|
|
258
|
-
};
|
|
236
|
+
const danger = colors.danger || "#DC2626";
|
|
259
237
|
|
|
260
|
-
|
|
261
|
-
return {
|
|
262
|
-
background: colors.transparent,
|
|
238
|
+
const text = colors.text || "#111111";
|
|
263
239
|
|
|
264
|
-
|
|
240
|
+
const onPrimary = colors.onPrimary || "#FFFFFF";
|
|
265
241
|
|
|
266
|
-
|
|
242
|
+
const border = colors.border || "#E5E5E5";
|
|
267
243
|
|
|
268
|
-
|
|
244
|
+
switch (variant) {
|
|
245
|
+
case VARIANTS.outline:
|
|
246
|
+
return {
|
|
247
|
+
background: "transparent",
|
|
248
|
+
border: primary,
|
|
249
|
+
text: primary,
|
|
269
250
|
};
|
|
270
251
|
|
|
271
|
-
case
|
|
252
|
+
case VARIANTS.ghost:
|
|
272
253
|
return {
|
|
273
|
-
background:
|
|
274
|
-
|
|
254
|
+
background: "transparent",
|
|
275
255
|
border: null,
|
|
276
|
-
|
|
277
|
-
text: colors.primary,
|
|
278
|
-
|
|
279
|
-
ripple: colors.primary,
|
|
256
|
+
text: primary,
|
|
280
257
|
};
|
|
281
258
|
|
|
282
|
-
case
|
|
259
|
+
case VARIANTS.soft:
|
|
283
260
|
return {
|
|
284
|
-
background:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
text: colors.onPrimary,
|
|
289
|
-
|
|
290
|
-
ripple: colors.dangerSoft || colors.danger,
|
|
261
|
+
background: primarySoft,
|
|
262
|
+
border: null,
|
|
263
|
+
text: primary,
|
|
291
264
|
};
|
|
292
265
|
|
|
293
|
-
case
|
|
266
|
+
case VARIANTS.danger:
|
|
294
267
|
return {
|
|
295
|
-
background:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
text: colors.onPrimary,
|
|
268
|
+
background: danger,
|
|
269
|
+
border: danger,
|
|
270
|
+
text: onPrimary,
|
|
271
|
+
};
|
|
300
272
|
|
|
301
|
-
|
|
273
|
+
case VARIANTS.success:
|
|
274
|
+
return {
|
|
275
|
+
background: success,
|
|
276
|
+
border: success,
|
|
277
|
+
text: onPrimary,
|
|
302
278
|
};
|
|
303
279
|
|
|
304
|
-
case
|
|
280
|
+
case VARIANTS.solid:
|
|
305
281
|
default:
|
|
306
282
|
return {
|
|
307
|
-
background:
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
text: colors.onPrimary,
|
|
312
|
-
|
|
313
|
-
ripple: colors.primaryPressed || colors.primary,
|
|
283
|
+
background: primary,
|
|
284
|
+
border: primary,
|
|
285
|
+
text: onPrimary,
|
|
314
286
|
};
|
|
315
287
|
}
|
|
316
288
|
}
|
|
317
289
|
|
|
318
|
-
|
|
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) {
|
|
319
296
|
switch (size) {
|
|
320
|
-
case
|
|
297
|
+
case SIZES.sm:
|
|
321
298
|
return {
|
|
322
|
-
height:
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
textVariant: "label",
|
|
299
|
+
height: 36,
|
|
300
|
+
paddingHorizontal: 14,
|
|
301
|
+
gap: 6,
|
|
302
|
+
borderRadius: 10,
|
|
303
|
+
fontSize: 13,
|
|
304
|
+
lineHeight: 18,
|
|
329
305
|
};
|
|
330
306
|
|
|
331
|
-
case
|
|
307
|
+
case SIZES.lg:
|
|
332
308
|
return {
|
|
333
|
-
height:
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
textVariant: "bodyMedium",
|
|
309
|
+
height: 52,
|
|
310
|
+
paddingHorizontal: 22,
|
|
311
|
+
gap: 8,
|
|
312
|
+
borderRadius: 14,
|
|
313
|
+
fontSize: 16,
|
|
314
|
+
lineHeight: 22,
|
|
340
315
|
};
|
|
341
316
|
|
|
342
|
-
case
|
|
317
|
+
case SIZES.xl:
|
|
343
318
|
return {
|
|
344
|
-
height:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
textVariant: "bodyMedium",
|
|
319
|
+
height: 60,
|
|
320
|
+
paddingHorizontal: 26,
|
|
321
|
+
gap: 8,
|
|
322
|
+
borderRadius: 16,
|
|
323
|
+
fontSize: 17,
|
|
324
|
+
lineHeight: 24,
|
|
351
325
|
};
|
|
352
326
|
|
|
353
|
-
case
|
|
327
|
+
case SIZES.md:
|
|
354
328
|
default:
|
|
355
329
|
return {
|
|
356
|
-
height:
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
textVariant: "label",
|
|
330
|
+
height: 44,
|
|
331
|
+
paddingHorizontal: 18,
|
|
332
|
+
gap: 8,
|
|
333
|
+
borderRadius: 12,
|
|
334
|
+
fontSize: 14,
|
|
335
|
+
lineHeight: 20,
|
|
363
336
|
};
|
|
364
337
|
}
|
|
365
338
|
}
|
|
366
339
|
|
|
367
340
|
const styles = StyleSheet.create({
|
|
368
341
|
button: {
|
|
342
|
+
flexShrink: 0,
|
|
369
343
|
alignItems: "center",
|
|
370
344
|
justifyContent: "center",
|
|
371
345
|
overflow: "hidden",
|
|
372
|
-
flexShrink: 0,
|
|
373
346
|
},
|
|
374
347
|
|
|
375
348
|
content: {
|
|
376
|
-
width: "100%",
|
|
377
349
|
flexDirection: "row",
|
|
378
350
|
alignItems: "center",
|
|
379
351
|
justifyContent: "center",
|
|
@@ -386,20 +358,24 @@ const styles = StyleSheet.create({
|
|
|
386
358
|
justifyContent: "center",
|
|
387
359
|
},
|
|
388
360
|
|
|
389
|
-
|
|
390
|
-
flexShrink: 1,
|
|
391
|
-
textAlign: "center",
|
|
392
|
-
},
|
|
393
|
-
|
|
394
|
-
iconRight: {
|
|
361
|
+
icon: {
|
|
395
362
|
alignItems: "center",
|
|
396
363
|
justifyContent: "center",
|
|
397
364
|
flexShrink: 0,
|
|
398
365
|
},
|
|
366
|
+
|
|
367
|
+
text: {
|
|
368
|
+
flexShrink: 1,
|
|
369
|
+
fontWeight: "600",
|
|
370
|
+
textAlign: "center",
|
|
371
|
+
includeFontPadding: false,
|
|
372
|
+
},
|
|
399
373
|
});
|
|
400
374
|
|
|
401
375
|
export const UIButton = memo(UIButtonComponent);
|
|
402
376
|
|
|
403
377
|
UIButton.displayName = "UIButton";
|
|
404
378
|
|
|
405
|
-
export
|
|
379
|
+
export const UIButtonVariants = VARIANTS;
|
|
380
|
+
|
|
381
|
+
export const UIButtonSizes = SIZES;
|