react-native-varia 0.2.3 → 0.2.4

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 (35) hide show
  1. package/bin/cli.js +24 -34
  2. package/lib/components/Accordion.tsx +113 -0
  3. package/lib/components/Button.tsx +10 -1
  4. package/lib/components/CircleProgress.tsx +30 -21
  5. package/lib/components/Divider.tsx +18 -15
  6. package/lib/components/Drawer.tsx +5 -48
  7. package/lib/components/Field.tsx +24 -39
  8. package/lib/components/GradientBackground.tsx +25 -7
  9. package/lib/components/GradientText.tsx +38 -11
  10. package/lib/components/IconWrapper.tsx +20 -14
  11. package/lib/components/Input.tsx +106 -25
  12. package/lib/components/NumberInput.tsx +54 -11
  13. package/lib/components/OldSlider.tsx +327 -0
  14. package/lib/components/RadioGroup.tsx +55 -17
  15. package/lib/components/ReText.tsx +1 -1
  16. package/lib/components/Select.tsx +58 -22
  17. package/lib/components/Slider.tsx +176 -115
  18. package/lib/components/Slideshow.tsx +65 -63
  19. package/lib/components/SlidingDrawer.tsx +20 -21
  20. package/lib/components/Spinner.tsx +6 -2
  21. package/lib/components/Toast.tsx +89 -0
  22. package/lib/components/context/Field.tsx +27 -0
  23. package/lib/theme/Button.recipe.tsx +11 -1
  24. package/lib/theme/CircleProgress.recipe.tsx +3 -3
  25. package/lib/theme/Field.recipe.tsx +17 -2
  26. package/lib/theme/Input.recipe.tsx +12 -3
  27. package/lib/theme/NumberInput.recipe.tsx +8 -3
  28. package/lib/theme/RadioGroup.recipe.tsx +7 -1
  29. package/lib/theme/Select.recipe.tsx +7 -7
  30. package/lib/theme/Slider.recipe.tsx +366 -22
  31. package/lib/theme/Slideshow.recipe.tsx +1 -1
  32. package/lib/theme/SlidingDrawer.recipe.tsx +58 -4
  33. package/lib/theme/Toast.recipe.tsx +71 -0
  34. package/package.json +1 -1
  35. package/lib/theme/Button.recipe-old.tsx +0 -67
@@ -4,24 +4,35 @@ import React, {
4
4
  useState,
5
5
  ReactNode,
6
6
  ReactElement,
7
+ useMemo,
7
8
  } from 'react'
8
9
  import {
9
10
  View,
10
11
  TouchableOpacity,
11
12
  ScrollView,
12
13
  TouchableWithoutFeedback,
13
- StyleSheet,
14
+ Pressable,
14
15
  } from 'react-native'
15
16
  import {UnistylesVariants} from 'react-native-unistyles'
16
17
  import {Portal} from '@gorhom/portal'
17
18
  import Text from './Text'
18
- import {StyleSheet as UniStyleSheet} from 'react-native-unistyles'
19
+ import {StyleSheet} from 'react-native-unistyles'
19
20
  import {SelectStyles, SelectDefaultVariants} from '../theme/Select.recipe'
20
- import {PalettesWithNestedKeys} from '../style/varia/types'
21
+ import {
22
+ AlignSelf,
23
+ Flex,
24
+ PalettesWithNestedKeys,
25
+ StackDirection,
26
+ } from '../style/varia/types'
27
+ import {computeFlexSync} from '../style/varia/utils'
21
28
 
22
29
  type SelectVariants = UnistylesVariants<typeof SelectStyles>
23
30
 
