react-native-varia 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -12,26 +12,188 @@ A Component library based on **react-native-unistyles** that provides a CLI tool
12
12
  yarn add -D react-native-varia
13
13
  ```
14
14
 
15
- You also need to install [react-native-unistyles](https://www.unistyl.es/v3/start/getting-started) for advanced styling capabilities:
15
+ You also need to install [react-native-unistyles](https://www.unistyl.es/v3/start/getting-started)
16
+
17
+ 2. Components dependencies
18
+
19
+ | Component | Dependencies |
20
+ | ------------------ | ---------------------------------------------------------------------------- |
21
+ | Badge | - |
22
+ | Button | react-native-svg |
23
+ | Checkbox | react-native-svg |
24
+ | CircleProgress | react-native-reanimated, react-native-svg |
25
+ | Field | - |
26
+ | GradientBackground | react-native-svg |
27
+ | GradientText | react-native-svg |
28
+ | Input | - |
29
+ | Link | - |
30
+ | Modal | react-native-reanimated, @gorhom/portal, react-native-svg |
31
+ | NumberInput | - |
32
+ | RadioGroup | - |
33
+ | ReText | react-native-reanimated |
34
+ | Select | @gorhom/portal |
35
+ | Slider | react-native-reanimated, react-native-gesture-handler, react-native-worklets |
36
+ | Slideshow | react-native-reanimated, react-native-gesture-handler, react-native-worklets |
37
+ | SlidingDrawer | react-native-reanimated, react-native-gesture-handler, react-native-worklets |
38
+ | Spinner | - |
39
+ | Switch | react-native-reanimated |
40
+
41
+ Install react-native-reanimated, react-native-worklets and react-native-gesture-handler.
16
42
 
17
- 2. Some components has reanimated dependency.
18
- If you are going to use the next components:
19
-
20
- - Slider
21
- - SlidingDrawer
22
- - Slideshow
23
- - Switch
24
- - ReText
25
- - Modal
26
-
27
- Install react-native-reanimated and react-native-worklets.
28
43
  Check the [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/) docs.
29
- And install react-native-gesture-handler.
44
+
30
45
  Check the [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation) docs.
31
46
 
32
- 3. Install react-native-svg.
47
+ Check the [react-native-worklets](https://docs.swmansion.com/react-native-worklets/docs/) docs.
48
+
49
+ Check the [react-native-svg](https://github.com/software-mansion/react-native-svg?tab=readme-ov-file#installation) docs.
50
+
51
+ Check the [react-native-portal](https://github.com/gorhom/react-native-portal) docs.
52
+
53
+ ## Varia setup
54
+
55
+ Now you need to run:
56
+
57
+ ```
58
+ npx varia setup
59
+ ```
60
+
61
+ This will copy the mixins, types and utils files from **lib** into **src/style/varia**.
62
+
63
+ ## About ColorPalettes
64
+
65
+ React Native Varia uses a color palette system to provide a consistent color scheme for your app. It is based on Radix color palette system.
66
+ Check the [Radix Color Palettes](https://www.radix-ui.com/colors/docs/palette-composition/scales) for more information.
67
+
68
+ Check how to [Compose a color palette](https://www.radix-ui.com/colors/docs/palette-composition/composing-a-palette) for more information.
69
+
70
+ Varia has the same color palettes as Radix built-in.
71
+ In the next section you will learn how to add them.
72
+
73
+ ## Creating your Theme
74
+
75
+ After setting up react-native unistyles theme, you will need to update it, to include the color palette system and default token needed for varia components.
76
+
77
+ In you src/style/themes.ts file, you will need to update it, to include the color palettes you will use:
78
+
79
+ ```ts
80
+ import {tomato} from './varia/colorPalettes/tomato'
81
+ import {teal} from './varia/colorPalettes/teal'
82
+ import {slate} from './varia/colorPalettes/slate'
83
+ import {iris} from './varia/colorPalettes/iris'
84
+ ```
85
+
86
+ Create a your preset with them, following how to [Compose a color palette](https://www.radix-ui.com/colors/docs/palette-composition/composing-a-palette) from radix you will set an accent and a gray color palette, and a red color palette is needed as well for default error styling in the components:
87
+
88
+ ```ts
89
+ import {slate} from './varia/colorPalettes/slate'
90
+ import {iris} from './varia/colorPalettes/iris'
91
+ import {red} from './varia/colorPalettes/red'
92
+
93
+ export const colorPalettes = createPreset({
94
+ accent: iris,
95
+ gray: slate,
96
+ red,
97
+ })
98
+ ```
33
99
 
34
- `yarn add react-native-svg`
100
+ Beside those color palettes you can add more optional color palettes to your theme.
101
+
102
+ ```ts
103
+ import {lime} from './varia/colorPalettes/lime'
104
+ import {olive} from './varia/colorPalettes/olive'
105
+ import {red} from './varia/colorPalettes/red'
106
+ import {yellow} from './varia/colorPalettes/yellow'
107
+ import {forest} from './varia/colorPalettes/forest'
108
+
109
+ export const colorPalettes = createPreset({
110
+ accent: lime,
111
+ gray: olive,
112
+ red,
113
+ yellow,
114
+ forest,
115
+ })
116
+ ```
117
+
118
+ Include de default theme tokens:
119
+
120
+ ```ts
121
+ import {
122
+ defaultColors,
123
+ defaultFontSizes,
124
+ defaultFontWeights,
125
+ defaultRadii,
126
+ defaultShadows,
127
+ defaultSizes,
128
+ defaultSpacing,
129
+ } from './varia/defaultTheme'
130
+ ```
131
+
132
+ Create the base theme, here you can override the default tokens with whatever you want:
133
+
134
+ ```ts
135
+ export const base = {
136
+ colors: {
137
+ ...defaultColors,
138
+ },
139
+ fontWeights: {
140
+ ...defaultFontWeights,
141
+ },
142
+ sizes: {
143
+ ...defaultSizes,
144
+ },
145
+ fontSizes: {
146
+ ...defaultFontSizes,
147
+ },
148
+ spacing: {
149
+ ...defaultSpacing,
150
+ },
151
+ radii: {
152
+ ...defaultRadii,
153
+ },
154
+ } as const
155
+ ```
156
+
157
+ Get the shadows tokens:
158
+
159
+ ```ts
160
+ const lightShadows = defaultShadows(colorPalettes.light)
161
+ const darkShadows = defaultShadows(colorPalettes.dark)
162
+ ```
163
+
164
+ Ensamble the light and dark theme, you can add extend here with independent light and dark colors:
165
+
166
+ ```ts
167
+ export const lightTheme = {
168
+ colors: {
169
+ ...base.colors,
170
+ ...colorPalettes.light,
171
+ },
172
+ fontSizes: base.fontSizes,
173
+ fontWeights: base.fontWeights,
174
+ spacing: base.spacing,
175
+ radii: base.radii,
176
+ sizes: base.sizes,
177
+ shadows: {
178
+ ...lightShadows,
179
+ },
180
+ } as const
181
+
182
+ export const darkTheme = {
183
+ colors: {
184
+ ...base.colors,
185
+ ...colorPalettes.dark,
186
+ },
187
+ fontSizes: base.fontSizes,
188
+ fontWeights: base.fontWeights,
189
+ spacing: base.spacing,
190
+ radii: base.radii,
191
+ sizes: base.sizes,
192
+ shadows: {
193
+ ...darkShadows,
194
+ },
195
+ } as const
196
+ ```
35
197
 
36
198
  ## ⚙️ Available Commands
37
199
 
@@ -47,7 +209,11 @@ Once installed, you can use the following commands via `npx varia`:
47
209
 
48
210
  | Command | Description |
49
211
  | -------------------------------- | -------------------------------------------------------------------------------- |
50
- | `npx varia setup` | Copies the mixins, types and utils files from **lib** into **src/style**. |
51
- | `npx varia add <component_name>` | Copies the specified component from **lib/components** into your project. |
212
+ | `npx varia setup` | Adds the mixins, types and utils files from to **src/style/varia**. |
213
+ | `npx varia add <component_name>` | Adds the specified component into your project **src/components**. |
52
214
  | `npx varia add-icon <icon_name>` | Copies the **Icon.tsx** template and renames it to the specified icon name. |
53
215
  | `npx varia add-patterns` | Copies the entire **lib/patterns** folder into **src/patterns** in your project. |
216
+
217
+ ```
218
+
219
+ ```
@@ -40,22 +40,14 @@ const Badge = ({
40
40
 
41
41
  const displayedContent = max && content > max ? `${max}+` : content
42
42
 
43
- // @ts-ignore
44
- const badgeSize = BadgeStyles.container(colorPalette).minWidth
45
- const withoutChildrenSize = !children ? badgeSize : 'auto'
46
-
47
- return (
48
- <HStack
49
- style={{
50
- position: 'relative',
51
- minWidth: withoutChildrenSize,
52
- height: withoutChildrenSize,
53
- }}>
54
- {children && children}
43
+ return children ? (
44
+ <HStack style={{position: 'relative'}}>
45
+ {children}
55
46
  <View
56
47
  testID="varia-badge"
57
48
  style={[
58
- styles.badge(x, y),
49
+ styles.badge,
50
+ styles.badgeAbsolute(x, y),
59
51
  BadgeStyles.container(colorPalette),
60
52
  mixins && mixins,
61
53
  ]}>
@@ -64,18 +56,23 @@ const Badge = ({
64
56
  </Text>
65
57
  </View>
66
58
  </HStack>
59
+ ) : (
60
+ <View
61
+ testID="varia-badge"
62
+ style={[
63
+ styles.badge,
64
+ BadgeStyles.container(colorPalette),
65
+ mixins && mixins,
66
+ ]}>
67
+ <Text style={[styles.text, BadgeStyles.text(colorPalette)]}>
68
+ {displayedContent}
69
+ </Text>
70
+ </View>
67
71
  )
68
72
  }
69
73
 
70
74
  const styles = StyleSheet.create({
71
- badge: (x, y) => ({
72
- position: 'absolute',
73
- [y]: 0,
74
- [x]: 0,
75
- transform: [
76
- {translateY: y === 'top' ? '-30%' : '30%'},
77
- {translateX: x === 'left' ? '-30%' : '30%'},
78
- ],
75
+ badge: {
79
76
  paddingVertical: 1,
80
77
  paddingHorizontal: 6,
81
78
  zIndex: 1,
@@ -83,6 +80,15 @@ const styles = StyleSheet.create({
83
80
  borderWidth: 1,
84
81
  alignItems: 'center',
85
82
  justifyContent: 'center',
83
+ },
84
+ badgeAbsolute: (x, y) => ({
85
+ position: 'absolute',
86
+ [y]: 0,
87
+ [x]: 0,
88
+ transform: [
89
+ {translateY: y === 'top' ? '-50%' : '50%'},
90
+ {translateX: x === 'left' ? '-50%' : '50%'},
91
+ ],
86
92
  }),
87
93
  text: {
88
94
  textAlign: 'center',
@@ -3,7 +3,7 @@ import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
3
3
  import {ButtonStyles, ButtonDefaultVariants} from '../theme/Button.recipe'
4
4
  import {useMemo} from 'react'
5
5
  import {IconWrapperProps} from './IconWrapper'
6
- import Spinner from './Spinner'
6
+ import Spinner, {SpinnerProps} from './Spinner'
7
7
  import {PalettesWithNestedKeys} from '../style/varia/types'
8
8
 
9
9
  type TextAdjustment = 'singleLine' | 'multiline' | 'adjustToFit'
@@ -75,7 +75,6 @@ const Button = ({
75
75
  rotation: icon.rotation,
76
76
  scale: icon.scale,
77
77
  colorPalette,
78
- //@ts-ignore
79
78
  size: icon.size,
80
79
  color: ButtonStyles.text(colorPalette).color,
81
80
  }}
@@ -93,10 +92,8 @@ const Button = ({
93
92
  disabled={disabled || loading}>
94
93
  {loading ? (
95
94
  <Spinner
96
- //@ts-ignore
97
- size={ButtonStyles.text.fontSize}
98
- //@ts-ignore
99
- color={ButtonStyles.text.color}
95
+ size={size as SpinnerProps['size']}
96
+ color={ButtonStyles.text(colorPalette).color}
100
97
  />
101
98
  ) : (
102
99
  <>
@@ -31,10 +31,12 @@ function Checkbox({
31
31
 
32
32
  const isChecked = checked
33
33
 
34
- // @ts-ignore
35
- const checkSize = CheckboxStyles.check(colorPalette).width
36
- // @ts-ignore
37
- const checkColor = CheckboxStyles.check(colorPalette).color
34
+ const checkStyle = CheckboxStyles.check(colorPalette) as {
35
+ width: string
36
+ color: string
37
+ }
38
+ const checkSize = checkStyle.width
39
+ const checkColor = checkStyle.color
38
40
 
39
41
  return (
40
42
  <Pressable
@@ -67,13 +69,7 @@ export {Checkbox}
67
69
 
68
70
  const Check = ({size, color}: {size: string; color: string}) => {
69
71
  return (
70
- <Svg
71
- width={size}
72
- height={size}
73
- viewBox="0 0 16 13"
74
- fill="none"
75
- // @ts-ignore: svg props
76
- xmlns="http://www.w3.org/2000/svg">
72
+ <Svg width={size} height={size} viewBox="0 0 16 13" fill="none">
77
73
  <Line
78
74
  x1="1.64402"
79
75
  y1="6.05591"
@@ -1,4 +1,4 @@
1
- import {useEffect, useLayoutEffect, useRef} from 'react'
1
+ import {useEffect} from 'react'
2
2
  import {View, StyleSheet} from 'react-native'
3
3
  import Animated, {
4
4
  Easing,
@@ -46,17 +46,6 @@ const BaseCircleProgress = ({
46
46
  children,
47
47
  colors,
48
48
  }: CircleProgressProps) => {
49
- const container = useRef<View>(null)
50
-
51
- // useLayoutEffect(() => {
52
- // //@ts-ignore
53
- // container.current?.measure((x, y, width, height) => {
54
- // const pxPerUnit = width / svgSize
55
- // const strokeWidthSVG =
56
- // circleProgressTokens.variants.size[size]?.trackStrokeWidth * pxPerUnit
57
- // })
58
- // }, [])
59
-
60
49
  const resolvedSize = circleProgressTokens.variants.size[size]
61
50
 
62
51
  const colorValue = circleProgressTokens.variants.variant[variant]
@@ -108,7 +97,7 @@ const BaseCircleProgress = ({
108
97
  })
109
98
 
110
99
  return (
111
- <View style={styles.container} ref={container}>
100
+ <View style={styles.container}>
112
101
  <Svg
113
102
  width="100%"
114
103
  height="100%"
@@ -1,8 +1,8 @@
1
1
  import React, {createContext, useContext} from 'react'
2
+ import {UnistylesVariants} from 'react-native-unistyles'
2
3
  import Text from './Text'
3
4
  import {VStack} from '../patterns'
4
5
  import {DefaultFieldVariants, FieldStyles} from '../theme/Field.recipe'
5
- import {UnistylesVariants} from 'react-native-unistyles'
6
6
  import {PalettesWithNestedKeys} from '../style/varia/types'
7
7
 
8
8
  type FieldVariants = UnistylesVariants<typeof FieldStyles>
@@ -90,10 +90,7 @@ const FieldLabel = ({children, ...props}: FieldLabelProps) => {
90
90
  FieldStyles.useVariants({variant, size})
91
91
 
92
92
  return (
93
- <Text
94
- size={size}
95
- // @ts-ignore
96
- color={FieldStyles.label(colorPalette).color}>
93
+ <Text size={size} color={FieldStyles.label(colorPalette).color}>
97
94
  {children}
98
95
  </Text>
99
96
  )
@@ -121,7 +118,6 @@ const FieldError = ({...props}: FieldErrorProps) => {
121
118
  FieldStyles.useVariants({size, variant})
122
119
 
123
120
  return (
124
- // @ts-ignore
125
121
  <Text size={size} color={FieldStyles.error(colorPalette).color}>
126
122
  {error}
127
123
  </Text>
@@ -66,6 +66,11 @@ const Input = ({
66
66
  invalid,
67
67
  })
68
68
 
69
+ const placeholderStyle = InputStyles.placeholder(colorPalette) as {
70
+ color: string
71
+ }
72
+ const placeholderColor = placeholderStyle.color
73
+
69
74
  return (
70
75
  <HStack
71
76
  style={{
@@ -82,8 +87,7 @@ const Input = ({
82
87
  ]}
83
88
  value={value}
84
89
  placeholder={placeholder}
85
- // @ts-ignore
86
- placeholderTextColor={InputStyles.placeholder(colorPalette).color}
90
+ placeholderTextColor={placeholderColor}
87
91
  inputMode={inputMode}
88
92
  keyboardType={keyboardType}
89
93
  secureTextEntry={password}
@@ -6,8 +6,8 @@ import {
6
6
  type StyleProp,
7
7
  type ViewStyle,
8
8
  } from 'react-native'
9
- import Text from './Text'
10
9
  import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
10
+ import Text from './Text'
11
11
  import {PalettesWithNestedKeys, ThemeColors} from '../style/varia/types'
12
12
  import {DefaultTextVariants, TextStyles} from '../theme/Text.recipe'
13
13
  type TextVariants = UnistylesVariants<typeof TextStyles>
@@ -6,12 +6,12 @@ import {
6
6
  StyleSheet as RNStyleSheet,
7
7
  } from 'react-native'
8
8
  import Animated from 'react-native-reanimated'
9
+ import {Portal} from '@gorhom/portal'
10
+ import Svg, {Path} from 'react-native-svg'
9
11
  import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
10
12
  import Text from './Text'
11
- import Svg, {Path} from 'react-native-svg'
12
13
  import {ModalStyles, ModalTokens} from '../theme/Modal.recipe'
13
14
  import {PalettesWithNestedKeys} from '../style/varia/types'
14
- import {Portal} from '@gorhom/portal'
15
15
 
16
16
  type ModalVariants = UnistylesVariants<typeof ModalStyles>
17
17
  type AnimationKey = keyof typeof ModalTokens.animations.variants
@@ -176,8 +176,6 @@ const CloseButton = ({
176
176
  }: CloseButtonProps) => (
177
177
  <TouchableOpacity onPress={onClose}>
178
178
  <Svg
179
- // @ts-ignore
180
- xmlns="http://www.w3.org/2000/svg"
181
179
  width={scale * 24}
182
180
  height={scale * 24}
183
181
  viewBox={`0 0 ${24} ${24}`}
@@ -1,12 +1,11 @@
1
1
  import React, {createContext, useContext, useState} from 'react'
2
2
  import {View, TextInput, Pressable} from 'react-native'
3
+ import {UnistylesVariants, StyleSheet} from 'react-native-unistyles'
3
4
  import {
4
5
  NumberInputStyles,
5
6
  NumberInputDefaultVariants,
6
7
  } from '../theme/NumberInput.recipe'
7
8
  import {PalettesWithNestedKeys} from '../style/varia/types'
8
- import {UnistylesVariants, StyleSheet} from 'react-native-unistyles'
9
- import Arrow from '../icons/Arrow'
10
9
  import Plus from '../icons/Plus'
11
10
  import Minus from '../icons/Minus'
12
11
 
@@ -1,3 +1,4 @@
1
+ import {useMemo} from 'react'
1
2
  import type {StyleProp, TextInputProps, TextStyle} from 'react-native'
2
3
  import {TextInput} from 'react-native'
3
4
  import Animated, {SharedValue, useAnimatedProps} from 'react-native-reanimated'
@@ -8,7 +9,6 @@ import {
8
9
  ThemeColors,
9
10
  } from '../style/varia/types'
10
11
  import {TextStyles, DefaultTextVariants} from '../theme/Text.recipe'
11
- import {useMemo} from 'react'
12
12
  import {extractThemeColor} from '../style/varia/utils'
13
13
 
14
14
  type ReTextVariants = UnistylesVariants<typeof TextStyles>
@@ -12,12 +12,12 @@ import {
12
12
  TouchableWithoutFeedback,
13
13
  StyleSheet,
14
14
  } from 'react-native'
15
+ import {UnistylesVariants} from 'react-native-unistyles'
15
16
  import {Portal} from '@gorhom/portal'
16
17
  import Text from './Text'
17
18
  import {StyleSheet as UniStyleSheet} from 'react-native-unistyles'
18
19
  import {SelectStyles, SelectDefaultVariants} from '../theme/Select.recipe'
19
20
  import {PalettesWithNestedKeys} from '../style/varia/types'
20
- import {UnistylesVariants} from 'react-native-unistyles'
21
21
 
22
22
  type SelectVariants = UnistylesVariants<typeof SelectStyles>
23
23
 
@@ -52,19 +52,17 @@ const Slider = ({
52
52
  size,
53
53
  variant,
54
54
  })
55
- // @ts-ignore
56
- const halfSize = (SliderStyles.thumb(colorPalette).width ?? 0) / 2
55
+ const thumbStyle = SliderStyles.thumb(colorPalette)
56
+ const maximumTrackStyle = SliderStyles.maximumTrack(colorPalette)
57
+ const minimumTrackStyle = SliderStyles.minimumTrack(colorPalette, false)
58
+
59
+ const halfSize = (thumbStyle.width ?? 0) / 2
57
60
  const thumbSize = {
58
- // @ts-ignore
59
- width: SliderStyles.thumb(colorPalette).width,
60
- // @ts-ignore
61
- height: SliderStyles.thumb(colorPalette).height,
61
+ width: thumbStyle.width,
62
+ height: thumbStyle.height,
62
63
  }
63
- // @ts-ignore
64
- const maximumTrackWidth = SliderStyles.maximumTrack(colorPalette).height ?? 0
65
- const minimumTrackWidth =
66
- // @ts-ignore
67
- SliderStyles.minimumTrack(colorPalette, false).height ?? 0
64
+ const maximumTrackWidth = maximumTrackStyle.height ?? 0
65
+ const minimumTrackWidth = minimumTrackStyle.height ?? 0
68
66
  const context = useSharedValue({x: 0})
69
67
  const translate = useSharedValue(value)
70
68
  const trackLength = useSharedValue(0)
@@ -1,6 +1,6 @@
1
- import {Gesture, GestureDetector} from 'react-native-gesture-handler'
2
1
  import React, {useImperativeHandle} from 'react'
3
2
  import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
3
+ import {Gesture, GestureDetector} from 'react-native-gesture-handler'
4
4
  import Animated, {
5
5
  useAnimatedStyle,
6
6
  useSharedValue,
@@ -4,15 +4,14 @@ import {
4
4
  type StyleProp,
5
5
  type ViewStyle,
6
6
  } from 'react-native'
7
- import {withUnistyles} from 'react-native-unistyles'
7
+ import {withUnistyles, UnistylesVariants} from 'react-native-unistyles'
8
8
  import {PalettesWithNestedKeys, ThemeColors} from '../style/varia/types'
9
9
  import {SpinnerTokens} from '../theme/Spinner.recipe'
10
10
  import {resolveColor} from '../style/varia/utils'
11
11
  import {SpinnerStyles} from '../theme/Spinner.recipe'
12
- import {UnistylesVariants} from 'react-native-unistyles'
13
12
 
14
13
  type SpinnerVariants = UnistylesVariants<typeof SpinnerStyles>
15
- type SpinnerProps = SpinnerVariants &
14
+ export type SpinnerProps = SpinnerVariants &
16
15
  Omit<ActivityIndicatorProps, 'size'> & {
17
16
  color?: ThemeColors
18
17
  style?: StyleProp<ViewStyle>
@@ -1,4 +1,4 @@
1
- import {TouchableWithoutFeedback} from 'react-native'
1
+ import {TouchableWithoutFeedback, View} from 'react-native'
2
2
  import Animated, {
3
3
  useAnimatedStyle,
4
4
  useSharedValue,
@@ -41,7 +41,7 @@ const Switch = ({
41
41
  size = SwitchTokens.defaultProps.size,
42
42
  flex = 1,
43
43
  }: SwitchProps) => {
44
- const animatedRef = useRef(null)
44
+ const animatedRef = useRef<View>(null)
45
45
 
46
46
  const isAnimating = useSharedValue(false)
47
47
 
@@ -76,15 +76,11 @@ const Switch = ({
76
76
  const containerWidth = useSharedValue(0)
77
77
 
78
78
  useLayoutEffect(() => {
79
- //@ts-ignore
80
79
  animatedRef.current?.measure((x, y, width) => {
81
80
  containerWidth.value = width
82
- //@ts-ignore
83
81
  const thumbWidth = SwitchStyles.thumb(colorPalette).width
84
- //@ts-ignore
85
82
  const padding = SwitchStyles.container(colorPalette).padding || 0
86
83
  const trackBorderWidth =
87
- //@ts-ignore
88
84
  SwitchStyles.container(colorPalette).borderWidth || 0
89
85
  thumbEnabledPosition.value =
90
86
  width - thumbWidth - trackBorderWidth * 2 - padding * 2
@@ -269,12 +269,11 @@ export const FlexGrid = ({
269
269
  style?: any
270
270
  children: ReactNode
271
271
  }) => {
272
- const viewRef = useRef(null)
272
+ const viewRef = useRef<View>(null)
273
273
  const gridItems = Children.toArray(children)
274
274
  const [parentWidth, setParentWidth] = useState(0)
275
275
 
276
276
  useLayoutEffect(() => {
277
- // @ts-ignore
278
277
  viewRef.current?.measure((x, y, width, height, pageX, pageY) => {
279
278
  setParentWidth(width)
280
279
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-varia",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "bin": {
5
5
  "varia": "bin/cli.js"
6
6
  },
@@ -1,153 +0,0 @@
1
- import React, {useState} from 'react'
2
- import {
3
- View,
4
- Text,
5
- TouchableOpacity,
6
- ScrollView,
7
- TouchableWithoutFeedback,
8
- } from 'react-native'
9
- import {StyleSheet} from 'react-native-unistyles'
10
- import {SelectStyles, SelectDefaultVariants} from '../theme/Select.recipe'
11
- import {PalettesWithNestedKeys} from '../style/varia/types'
12
- import {UnistylesVariants} from 'react-native-unistyles'
13
- import {Modal} from './Modal'
14
-
15
- type SelectVariants = UnistylesVariants<typeof SelectStyles>
16
-
17
- interface Option {
18
- label: string
19
- value: string
20
- }
21
-
22
- type SelectProps = SelectVariants & {
23
- options: Option[]
24
- value?: string
25
- onChange?: (value: string) => void
26
- onBlur?: () => void
27
- defaultValue?: string
28
- placeholder?: string
29
- colorPalette?: PalettesWithNestedKeys
30
- flex?: number
31
- }
32
-
33
- export const Select = ({
34
- options,
35
- value: propValue,
36
- onChange: propOnChange,
37
- onBlur: propOnBlur,
38
- defaultValue = '',
39
- placeholder = 'Selecciona una opción',
40
- variant = SelectDefaultVariants.variant,
41
- size = SelectDefaultVariants.size,
42
- colorPalette = 'accent',
43
- flex = 1,
44
- }: SelectProps) => {
45
- SelectStyles.useVariants({
46
- variant,
47
- size,
48
- })
49
-
50
- const [isOpen, setIsOpen] = useState(false)
51
- const [internalValue, setInternalValue] = useState<string>(defaultValue)
52
-
53
- const isControlled = propValue !== undefined && propOnChange !== undefined
54
-
55
- const value = isControlled ? propValue! : internalValue
56
-
57
- const handleSelect = (val: string) => {
58
- if (isControlled) {
59
- propOnChange!(val)
60
- } else {
61
- setInternalValue(val)
62
- }
63
- setIsOpen(false)
64
- }
65
-
66
- const selectedOption = options.find(opt => opt.value === value)
67
-
68
- return (
69
- <>
70
- <TouchableWithoutFeedback
71
- onPress={() => {
72
- setIsOpen(true)
73
- propOnBlur?.()
74
- }}>
75
- <View
76
- style={[
77
- styles.container(flex),
78
- SelectStyles.container(colorPalette),
79
- ]}>
80
- <View style={[styles.input, SelectStyles.input(colorPalette)]}>
81
- <Text
82
- style={[SelectStyles.valueText(colorPalette, !!selectedOption)]}>
83
- {selectedOption ? selectedOption.label : placeholder}
84
- </Text>
85
- </View>
86
- </View>
87
- </TouchableWithoutFeedback>
88
-
89
- {/* Modal con lista de opciones */}
90
- <Modal.Root
91
- isOpen={isOpen}
92
- setIsOpen={setIsOpen}
93
- colorPalette={colorPalette}
94
- variant="outline"
95
- portalHostName="select">
96
- <Modal.Overlay variant={'outline'} customStyle={SelectStyles}>
97
- <Modal.Content>
98
- <Modal.Body>
99
- <ScrollView
100
- style={[SelectStyles.ModalContainer(colorPalette)]}
101
- contentContainerStyle={[
102
- SelectStyles.itemsContainer(colorPalette),
103
- ]}>
104
- {options.map(item => (
105
- <TouchableOpacity
106
- key={item.value}
107
- onPress={() => handleSelect(item.value)}>
108
- <View
109
- style={[
110
- styles.item,
111
- SelectStyles.item(
112
- colorPalette,
113
- selectedOption?.value === item.value,
114
- ),
115
- ]}>
116
- <Text
117
- style={SelectStyles.itemText(
118
- colorPalette,
119
- selectedOption?.value === item.value,
120
- )}>
121
- {item.label}
122
- </Text>
123
- </View>
124
- </TouchableOpacity>
125
- ))}
126
- </ScrollView>
127
- </Modal.Body>
128
- </Modal.Content>
129
- </Modal.Overlay>
130
- </Modal.Root>
131
- </>
132
- )
133
- }
134
-
135
- const styles = StyleSheet.create({
136
- container: (flex: number) => ({
137
- flexGrow: flex,
138
- flexDirection: 'row',
139
- justifyContent: 'center',
140
- }),
141
- input: {
142
- flex: 1,
143
- flexDirection: 'row',
144
- alignItems: 'center',
145
- justifyContent: 'center',
146
- },
147
- item: {
148
- paddingVertical: 2,
149
- paddingHorizontal: 8,
150
- alignItems: 'center',
151
- flexDirection: 'row',
152
- },
153
- })
@@ -1,174 +0,0 @@
1
- import {TouchableWithoutFeedback} from 'react-native'
2
- import Animated, {
3
- Easing,
4
- useAnimatedStyle,
5
- useSharedValue,
6
- withSpring,
7
- withTiming,
8
- } from 'react-native-reanimated'
9
- import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
10
- import {useAnimatedVariantColor} from 'react-native-unistyles/reanimated'
11
- import {useLayoutEffect, useRef, useState} from 'react'
12
- import {SwitchTokens, SwitchStyles} from '../theme/Switch.recipe'
13
- import {PalettesWithNestedKeys} from '../style/varia/types'
14
-
15
- const animations = {
16
- withSpring,
17
- withTiming,
18
- }
19
-
20
- type AnimationType = 'withSpring' | 'withTiming'
21
-
22
- type SwitchVariants = UnistylesVariants<typeof SwitchStyles>
23
-
24
- type SwitchProps = SwitchVariants & {
25
- colorPalette?: PalettesWithNestedKeys
26
- value?: boolean
27
- animation?: keyof typeof SwitchTokens.variants.animation
28
- onValueChange?: (value: boolean) => void
29
- flex?: number
30
- }
31
-
32
- const Switch = ({
33
- colorPalette = 'accent',
34
- value,
35
- animation = SwitchTokens.defaultProps.animation,
36
- onValueChange = () => {},
37
- variant = SwitchTokens.defaultProps.variant,
38
- size = SwitchTokens.defaultProps.size,
39
- flex = 1,
40
- }: SwitchProps) => {
41
- const animatedRef = useRef(null)
42
-
43
- SwitchStyles.useVariants({
44
- variant,
45
- size,
46
- enabled: value,
47
- })
48
-
49
- const animationVariant =
50
- SwitchTokens.variants?.animation && animation
51
- ? SwitchTokens.variants.animation[animation]
52
- : {
53
- type: 'withSpring' as AnimationType,
54
- props: {
55
- damping: 15,
56
- stiffness: 100,
57
- mass: 1,
58
- },
59
- }
60
- console.log('🚀 ~ animationVariant:', animationVariant)
61
-
62
- const color = useAnimatedVariantColor(
63
- SwitchStyles.container(colorPalette),
64
- 'backgroundColor',
65
- )
66
- const thumbColor = useAnimatedVariantColor(
67
- SwitchStyles.thumb(colorPalette),
68
- 'backgroundColor',
69
- )
70
- const thumbEnabledPosition = useSharedValue(0)
71
- const animatedValue = useSharedValue(0)
72
- const containerWidth = useSharedValue(0)
73
-
74
- useLayoutEffect(() => {
75
- //@ts-ignore
76
- animatedRef.current?.measure((x, y, width) => {
77
- containerWidth.value = width
78
- //@ts-ignore
79
- const thumbWidth = SwitchStyles.thumb(colorPalette).width
80
- //@ts-ignore
81
- const padding = SwitchStyles.container(colorPalette).padding || 0
82
- const trackBorderWidth =
83
- //@ts-ignore
84
- SwitchStyles.container(colorPalette).borderWidth || 0
85
- thumbEnabledPosition.value =
86
- width - thumbWidth - trackBorderWidth * 2 - padding * 2
87
- })
88
- }, [])
89
-
90
- const animatedStyle = useAnimatedStyle(() => {
91
- return {
92
- backgroundColor: animations[animationVariant.type](
93
- color.value,
94
- animationVariant.props,
95
- ),
96
- // backgroundColor: withTiming(color.value, {
97
- // duration: 100,
98
- // easing: Easing.ease,
99
- // }),
100
- }
101
- })
102
- const thumbAnimatedStyle = useAnimatedStyle(() => {
103
- return {
104
- backgroundColor: animations[animationVariant.type](
105
- thumbColor.value,
106
- animationVariant.props,
107
- ),
108
- // backgroundColor: withTiming(thumbColor.value, {
109
- // duration: 100,
110
- // easing: Easing.ease,
111
- // }),
112
- }
113
- })
114
-
115
- const circleTranslationStyle = useAnimatedStyle(() => {
116
- return {
117
- transform: [
118
- {
119
- translateX: animatedValue.value,
120
- },
121
- ],
122
- }
123
- })
124
-
125
- return (
126
- <TouchableWithoutFeedback
127
- onPress={() => {
128
- onValueChange(!value)
129
- animatedValue.value = animations[animationVariant.type](
130
- animatedValue.value === 0 ? thumbEnabledPosition.value : 0,
131
- animationVariant.props,
132
- )
133
- // animatedValue.value = withTiming(
134
- // animatedValue.value === 0 ? thumbEnabledPosition.value : 0,
135
- // {duration: 100, easing: Easing.ease},
136
- // )
137
- }}>
138
- <Animated.View
139
- ref={animatedRef}
140
- style={[
141
- styles.container(flex),
142
- animatedStyle,
143
- SwitchStyles.container(colorPalette),
144
- ]}>
145
- <Animated.View
146
- style={[
147
- styles.thumb,
148
- SwitchStyles.thumb(colorPalette),
149
- thumbAnimatedStyle,
150
- circleTranslationStyle,
151
- ]}
152
- />
153
- </Animated.View>
154
- </TouchableWithoutFeedback>
155
- )
156
- }
157
-
158
- export default Switch
159
-
160
- const styles = StyleSheet.create((theme, rt) => ({
161
- container: (flex: number) => ({
162
- // flex,
163
- flexGrow: flex,
164
- flexShrink: 0,
165
- alignSelf: 'flex-start',
166
- flexDirection: 'row',
167
- alignItems: 'center',
168
- margin: 0,
169
- borderRadius: 20,
170
- }),
171
- thumb: {
172
- borderRadius: 9999,
173
- },
174
- }))
package/lib/mixins.ts DELETED
@@ -1,180 +0,0 @@
1
- import {StyleSheet} from 'react-native-unistyles';
2
- import { ThemeColors } from '../src/style/types';
3
- import { extractThemeColor } from './utils';
4
-
5
- // const extractThemeColor = (color: ThemeColors, theme: any) => {
6
- // return color in theme.colors ? theme.colors[color] : color;
7
- // }
8
-
9
- const mixins = StyleSheet.create((theme, rt) => ({
10
- size: (width: number, height: number = width) => ({
11
- width,
12
- height,
13
- }),
14
- row: {
15
- justifyContent: 'center',
16
- flexDirection: 'row',
17
- },
18
- gap: (gap: number) => ({
19
- gap,
20
- }),
21
- center: {
22
- alignItems: 'center',
23
- justifyContent: 'center',
24
- },
25
- sx: (sx: any) => ({
26
- ...sx,
27
- }),
28
- w: (width: number) => ({
29
- width,
30
- }),
31
- h: (height: number) => ({
32
- height,
33
- }),
34
- bg: (backgroundColor: ThemeColors) => ({
35
- backgroundColor: extractThemeColor(backgroundColor, theme),
36
- }),
37
- flexColumn: (flex: number = 1) => ({
38
- flex,
39
- width: '100%',
40
- }),
41
- flexRow: (flex: number = 1) => ({
42
- flex,
43
- height: '100%',
44
- }),
45
- minMaxW: (minWidth: number, maxWidth: number) => ({
46
- minWidth,
47
- maxWidth,
48
- }),
49
- minMaxH: (minHeight: number, maxHeight: number) => ({
50
- minHeight,
51
- maxHeight,
52
- }),
53
- vw: (amount: number) => ({
54
- width:
55
- ((rt.screen.width - rt.insets.left - rt.insets.right) * amount) / 100,
56
- }),
57
- vh: (amount: number) => ({
58
- height:
59
- ((rt.screen.height - rt.insets.top - rt.insets.bottom) * amount) / 100,
60
- }),
61
- vwh: (amount: number) => ({
62
- width:
63
- ((rt.screen.width - rt.insets.left - rt.insets.right) * amount) / 100,
64
- height:
65
- ((rt.screen.height - rt.insets.top - rt.insets.bottom) * amount) / 100,
66
- }),
67
- self: (
68
- alignSelf: 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch',
69
- ) => ({
70
- alignSelf,
71
- }),
72
- justify: (
73
- justifyContent:
74
- | 'flex-start'
75
- | 'flex-end'
76
- | 'center'
77
- | 'space-around'
78
- | 'space-between'
79
- | 'space-evenly',
80
- ) => ({
81
- justifyContent,
82
- }),
83
- rtl: {
84
- direction: 'rtl',
85
- },
86
- ar: (aspectRatio: number) => ({
87
- aspectRatio,
88
- }),
89
- br: (borderRadius: number) => ({
90
- borderRadius,
91
- }),
92
- bw: (borderWidth: number) => ({
93
- borderWidth,
94
- }),
95
- bc: (borderColor: ThemeColors) => ({
96
- borderColor: extractThemeColor(borderColor, theme),
97
- }),
98
- border: (borderWidth: number, borderColor: ThemeColors) => ({
99
- borderWidth,
100
- borderColor: extractThemeColor(borderColor, theme),
101
- }),
102
- m: (margin: number) => ({
103
- margin,
104
- }),
105
- mt: (marginTop: number) => ({
106
- marginTop,
107
- }),
108
- mb: (marginBottom: number) => ({
109
- marginBottom,
110
- }),
111
- ml: (marginLeft: number) => ({
112
- marginLeft,
113
- }),
114
- mr: (marginRight: number) => ({
115
- marginRight,
116
- }),
117
- mx: (marginHorizontal: number) => ({
118
- marginHorizontal,
119
- }),
120
- my: (marginVertical: number) => ({
121
- marginVertical,
122
- }),
123
- p: (padding: number) => ({
124
- padding,
125
- }),
126
- pt: (paddingTop: number) => ({
127
- paddingTop,
128
- }),
129
- pb: (paddingBottom: number) => ({
130
- paddingBottom,
131
- }),
132
- pl: (paddingLeft: number) => ({
133
- paddingLeft,
134
- }),
135
- pr: (paddingRight: number) => ({
136
- paddingRight,
137
- }),
138
- px: (paddingHorizontal: number) => ({
139
- paddingHorizontal,
140
- }),
141
- py: (paddingVertical: number) => ({
142
- paddingVertical,
143
- }),
144
- t: (top: number = 0) => ({
145
- position: 'absolute',
146
- top,
147
- }),
148
- b: (bottom: number = 0) => ({
149
- position: 'absolute',
150
- bottom,
151
- }),
152
- l: (left: number = 0) => ({
153
- position: 'absolute',
154
- left,
155
- }),
156
- r: (right: number = 0) => ({
157
- position: 'absolute',
158
- right,
159
- }),
160
- static: {
161
- position: 'static',
162
- },
163
- absolute: {
164
- position: 'absolute',
165
- },
166
- relative: {
167
- position: 'relative',
168
- },
169
- z: (zIndex: number) => ({
170
- zIndex,
171
- }),
172
- opacity: (opacity: number) => ({
173
- opacity,
174
- }),
175
- circle: {
176
- borderRadius: 9999,
177
- },
178
- }));
179
-
180
- export default mixins;
package/lib/types.ts DELETED
@@ -1,70 +0,0 @@
1
- import { darkTheme, lightTheme } from "./themes";
2
-
3
- const themes = {
4
- light: lightTheme,
5
- dark: darkTheme,
6
- };
7
-
8
- export type ColorsType = (typeof themes)[keyof typeof themes]['colors'];
9
-
10
- export type ThemeType = (typeof themes)[keyof typeof themes];
11
-
12
- export type TextSemanticSizes =
13
- | 'h1'
14
- | 'h2'
15
- | 'h3'
16
- | 'h4'
17
- | 'h5'
18
- | 'h6'
19
- | 'h7'
20
- | 'h8'
21
- | 'h9'
22
- | 'body';
23
-
24
- export type directions =
25
- | 'to top'
26
- | 'to bottom'
27
- | 'to left'
28
- | 'to right'
29
- | 'to top left'
30
- | 'to top right'
31
- | 'to bottom left'
32
- | 'to bottom right';
33
-
34
- type ColorName = keyof ColorsType;
35
-
36
- type LooseString<T extends string> = T | (string & {});
37
-
38
- export type ThemeColors = LooseString<ColorName>;
39
-
40
- export function createGradientTokens<
41
- const CP extends Record<string, { startColor: ThemeColors; endColor: ThemeColors }>
42
- >(tokens: {
43
- defaultProps: { colorPalette: keyof CP; direction: directions };
44
- variants: {
45
- direction: Record<directions, { x1: number; y1: number; x2: number; y2: number }>;
46
- colorPalette: CP;
47
- };
48
- }) {
49
- return tokens;
50
- }
51
-
52
- type SVGSize = {
53
- width: number;
54
- height: number;
55
- viewBoxWidth: number;
56
- viewBoxHeight: number;
57
- }
58
-
59
- export function createIconTokens<
60
- const CP extends Record<string, { color: ThemeColors }>
61
- >(tokens: {
62
- defaultProps: { colorPalette: keyof CP; size: any, scale: number };
63
- variants: {
64
- size: Record<string, SVGSize>;
65
- colorPalette: CP;
66
- };
67
- }) {
68
- return tokens;
69
- }
70
-
package/lib/utils.ts DELETED
@@ -1,80 +0,0 @@
1
- export function hexToRgba(hex: string, alpha: number = 1) {
2
- // Remove the leading '#' if present
3
- hex = hex.replace(/^#/, '');
4
-
5
- // Parse the red, green, and blue components
6
- let r, g, b, a;
7
-
8
- if (hex.length === 6) {
9
- r = parseInt(hex.slice(0, 2), 16);
10
- g = parseInt(hex.slice(2, 4), 16);
11
- b = parseInt(hex.slice(4, 6), 16);
12
- a = alpha; // Use the provided alpha value
13
- } else if (hex.length === 8) {
14
- r = parseInt(hex.slice(0, 2), 16);
15
- g = parseInt(hex.slice(2, 4), 16);
16
- b = parseInt(hex.slice(4, 6), 16);
17
- a = parseInt(hex.slice(6, 8), 16) / 255; // Normalize alpha to 0-1
18
- } else {
19
- throw new Error('Invalid hex color format. Use #RRGGBB or #RRGGBBAA.');
20
- }
21
-
22
- return `rgba(${r}, ${g}, ${b}, ${a})`;
23
- }
24
-
25
- import {Dimensions, PixelRatio} from 'react-native';
26
- import { ThemeColors } from '../src/style/types';
27
-
28
- const {width, height} = Dimensions.get('window');
29
-
30
- const guidelineBaseWidth = 375;
31
- const guidelineBaseHeight = 667;
32
-
33
- const scale = (size: number): number => (width / guidelineBaseWidth) * size;
34
- const verticalScale = (size: number): number =>
35
- (height / guidelineBaseHeight) * size;
36
- const moderateScale = (size: number, factor: number = 0.5): number =>
37
- size + (scale(size) - size) * factor;
38
-
39
- // FONT SCALING
40
- // Usage: nf(16)
41
- const scaleNew = height / 667;
42
- const normalizeFont = (size: number): number => {
43
- const newSize = size * scaleNew;
44
- return Math.round(PixelRatio.roundToNearestPixel(newSize));
45
- };
46
-
47
- // DYNAMIC DIMENSION CONSTANTS
48
- // Usage: wp(5), hp(20)
49
- const widthPercentageToDP = (widthPercent: string): number => {
50
- // Convert string input to decimal number
51
- const elemWidth = parseFloat(widthPercent);
52
- return PixelRatio.roundToNearestPixel((width * elemWidth) / 100);
53
- };
54
- const heightPercentageToDP = (heightPercent: string): number => {
55
- // Convert string input to decimal number
56
- const elemHeight = parseFloat(heightPercent);
57
- return PixelRatio.roundToNearestPixel((height * elemHeight) / 100);
58
- };
59
-
60
- // Usage: wpx(141), hpx(220)
61
- const widthFromPixel = (widthPx: number, w: number = 414): number =>
62
- widthPx * (width / w);
63
- const heightFromPixel = (heightPx: number, h: number = 896): number =>
64
- heightPx * (height / h);
65
-
66
- export {
67
- scale,
68
- verticalScale,
69
- moderateScale,
70
- normalizeFont as nf,
71
- widthPercentageToDP as wp,
72
- heightPercentageToDP as hp,
73
- widthFromPixel as wpx,
74
- heightFromPixel as hpx,
75
- };
76
-
77
- export const extractThemeColor = (color: ThemeColors, theme: any) => {
78
- return color in theme.colors ? theme.colors[color] : color;
79
- }
80
-