react95-native-rabbl 0.1.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.
Files changed (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -0
  3. package/package.json +154 -0
  4. package/src/assets/fonts/src/ms-sans-serif/MS Sans Serif.ttf +0 -0
  5. package/src/assets/fonts/src/ms-sans-serif/license.txt +4 -0
  6. package/src/assets/fonts/src/ms-sans-serif/readme.txt +26 -0
  7. package/src/assets/fonts/src/ms-sans-serif-bold/MS Sans Serif Bold.ttf +0 -0
  8. package/src/assets/fonts/src/ms-sans-serif-bold/license.txt +4 -0
  9. package/src/assets/fonts/src/ms-sans-serif-bold/readme.txt +26 -0
  10. package/src/components/AppBar/AppBar.spec.tsx +140 -0
  11. package/src/components/AppBar/AppBar.tsx +43 -0
  12. package/src/components/AppBar/AppBarBackAction.tsx +20 -0
  13. package/src/components/AppBar/AppBarContent.tsx +84 -0
  14. package/src/components/AppBar/index.ts +1 -0
  15. package/src/components/Button/Button.spec.tsx +59 -0
  16. package/src/components/Button/Button.tsx +236 -0
  17. package/src/components/Button/index.ts +1 -0
  18. package/src/components/Card/Card.spec.tsx +54 -0
  19. package/src/components/Card/Card.tsx +88 -0
  20. package/src/components/Card/CardContent.tsx +23 -0
  21. package/src/components/Card/index.ts +1 -0
  22. package/src/components/Checkbox/Checkbox.tsx +10 -0
  23. package/src/components/Checkbox/index.ts +1 -0
  24. package/src/components/ColorButton/ColorButton.tsx +69 -0
  25. package/src/components/ColorButton/index.ts +1 -0
  26. package/src/components/ColorPicker/ColorPicker.tsx +109 -0
  27. package/src/components/ColorPicker/index.ts +1 -0
  28. package/src/components/Desktop/Desktop.spec.tsx +32 -0
  29. package/src/components/Desktop/Desktop.tsx +132 -0
  30. package/src/components/Desktop/index.tsx +1 -0
  31. package/src/components/Divider/Divider.spec.tsx +47 -0
  32. package/src/components/Divider/Divider.tsx +52 -0
  33. package/src/components/Divider/index.tsx +1 -0
  34. package/src/components/FAB/FAB.tsx +288 -0
  35. package/src/components/FAB/FABGroup.tsx +385 -0
  36. package/src/components/FAB/index.ts +1 -0
  37. package/src/components/Fieldset/Fieldset.spec.tsx +48 -0
  38. package/src/components/Fieldset/Fieldset.tsx +107 -0
  39. package/src/components/Fieldset/index.ts +1 -0
  40. package/src/components/Hourglass/Hourglass.spec.tsx +24 -0
  41. package/src/components/Hourglass/Hourglass.tsx +43 -0
  42. package/src/components/Hourglass/base64hourglass.ts +3 -0
  43. package/src/components/Hourglass/index.ts +1 -0
  44. package/src/components/Icons/ArrowIcon.tsx +85 -0
  45. package/src/components/Icons/CheckmarkIcon.tsx +55 -0
  46. package/src/components/Icons/ChevronIcon.tsx +93 -0
  47. package/src/components/Icons/CloseIcon.tsx +48 -0
  48. package/src/components/Icons/index.ts +4 -0
  49. package/src/components/Label/Label.tsx +77 -0
  50. package/src/components/Label/index.ts +1 -0
  51. package/src/components/List/List.tsx +3 -0
  52. package/src/components/List/ListAccordion.tsx +154 -0
  53. package/src/components/List/ListItem.tsx +74 -0
  54. package/src/components/List/ListSection.tsx +51 -0
  55. package/src/components/List/index.ts +3 -0
  56. package/src/components/Menu/Menu.tsx +100 -0
  57. package/src/components/Menu/MenuItem.tsx +100 -0
  58. package/src/components/Menu/index.ts +1 -0
  59. package/src/components/NumberInput/NumberInput.spec.tsx +119 -0
  60. package/src/components/NumberInput/NumberInput.tsx +144 -0
  61. package/src/components/NumberInput/index.ts +1 -0
  62. package/src/components/Panel/Panel.spec.tsx +29 -0
  63. package/src/components/Panel/Panel.tsx +75 -0
  64. package/src/components/Panel/index.ts +1 -0
  65. package/src/components/Portal/Portal.tsx +52 -0
  66. package/src/components/Portal/PortalConsumer.tsx +48 -0
  67. package/src/components/Portal/PortalHost.tsx +150 -0
  68. package/src/components/Portal/PortalManager.tsx +57 -0
  69. package/src/components/Portal/index.ts +1 -0
  70. package/src/components/Progress/Progress.tsx +125 -0
  71. package/src/components/Progress/index.ts +1 -0
  72. package/src/components/Radio/Radio.tsx +14 -0
  73. package/src/components/Radio/index.ts +1 -0
  74. package/src/components/ScrollPanel/ScrollPanel.tsx +72 -0
  75. package/src/components/ScrollPanel/index.ts +1 -0
  76. package/src/components/ScrollView/ScrollView.tsx +284 -0
  77. package/src/components/ScrollView/index.ts +1 -0
  78. package/src/components/Select/Select.tsx +229 -0
  79. package/src/components/Select/SelectBase.tsx +119 -0
  80. package/src/components/Select/SelectBox.tsx +66 -0
  81. package/src/components/Select/index.ts +2 -0
  82. package/src/components/Slider/Slider.tsx +301 -0
  83. package/src/components/Slider/index.ts +1 -0
  84. package/src/components/Snackbar/Snackbar.tsx +260 -0
  85. package/src/components/Snackbar/SnackbarContent.tsx +23 -0
  86. package/src/components/Snackbar/index.ts +1 -0
  87. package/src/components/SwitchBase/SwitchBase.tsx +193 -0
  88. package/src/components/SwitchBase/index.ts +1 -0
  89. package/src/components/Tabs/Tabs.tsx +208 -0
  90. package/src/components/Tabs/index.ts +1 -0
  91. package/src/components/TextInput/TextInput.tsx +82 -0
  92. package/src/components/TextInput/index.ts +1 -0
  93. package/src/components/Toolbar/Toolbar.tsx +113 -0
  94. package/src/components/Toolbar/index.ts +1 -0
  95. package/src/components/Typography/Anchor.tsx +38 -0
  96. package/src/components/Typography/Text.spec.tsx +30 -0
  97. package/src/components/Typography/Text.tsx +55 -0
  98. package/src/components/Typography/Title.tsx +58 -0
  99. package/src/components/Typography/index.ts +3 -0
  100. package/src/components/Window/Window.tsx +132 -0
  101. package/src/components/Window/index.ts +1 -0
  102. package/src/core/Provider.tsx +52 -0
  103. package/src/core/theming.tsx +8 -0
  104. package/src/hooks/useAsyncReference.ts +22 -0
  105. package/src/hooks/useControlledOrUncontrolled.ts +23 -0
  106. package/src/index.ts +38 -0
  107. package/src/styles/shadow.tsx +36 -0
  108. package/src/styles/styleElements.tsx +105 -0
  109. package/src/styles/styles.ts +129 -0
  110. package/src/styles/themes/aiee.ts +36 -0
  111. package/src/styles/themes/ash.ts +35 -0
  112. package/src/styles/themes/azureOrange.ts +33 -0
  113. package/src/styles/themes/bee.ts +33 -0
  114. package/src/styles/themes/blackAndWhite.ts +33 -0
  115. package/src/styles/themes/blue.ts +36 -0
  116. package/src/styles/themes/brick.ts +33 -0
  117. package/src/styles/themes/candy.ts +33 -0
  118. package/src/styles/themes/cherry.ts +36 -0
  119. package/src/styles/themes/coldGray.ts +34 -0
  120. package/src/styles/themes/counterStrike.ts +33 -0
  121. package/src/styles/themes/darkTeal.ts +36 -0
  122. package/src/styles/themes/eggplant.ts +33 -0
  123. package/src/styles/themes/fxDev.ts +36 -0
  124. package/src/styles/themes/highContrast.ts +33 -0
  125. package/src/styles/themes/hotChocolate.ts +36 -0
  126. package/src/styles/themes/index.ts +103 -0
  127. package/src/styles/themes/lilac.ts +33 -0
  128. package/src/styles/themes/lilacRoseDark.ts +34 -0
  129. package/src/styles/themes/maple.ts +33 -0
  130. package/src/styles/themes/marine.ts +33 -0
  131. package/src/styles/themes/matrix.ts +33 -0
  132. package/src/styles/themes/millenium.ts +33 -0
  133. package/src/styles/themes/modernDark.ts +33 -0
  134. package/src/styles/themes/molecule.ts +33 -0
  135. package/src/styles/themes/monochrome.ts +0 -0
  136. package/src/styles/themes/ninjaTurtles.ts +33 -0
  137. package/src/styles/themes/olive.ts +33 -0
  138. package/src/styles/themes/original.ts +33 -0
  139. package/src/styles/themes/pamelaAnderson.ts +33 -0
  140. package/src/styles/themes/plum.ts +33 -0
  141. package/src/styles/themes/polarized.ts +36 -0
  142. package/src/styles/themes/powerShell.ts +36 -0
  143. package/src/styles/themes/rainyDay.ts +33 -0
  144. package/src/styles/themes/raspberry.ts +36 -0
  145. package/src/styles/themes/redWine.ts +36 -0
  146. package/src/styles/themes/rose.ts +33 -0
  147. package/src/styles/themes/seawater.ts +36 -0
  148. package/src/styles/themes/slate.ts +33 -0
  149. package/src/styles/themes/solarizedDark.ts +36 -0
  150. package/src/styles/themes/solarizedLight.ts +36 -0
  151. package/src/styles/themes/spruce.ts +33 -0
  152. package/src/styles/themes/stormClouds.ts +36 -0
  153. package/src/styles/themes/theSixtiesUSA.ts +33 -0
  154. package/src/styles/themes/tokyoDark.ts +33 -0
  155. package/src/styles/themes/tooSexy.ts +33 -0
  156. package/src/styles/themes/travel.ts +33 -0
  157. package/src/styles/themes/vaporTeal.ts +33 -0
  158. package/src/styles/themes/vermillion.ts +33 -0
  159. package/src/styles/themes/violetDark.ts +33 -0
  160. package/src/styles/themes/water.ts +33 -0
  161. package/src/styles/themes/wmii.ts +36 -0
  162. package/src/types.tsx +55 -0
  163. package/src/utils/index.ts +57 -0
@@ -0,0 +1,385 @@
1
+ import * as React from 'react';
2
+ import {
3
+ StyleProp,
4
+ StyleSheet,
5
+ Animated,
6
+ SafeAreaView,
7
+ TouchableWithoutFeedback,
8
+ View,
9
+ ViewStyle,
10
+ } from 'react-native';
11
+
12
+ import { Text, FAB, Card } from '../..';
13
+
14
+ type Props = {
15
+ icon?: boolean;
16
+ /**
17
+ * Action items to display in the form of a speed dial.
18
+ * An action item should contain the following properties:
19
+ * - `icon`: icon to display (required)
20
+ * - `label`: optional label text
21
+ * - `accessibilityLabel`: accessibility label for the action, uses label by default if specified
22
+ * - `color`: custom icon color of the action item
23
+ * - `style`: pass additional styles for the fab item, for example, `backgroundColor`
24
+ * - `small`: boolean describing whether small or normal sized FAB is rendered. Defaults to `true`
25
+ * - `onPress`: callback that is called when `FAB` is pressed (required)
26
+ */
27
+ actions: Array<{
28
+ icon?: boolean;
29
+ label?: string;
30
+ color?: string;
31
+ accessibilityLabel?: string;
32
+ style?: StyleProp<ViewStyle>;
33
+ small?: boolean;
34
+ onPress: () => void;
35
+ testID?: string;
36
+ }>;
37
+ /**
38
+ * Accessibility label for the FAB. This is read by the screen reader when the user taps the FAB.
39
+ */
40
+ accessibilityLabel?: string;
41
+ /**
42
+ * Custom color for the `FAB`.
43
+ */
44
+ color?: string;
45
+ /**
46
+ * Function to execute on pressing the `FAB`.
47
+ */
48
+ onPress?: () => void;
49
+ /**
50
+ * Whether the speed dial is open.
51
+ */
52
+ open: boolean;
53
+ /**
54
+ * Callback which is called on opening and closing the speed dial.
55
+ * The open state needs to be updated when it's called, otherwise the change is dropped.
56
+ */
57
+ onStateChange: (state: { open: boolean }) => void;
58
+ /**
59
+ * Whether `FAB` is currently visible.
60
+ */
61
+ visible: boolean;
62
+ /**
63
+ * Style for the group. You can use it to pass additional styles if you need.
64
+ * For example, you can set an additional padding if you have a tab bar at the bottom.
65
+ */
66
+ style?: StyleProp<ViewStyle>;
67
+ /**
68
+ * Style for the FAB. It allows to pass the FAB button styles, such as backgroundColor.
69
+ */
70
+ fabStyle?: StyleProp<ViewStyle>;
71
+ /**
72
+ * Pass down testID from Group props to FAB.
73
+ */
74
+ testID?: string;
75
+ };
76
+
77
+ /**
78
+ * A component to display a stack of FABs with related actions in a speed dial.
79
+ * To render the group above other components, you'll need to wrap it with the [`Portal`](portal.html) component.
80
+ *
81
+ * <div class="screenshots">
82
+ * <img src="screenshots/fab-group.png" />
83
+ * </div>
84
+ *
85
+ * ## Usage
86
+ * ```js
87
+ * import * as React from 'react';
88
+ * import { FAB, Portal, Provider } from 'react-native-paper';
89
+ *
90
+ * const MyComponent = () => {
91
+ * const [state, setState] = React.useState({ open: false });
92
+ *
93
+ * const onStateChange = ({ open }) => setState({ open });
94
+ *
95
+ * const { open } = state;
96
+ *
97
+ * return (
98
+ * <Provider>
99
+ * <Portal>
100
+ * <FAB.Group
101
+ * open={open}
102
+ * icon={open ? 'calendar-today' : 'plus'}
103
+ * actions={[
104
+ * { icon: 'plus', onPress: () => console.log('Pressed add') },
105
+ * {
106
+ * icon: 'star',
107
+ * label: 'Star',
108
+ * onPress: () => console.log('Pressed star'),
109
+ * },
110
+ * {
111
+ * icon: 'email',
112
+ * label: 'Email',
113
+ * onPress: () => console.log('Pressed email'),
114
+ * },
115
+ * {
116
+ * icon: 'bell',
117
+ * label: 'Remind',
118
+ * onPress: () => console.log('Pressed notifications'),
119
+ * small: false,
120
+ * },
121
+ * ]}
122
+ * onStateChange={onStateChange}
123
+ * onPress={() => {
124
+ * if (open) {
125
+ * // do something if the speed dial is open
126
+ * }
127
+ * }}
128
+ * />
129
+ * </Portal>
130
+ * </Provider>
131
+ * );
132
+ * };
133
+ *
134
+ * export default MyComponent;
135
+ * ```
136
+ */
137
+ const FABGroup = ({
138
+ actions,
139
+ icon,
140
+ open,
141
+ onPress,
142
+ accessibilityLabel,
143
+ style,
144
+ fabStyle,
145
+ visible,
146
+ testID,
147
+ onStateChange,
148
+ color: colorProp,
149
+ }: Props) => {
150
+ const { current: backdrop } = React.useRef<Animated.Value>(
151
+ new Animated.Value(0),
152
+ );
153
+ const animations = React.useRef<Animated.Value[]>(
154
+ actions.map(() => new Animated.Value(open ? 1 : 0)),
155
+ );
156
+
157
+ const [prevActions, setPrevActions] = React.useState<
158
+ | {
159
+ label?: string;
160
+ color?: string;
161
+ accessibilityLabel?: string;
162
+ style?: StyleProp<ViewStyle>;
163
+ onPress: () => void;
164
+ testID?: string;
165
+ }[]
166
+ | null
167
+ >(null);
168
+
169
+ // TODO: decide on scale
170
+ const scale = 0.8;
171
+
172
+ React.useEffect(() => {
173
+ if (open) {
174
+ Animated.parallel([
175
+ Animated.timing(backdrop, {
176
+ toValue: 1,
177
+ duration: 250 * scale,
178
+ useNativeDriver: true,
179
+ }),
180
+ Animated.stagger(
181
+ 50 * scale,
182
+ animations.current
183
+ .map(animation =>
184
+ Animated.timing(animation, {
185
+ toValue: 1,
186
+ duration: 150 * scale,
187
+ useNativeDriver: true,
188
+ }),
189
+ )
190
+ .reverse(),
191
+ ),
192
+ ]).start();
193
+ } else {
194
+ Animated.parallel([
195
+ Animated.timing(backdrop, {
196
+ toValue: 0,
197
+ duration: 200 * scale,
198
+ useNativeDriver: true,
199
+ }),
200
+ ...animations.current.map(animation =>
201
+ Animated.timing(animation, {
202
+ toValue: 0,
203
+ duration: 150 * scale,
204
+ useNativeDriver: true,
205
+ }),
206
+ ),
207
+ ]).start();
208
+ }
209
+ }, [open, actions, backdrop, scale]);
210
+
211
+ const close = () => onStateChange({ open: false });
212
+
213
+ const toggle = () => onStateChange({ open: !open });
214
+
215
+ const labelColor = 'red';
216
+ const backdropOpacity = open
217
+ ? backdrop.interpolate({
218
+ inputRange: [0, 0.5, 1],
219
+ outputRange: [0, 1, 1],
220
+ })
221
+ : backdrop;
222
+
223
+ const opacities = animations.current;
224
+ const scales = opacities.map(opacity =>
225
+ open
226
+ ? opacity.interpolate({
227
+ inputRange: [0, 1],
228
+ outputRange: [0.8, 1],
229
+ })
230
+ : 1,
231
+ );
232
+
233
+ if (actions.length !== prevActions?.length) {
234
+ animations.current = actions.map(
235
+ (_, i) => animations.current[i] || new Animated.Value(open ? 1 : 0),
236
+ );
237
+ setPrevActions(actions);
238
+ }
239
+
240
+ return (
241
+ <View pointerEvents='box-none' style={[styles.container, style]}>
242
+ <TouchableWithoutFeedback onPress={close}>
243
+ <Animated.View
244
+ pointerEvents={open ? 'auto' : 'none'}
245
+ style={[
246
+ styles.backdrop,
247
+ {
248
+ opacity: backdropOpacity,
249
+ // backgroundColor: colors.backdrop,
250
+ backgroundColor: '#00000070',
251
+ },
252
+ ]}
253
+ />
254
+ </TouchableWithoutFeedback>
255
+ <SafeAreaView pointerEvents='box-none' style={styles.safeArea}>
256
+ <View pointerEvents={open ? 'box-none' : 'none'}>
257
+ {actions.map((SWAG, i) => (
258
+ <View
259
+ key={i} // eslint-disable-line react/no-array-index-key
260
+ style={[
261
+ styles.item,
262
+ {
263
+ marginHorizontal:
264
+ typeof SWAG.small === 'undefined' || SWAG.small ? 24 : 16,
265
+ },
266
+ ]}
267
+ pointerEvents={open ? 'box-none' : 'none'}
268
+ >
269
+ {SWAG.label && (
270
+ <View>
271
+ <Card
272
+ style={
273
+ [
274
+ styles.label,
275
+ {
276
+ transform: [{ scale: scales[i] }],
277
+ opacity: opacities[i],
278
+ },
279
+ ] as StyleProp<ViewStyle>
280
+ }
281
+ // onPress={() => {
282
+ // it.onPress();
283
+ // close();
284
+ // }}
285
+ accessibilityLabel={
286
+ SWAG.accessibilityLabel !== 'undefined'
287
+ ? SWAG.accessibilityLabel
288
+ : SWAG.label
289
+ }
290
+ accessibilityTraits='button'
291
+ accessibilityComponentType='button'
292
+ accessibilityRole='button'
293
+ >
294
+ <Text style={{ color: labelColor }}>{SWAG.label}</Text>
295
+ </Card>
296
+ </View>
297
+ )}
298
+ <FAB
299
+ small={typeof SWAG.small !== 'undefined' ? SWAG.small : true}
300
+ icon={SWAG.icon}
301
+ color={SWAG.color}
302
+ style={
303
+ [
304
+ {
305
+ transform: [{ scale: scales[i] }],
306
+ opacity: opacities[i],
307
+ // backgroundColor: theme.colors.surface,
308
+ },
309
+ SWAG.style,
310
+ ] as StyleProp<ViewStyle>
311
+ }
312
+ onPress={() => {
313
+ SWAG.onPress();
314
+ close();
315
+ }}
316
+ accessibilityLabel={
317
+ typeof SWAG.accessibilityLabel !== 'undefined'
318
+ ? SWAG.accessibilityLabel
319
+ : SWAG.label
320
+ }
321
+ accessibilityTraits='button'
322
+ accessibilityComponentType='button'
323
+ accessibilityRole='button'
324
+ testID={SWAG.testID}
325
+ visible={open}
326
+ />
327
+ </View>
328
+ ))}
329
+ </View>
330
+ <FAB
331
+ onPress={() => {
332
+ onPress?.();
333
+ toggle();
334
+ }}
335
+ icon={icon}
336
+ color={colorProp}
337
+ accessibilityLabel={accessibilityLabel}
338
+ accessibilityTraits='button'
339
+ accessibilityComponentType='button'
340
+ accessibilityRole='button'
341
+ accessibilityState={{ expanded: open }}
342
+ style={[styles.fab, fabStyle]}
343
+ visible={visible}
344
+ testID={testID}
345
+ />
346
+ </SafeAreaView>
347
+ </View>
348
+ );
349
+ };
350
+
351
+ FABGroup.displayName = 'FAB.Group';
352
+
353
+ export default FABGroup;
354
+
355
+ const styles = StyleSheet.create({
356
+ safeArea: {
357
+ alignItems: 'flex-end',
358
+ },
359
+ container: {
360
+ ...StyleSheet.absoluteFillObject,
361
+ justifyContent: 'flex-end',
362
+ },
363
+ fab: {
364
+ marginHorizontal: 16,
365
+ marginBottom: 16,
366
+ marginTop: 0,
367
+ },
368
+ backdrop: {
369
+ ...StyleSheet.absoluteFillObject,
370
+ },
371
+ label: {
372
+ borderRadius: 5,
373
+ paddingHorizontal: 12,
374
+ paddingVertical: 6,
375
+ marginVertical: 8,
376
+ marginHorizontal: 16,
377
+ elevation: 2,
378
+ },
379
+ item: {
380
+ marginBottom: 16,
381
+ flexDirection: 'row',
382
+ justifyContent: 'flex-end',
383
+ alignItems: 'center',
384
+ },
385
+ });
@@ -0,0 +1 @@
1
+ export { default } from './FAB';
@@ -0,0 +1,48 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react-native';
3
+
4
+ import { Fieldset, Text } from '../..';
5
+
6
+ describe('<Fieldset />', () => {
7
+ it('should render children', () => {
8
+ const { getByTestId } = render(
9
+ <Fieldset testID='fieldset'>
10
+ <Text>Banana dance</Text>
11
+ </Fieldset>,
12
+ );
13
+
14
+ expect(getByTestId('fieldset')).toHaveTextContent('Banana dance');
15
+ });
16
+
17
+ it('should render custom styles', () => {
18
+ const style = { backgroundColor: 'teal' };
19
+
20
+ const { getByTestId } = render(
21
+ <Fieldset testID='fieldset' style={style}>
22
+ <Text>Fieldset</Text>
23
+ </Fieldset>,
24
+ );
25
+
26
+ expect(getByTestId('fieldset')).toHaveStyle(style);
27
+ });
28
+
29
+ describe('prop: label', () => {
30
+ it('should render label', () => {
31
+ const { getByText } = render(<Fieldset label='Something:' />);
32
+
33
+ expect(getByText('Something:')).toBeTruthy();
34
+ });
35
+ });
36
+
37
+ describe('prop: labelStyle', () => {
38
+ it('should render custom label styles', () => {
39
+ const style = { backgroundColor: 'teal' };
40
+
41
+ const { getByText } = render(
42
+ <Fieldset label='Something:' labelStyle={style} />,
43
+ );
44
+
45
+ expect(getByText('Something:')).toHaveStyle(style);
46
+ });
47
+ });
48
+ });
@@ -0,0 +1,107 @@
1
+ // ORIGINAL WINDOWS NAME: GROUPBOX
2
+ import React from 'react';
3
+ import { StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
4
+
5
+ import type { Theme } from '../../types';
6
+ import { withTheme } from '../../core/theming';
7
+
8
+ import { Border } from '../../styles/styleElements';
9
+ import { Text } from '../..';
10
+
11
+ export const testId = 'fieldset';
12
+
13
+ type Props = React.ComponentPropsWithRef<typeof View> & {
14
+ children?: React.ReactNode;
15
+ disabled?: boolean;
16
+ label?: React.ReactNode;
17
+ labelStyle?: StyleProp<ViewStyle>;
18
+ style?: StyleProp<ViewStyle>;
19
+ theme: Theme;
20
+ variant?: 'default' | 'flat';
21
+ };
22
+
23
+ const Fieldset = ({
24
+ children,
25
+ disabled,
26
+ label,
27
+ labelStyle = {},
28
+ style = {},
29
+ theme,
30
+ variant = 'default',
31
+ ...rest
32
+ }: Props) => {
33
+ return (
34
+ <View style={[styles.wrapper, style]} testID={testId} {...rest}>
35
+ {variant === 'flat' ? (
36
+ <Border variant='flat' theme={theme} />
37
+ ) : (
38
+ <>
39
+ <View
40
+ style={[
41
+ styles.border,
42
+ {
43
+ borderWidth: 4,
44
+ borderColor: theme.borderLightest,
45
+ },
46
+ ]}
47
+ />
48
+ <View
49
+ style={[
50
+ styles.border,
51
+ {
52
+ marginRight: 2,
53
+ marginBottom: 2,
54
+ borderWidth: 2,
55
+ borderColor: theme.borderDark,
56
+ },
57
+ ]}
58
+ />
59
+ </>
60
+ )}
61
+ {label && (
62
+ <Text
63
+ theme={theme}
64
+ disabled={disabled}
65
+ style={[
66
+ styles.label,
67
+ {
68
+ backgroundColor:
69
+ variant === 'flat' ? theme.canvas : theme.material,
70
+ },
71
+ labelStyle,
72
+ ]}
73
+ >
74
+ {label}
75
+ </Text>
76
+ )}
77
+ {children}
78
+ </View>
79
+ );
80
+ };
81
+
82
+ const styles = StyleSheet.create({
83
+ wrapper: {
84
+ position: 'relative',
85
+ marginVertical: 12,
86
+ padding: 20,
87
+ },
88
+ label: {
89
+ position: 'absolute',
90
+ top: 0,
91
+ left: 8,
92
+ // TODO: how to properly center the label?
93
+ transform: [{ translateY: -8 }],
94
+ paddingHorizontal: 8,
95
+ fontSize: 16,
96
+ lineHeight: 16,
97
+ },
98
+ border: {
99
+ position: 'absolute',
100
+ top: 0,
101
+ left: 0,
102
+ right: 0,
103
+ bottom: 0,
104
+ },
105
+ });
106
+
107
+ export default withTheme(Fieldset);
@@ -0,0 +1 @@
1
+ export { default } from './Fieldset';
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react-native';
3
+ import { Hourglass } from '../..';
4
+
5
+ describe('<Hourglass />', () => {
6
+ it('should render Hourglass', () => {
7
+ const { getByTestId } = render(<Hourglass testID='hourglass' />);
8
+ const hourglass = getByTestId('hourglass');
9
+
10
+ expect(hourglass).toBeTruthy();
11
+ });
12
+
13
+ describe('prop: size', () => {
14
+ it('sets size correctly', () => {
15
+ const size = 53;
16
+ const { getByTestId } = render(
17
+ <Hourglass testID='hourglass' size={size} />,
18
+ );
19
+ const hourglass = getByTestId('hourglass');
20
+
21
+ expect(hourglass).toHaveStyle({ width: 53, height: 53 });
22
+ });
23
+ });
24
+ });
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import { View, ImageBackground, StyleProp, ViewStyle } from 'react-native';
3
+ import type { $RemoveChildren, DimensionValue } from '../../types';
4
+
5
+ import base64hourglass from './base64hourglass';
6
+
7
+ type Props = $RemoveChildren<typeof View> & {
8
+ // TODO: switch from any size (px / %) to the way we do it in Button(sm | md | lg) ?
9
+ size?: DimensionValue;
10
+ style?: StyleProp<ViewStyle>;
11
+ };
12
+
13
+ const Hourglass = ({ size = 30, style, ...rest }: Props) => {
14
+ return (
15
+ <View
16
+ style={[
17
+ {
18
+ width: size,
19
+ height: size,
20
+ },
21
+ style,
22
+ ]}
23
+ {...rest}
24
+ >
25
+ <ImageBackground
26
+ style={[
27
+ {
28
+ width: '100%',
29
+ height: '100%',
30
+ },
31
+ ]}
32
+ imageStyle={{
33
+ resizeMode: 'cover',
34
+ }}
35
+ source={{
36
+ uri: base64hourglass,
37
+ }}
38
+ />
39
+ </View>
40
+ );
41
+ };
42
+
43
+ export default Hourglass;
@@ -0,0 +1,3 @@
1
+ const base64hourglass =
2
+ 'data:image/gif;base64,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';
3
+ export default base64hourglass;
@@ -0,0 +1 @@
1
+ export { default } from './Hourglass';