24
- interface Option {
31
+ function hasDisplayName(type: any): type is {displayName: string} {
32
+ return typeof type === 'function' && 'displayName' in type
33
+ }
34
+
35
+ type Option = SelectVariants & {
25
36
  label: string
26
37
  value: string
27
38
  }
@@ -35,6 +46,7 @@ interface SelectContextType {
35
46
  colorPalette: PalettesWithNestedKeys
36
47
  variant: SelectVariants['variant']
37
48
  size: SelectVariants['size']
49
+ flex: Flex
38
50
  }
39
51
 
40
52
  const SelectContext = createContext<SelectContextType | undefined>(undefined)
@@ -53,9 +65,11 @@ type RootProps = SelectVariants & {
53
65
  defaultValue?: string
54
66
  placeholder?: string
55
67
  colorPalette?: PalettesWithNestedKeys
56
- flex?: number
57
68
  portalHostName?: string
58
69
  children: ReactNode
70
+ flex?: Flex
71
+ stretch?: AlignSelf
72
+ direction?: 'row' | 'column'
59
73
  }
60
74
 
61
75
  const SelectRoot = ({
@@ -66,9 +80,11 @@ const SelectRoot = ({
66
80
  variant = SelectDefaultVariants.variant,
67
81
  size = SelectDefaultVariants.size,
68
82
  colorPalette = 'accent',
69
- flex = 1,
70
83
  portalHostName = 'select',
71
84
  children,
85
+ flex = 0,
86
+ stretch,
87
+ direction = 'column',
72
88
  }: RootProps) => {
73
89
  SelectStyles.useVariants({variant, size})
74
90
  const [internalValue, setInternalValue] = useState(defaultValue)
@@ -84,27 +100,32 @@ const SelectRoot = ({
84
100
  }
85
101
 
86
102
  const trigger = React.Children.toArray(children).find(
87
- (child: any) =>
103
+ (child): child is ReactElement<TriggerProps> =>
88
104
  React.isValidElement(child) &&
89
- (child.type as any).displayName === 'SelectTrigger',
105
+ hasDisplayName(child.type) &&
106
+ child.type.displayName === 'SelectTrigger',
90
107
  )
91
108
 
92
109
  const portalChildren = React.Children.toArray(children).filter(
93
- (child: any) =>
110
+ (child): child is ReactElement<TriggerProps> =>
94
111
  !(
95
112
  React.isValidElement(child) &&
96
- (child.type as any).displayName === 'SelectTrigger'
113
+ hasDisplayName(child.type) &&
114
+ child.type.displayName === 'SelectTrigger'
97
115
  ),
98
116
  )
99
117
 
100
118
  return (
101
- <View style={[styles.container(flex)]}>
119
+ <View style={[styles.container(flex, stretch)]}>
102
120
  {trigger &&
103
121
  React.cloneElement(trigger as ReactElement<TriggerProps>, {
104
122
  isOpen,
105
123
  setIsOpen,
106
124
  value,
107
125
  options,
126
+ flex,
127
+ stretch,
128
+ direction,
108
129
  variant:
109
130
  (trigger as ReactElement<TriggerProps>).props.variant ?? variant,
110
131
  size: (trigger as ReactElement<TriggerProps>).props.size ?? size,
@@ -125,6 +146,7 @@ const SelectRoot = ({
125
146
  colorPalette,
126
147
  variant,
127
148
  size,
149
+ flex,
128
150
  }}>
129
151
  <View style={styles.portalContainer}>{portalChildren}</View>
130
152
  </SelectContext.Provider>
@@ -143,6 +165,9 @@ interface TriggerProps {
143
165
  colorPalette?: PalettesWithNestedKeys
144
166
  value?: string
145
167
  options?: Option[]
168
+ flex?: Flex
169
+ stretch?: AlignSelf
170
+ direction?: 'row' | 'column'
146
171
  }
147
172
 
148
173
  const SelectTrigger = ({
@@ -153,16 +178,25 @@ const SelectTrigger = ({
153
178
  size,
154
179
  colorPalette = 'accent',
155
180
  value,
181
+ flex = 0,
182
+ stretch,
183
+ direction,
156
184
  options = [],
157
185
  }: TriggerProps) => {
158
186
  SelectStyles.useVariants({variant, size})
187
+ const {flex: childFlex} = useMemo(() => {
188
+ return computeFlexSync(flex as number, stretch, direction as StackDirection)
189
+ }, [flex, stretch, direction])
159
190
  const selected = options.find(opt => opt.value === value)
160
191
  return (
161
- <TouchableWithoutFeedback onPress={() => setIsOpen?.(!isOpen)}>
162
- <View style={[styles.input, SelectStyles.trigger(colorPalette)]}>
163
- <Text>{selected ? selected.label : placeholder}</Text>
164
- </View>
165
- </TouchableWithoutFeedback>
192
+ <Pressable
193
+ onPress={() => setIsOpen?.(!isOpen)}
194
+ style={({pressed}) => [
195
+ styles.input(childFlex),
196
+ SelectStyles.trigger(colorPalette, pressed),
197
+ ]}>
198
+ <Text>{selected ? selected.label : placeholder}</Text>
199
+ </Pressable>
166
200
  )
167
201
  }
168
202
  SelectTrigger.displayName = 'SelectTrigger'
@@ -236,18 +270,20 @@ const Select = {
236
270
 
237
271
  export default Select
238
272
 
239
- const styles = UniStyleSheet.create({
240
- container: (flex: number) => ({
241
- flexGrow: flex,
273
+ const styles = StyleSheet.create({
274
+ container: (flex: Flex, stretch: AlignSelf) => ({
275
+ flex,
242
276
  flexDirection: 'row',
243
277
  justifyContent: 'center',
278
+ ...(stretch ? {alignSelf: stretch} : {}),
279
+ alignItems: 'stretch',
244
280
  }),
245
- input: {
246
- flex: 1,
281
+ input: (flex: Flex) => ({
282
+ flex,
247
283
  flexDirection: 'row',
248
284
  alignItems: 'center',
249
285
  justifyContent: 'center',
250
- },
286
+ }),
251
287
  item: {
252
288
  alignItems: 'center',
253
289
  flexDirection: 'row',
@@ -3,6 +3,7 @@ import {type LayoutChangeEvent, View} from 'react-native'
3
3
  import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
4
4
  import {Gesture, GestureDetector} from 'react-native-gesture-handler'
5
5
  import Animated, {
6
+ useAnimatedReaction,
6
7
  useAnimatedStyle,
7
8
  useSharedValue,
8
9
  } from 'react-native-reanimated'
@@ -12,6 +13,11 @@ import {PalettesWithNestedKeys} from '../style/varia/types'
12
13
 
13
14
  type SliderVariants = UnistylesVariants<typeof SliderStyles>
14
15
 
16
+ type ThumbStyleExtended = ReturnType<typeof SliderStyles.thumb> & {
17
+ width: number
18
+ height: number
19
+ }
20
+
15
21
  type SliderProps = SliderVariants & {
16
22
  colorPalette?: PalettesWithNestedKeys
17
23
  thickness?: number
@@ -23,7 +29,6 @@ type SliderProps = SliderVariants & {
23
29
  height: number
24
30
  }
25
31
  thumbChildren?: React.ReactNode
26
- axis: 'x' | 'y'
27
32
  steps?: number
28
33
  value?: number
29
34
  onValueChange?: (value: number) => void
@@ -42,36 +47,34 @@ const Slider = ({
42
47
  onValueChange,
43
48
  onSlidingComplete,
44
49
  }: SliderProps) => {
45
- let styles
46
- if (axis === 'x') {
47
- styles = stylesX
48
- } else {
49
- styles = stylesY
50
- }
50
+ // let styles
51
+ // if (axis === 'x') {
52
+ // styles = stylesX
53
+ // } else {
54
+ // styles = stylesY
55
+ // }
51
56
  SliderStyles.useVariants({
52
57
  size,
53
58
  variant,
59
+ axis,
54
60
  })
55
- const thumbStyle = SliderStyles.thumb(colorPalette)
56
- const maximumTrackStyle = SliderStyles.maximumTrack(colorPalette)
57
- const minimumTrackStyle = SliderStyles.minimumTrack(colorPalette, false)
61
+ styles.useVariants({
62
+ axis,
63
+ })
64
+ const thumbStyle = SliderStyles.thumb(colorPalette) as ThumbStyleExtended
58
65
 
59
- const halfSize = (thumbStyle.width ?? 0) / 2
60
- const thumbSize = {
61
- width: thumbStyle.width,
62
- height: thumbStyle.height,
63
- }
64
- const maximumTrackWidth = maximumTrackStyle.height ?? 0
65
- const minimumTrackWidth = minimumTrackStyle.height ?? 0
66
+ const halfSize =
67
+ axis === 'x' ? (thumbStyle.width ?? 0) / 2 : (thumbStyle.height ?? 0) / 2
66
68
  const context = useSharedValue({x: 0})
67
69
  const translate = useSharedValue(value)
68
70
  const trackLength = useSharedValue(0)
69
71
  const isInsideChild = useSharedValue(false)
70
72
 
71
- const handleTrackLayout = (event: LayoutChangeEvent) => {
72
- const {width, height} = event.nativeEvent.layout
73
- trackLength.value = axis === 'x' ? width : height
74
- }
73
+ // const handleTrackLayout = (event: LayoutChangeEvent) => {
74
+ // const {width, height} = event.nativeEvent.layout
75
+ // console.log('🚀 ~ handleTrackLayout ~ width:', width)
76
+ // trackLength.value = axis === 'x' ? width : height
77
+ // }
75
78
 
76
79
  const slideGesture = Gesture.Pan()
77
80
  .onTouchesDown(() => {
@@ -81,6 +84,7 @@ const Slider = ({
81
84
  context.value.x = translate.value
82
85
  })
83
86
  .onUpdate(e => {
87
+ // console.log('e', e.translationX)
84
88
  const stepLength = steps ? trackLength.value / steps : 1
85
89
  const delta = axis === 'y' ? -e.translationY : e.translationX
86
90
 
@@ -161,17 +165,18 @@ const Slider = ({
161
165
  return (
162
166
  <View
163
167
  style={[
164
- styles.container(maximumTrackWidth, halfSize),
168
+ styles.container(halfSize),
165
169
  SliderStyles.container(colorPalette),
166
170
  ]}>
167
171
  {axis === 'x' && <View style={{width: halfSize}} />}
168
172
  <GestureDetector gesture={tapGesture}>
169
173
  <View
170
174
  style={[
171
- styles.maximumTrack(maximumTrackWidth),
175
+ styles.maximumTrack(),
172
176
  SliderStyles.maximumTrack(colorPalette),
173
177
  ]}
174
- onLayout={handleTrackLayout}>
178
+ // onLayout={handleTrackLayout}
179
+ >
175
180
  {steps && (
176
181
  <View style={styles.steps}>
177
182
  {Array.from({length: steps + 1}, (_, index) => index).map(
@@ -189,7 +194,7 @@ const Slider = ({
189
194
  )}
190
195
  <Animated.View
191
196
  style={[
192
- styles.minimumTrack(halfSize, minimumTrackWidth),
197
+ styles.minimumTrack(halfSize),
193
198
  SliderStyles.minimumTrack(colorPalette, opacityTrack),
194
199
  animatedTrack,
195
200
  ]}>
@@ -197,7 +202,7 @@ const Slider = ({
197
202
  <View
198
203
  style={[
199
204
  SliderStyles.thumb(colorPalette),
200
- styles.thumb(halfSize, thumbSize),
205
+ styles.thumb(halfSize),
201
206
  ]}>
202
207
  {ThumbChildren || null}
203
208
  </View>
@@ -210,115 +215,171 @@ const Slider = ({
210
215
  )
211
216
  }
212
217
 
213
- const stylesX = StyleSheet.create(theme => ({
214
- container: (thickness, halfSize) => ({
215
- flex: thickness ? 1 : 1,
216
- maxWidth: 'auto',
217
- borderRadius: 22,
218
- width: '100%',
219
- height: '100%',
220
- paddingTop: 0,
221
- paddingRight: halfSize,
222
- flexDirection: 'row',
223
- }),
224
- maximumTrack: thickness => ({
225
- flex: thickness ? 1 : 1,
226
- justifyContent: 'center',
227
- position: 'relative',
228
- borderRadius: 22,
229
- }),
230
- minimumTrack: (halfSize, minimumTrackThickness) => ({
231
- height: minimumTrackThickness,
232
- width: '100%',
233
- left: halfSize * -1,
234
- bottom: 'auto',
235
- paddingBottom: 0,
236
- paddingLeft: halfSize,
237
- borderBottomLeftRadius: 20,
238
- borderBottomRightRadius: 0,
239
- borderTopLeftRadius: 20,
240
- justifyContent: 'center',
241
- }),
242
- thumb: (halfSize, thumbSize) => ({
243
- width: halfSize ? thumbSize.width : thumbSize.width,
244
- height: thumbSize.height,
245
- borderRadius: 25,
246
- position: 'absolute',
247
- right: 0,
248
- zIndex: 2,
249
- transform: [{translateX: '50%'}],
250
- }),
251
- steps: {
252
- width: '100%',
253
- height: '100%',
254
- flexDirection: 'row',
255
- justifyContent: 'space-between',
256
- alignItems: 'center',
257
- zIndex: 0,
258
- position: 'absolute',
259
- },
260
- step: (index, length) => ({
261
- width: 1,
262
- height: '100%',
263
- backgroundColor:
264
- index === 0 || index === length ? 'transparent' : theme.colors.fg.default,
218
+ const styles = StyleSheet.create(theme => ({
219
+ container: (halfSize: number) => ({
220
+ variants: {
221
+ axis: {
222
+ x: {
223
+ maxWidth: 'auto',
224
+ width: '100%',
225
+ paddingTop: 0,
226
+ paddingRight: halfSize,
227
+ flexDirection: 'row',
228
+ },
229
+ y: {
230
+ maxHeight: 'auto',
231
+ height: '100%',
232
+ paddingTop: halfSize,
233
+ paddingRight: 0,
234
+ flexDirection: 'column',
235
+ },
236
+ },
237
+ },
265
238
  }),
266
- }))
267
- const stylesY = StyleSheet.create(theme => ({
268
- container: (maximumTrackWidth, halfSize) => ({
269
- flex: 1,
270
- maxWidth: maximumTrackWidth,
271
- maxHeight: 'auto',
272
- borderRadius: 22,
273
- width: '100%',
274
- height: '100%',
275
- paddingTop: halfSize,
276
- paddingRight: 0,
277
- flexDirection: 'column',
278
- }),
279
- maximumTrack: maximumTrackWidth => ({
239
+ maximumTrack: () => ({
280
240
  flex: 1,
281
241
  justifyContent: 'center',
282
- alignItems: 'center',
283
242
  position: 'relative',
284
- maxWidth: maximumTrackWidth,
243
+ variants: {
244
+ axis: {
245
+ x: {},
246
+ y: {
247
+ alignItems: 'center',
248
+ },
249
+ },
250
+ },
285
251
  }),
286
- minimumTrack: (halfSize, minimumTrackWidth) => ({
287
- position: 'absolute',
288
- height: '100%',
289
- width: minimumTrackWidth,
290
- left: 'auto',
291
- bottom: halfSize * -1,
292
- paddingBottom: halfSize,
293
- paddingLeft: 0,
294
- borderBottomLeftRadius: 20,
295
- borderBottomRightRadius: 20,
296
- borderTopLeftRadius: 0,
297
- alignItems: 'center',
252
+ minimumTrack: (halfSize: number) => ({
253
+ variants: {
254
+ axis: {
255
+ x: {
256
+ width: '100%',
257
+ left: halfSize * -1,
258
+ bottom: 'auto',
259
+ paddingBottom: 0,
260
+ paddingLeft: halfSize,
261
+ borderBottomLeftRadius: 20,
262
+ borderBottomRightRadius: 0,
263
+ borderTopLeftRadius: 20,
264
+ justifyContent: 'center',
265
+ },
266
+ y: {
267
+ position: 'absolute',
268
+ height: '100%',
269
+ left: 'auto',
270
+ bottom: halfSize * -1,
271
+ paddingBottom: halfSize,
272
+ paddingLeft: 0,
273
+ borderBottomLeftRadius: 20,
274
+ borderBottomRightRadius: 20,
275
+ borderTopLeftRadius: 0,
276
+ alignItems: 'center',
277
+ },
278
+ },
279
+ },
298
280
  }),
299
- thumb: (halfSize, thumbSize) => ({
281
+ thumb: halfSize => ({
300
282
  borderRadius: 25,
301
283
  position: 'absolute',
302
- top: 0,
303
- zIndex: 2,
304
- transform: [{translateY: halfSize * -1}],
305
- width: thumbSize.height,
306
- height: thumbSize.width,
284
+ variants: {
285
+ axis: {
286
+ x: {
287
+ right: 0,
288
+ zIndex: 2,
289
+ transform: [{translateX: '50%'}],
290
+ },
291
+ y: {
292
+ top: 0,
293
+ zIndex: 2,
294
+ transform: [{translateY: halfSize * -1}],
295
+ },
296
+ },
297
+ },
307
298
  }),
308
299
  steps: {
309
300
  width: '100%',
310
301
  height: '100%',
311
- flexDirection: 'column',
312
302
  justifyContent: 'space-between',
313
303
  alignItems: 'center',
314
304
  zIndex: 0,
305
+ variants: {
306
+ axis: {
307
+ x: {
308
+ flexDirection: 'row',
309
+ position: 'absolute',
310
+ },
311
+ y: {
312
+ flexDirection: 'column',
313
+ },
314
+ },
315
+ },
315
316
  },
316
317
  step: (index, length) => ({
317
- width: '100%',
318
- height: 1,
319
318
  backgroundColor:
320
319
  index === 0 || index === length ? 'transparent' : theme.colors.fg.default,
320
+ variants: {
321
+ axis: {
322
+ x: {
323
+ width: 1,
324
+ height: '100%',
325
+ },
326
+ y: {
327
+ width: '100%',
328
+ height: 1,
329
+ },
330
+ },
331
+ },
321
332
  }),
322
333
  }))
334
+ // const stylesY = StyleSheet.create(theme => ({
335
+ // container: halfSize => ({
336
+ // maxHeight: 'auto',
337
+ // height: '100%',
338
+ // paddingTop: halfSize,
339
+ // paddingRight: 0,
340
+ // flexDirection: 'column',
341
+ // }),
342
+ // maximumTrack: () => ({
343
+ // flex: 1,
344
+ // justifyContent: 'center',
345
+ // alignItems: 'center',
346
+ // position: 'relative',
347
+ // // borderWidth: 1,
348
+ // // borderColor: 'yellow',
349
+ // }),
350
+ // minimumTrack: halfSize => ({
351
+ // position: 'absolute',
352
+ // height: '100%',
353
+ // left: 'auto',
354
+ // bottom: halfSize * -1,
355
+ // paddingBottom: halfSize,
356
+ // paddingLeft: 0,
357
+ // borderBottomLeftRadius: 20,
358
+ // borderBottomRightRadius: 20,
359
+ // borderTopLeftRadius: 0,
360
+ // alignItems: 'center',
361
+ // }),
362
+ // thumb: halfSize => ({
363
+ // borderRadius: 25,
364
+ // position: 'absolute',
365
+ // top: 0,
366
+ // zIndex: 2,
367
+ // transform: [{translateY: halfSize * -1}],
368
+ // }),
369
+ // steps: {
370
+ // width: '100%',
371
+ // height: '100%',
372
+ // justifyContent: 'space-between',
373
+ // alignItems: 'center',
374
+ // zIndex: 0,
375
+ // flexDirection: 'column',
376
+ // },
377
+ // step: (index, length) => ({
378
+ // width: '100%',
379
+ // height: 1,
380
+ // backgroundColor:
381
+ // index === 0 || index === length ? 'transparent' : theme.colors.fg.default,
382
+ // }),
383
+ // }))
323
384
 
324
385
  export default Slider