react-native-varia 0.4.0 → 0.4.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.
@@ -0,0 +1,215 @@
1
+ import React, {createContext, useContext} from 'react'
2
+ import {View, Pressable} from 'react-native'
3
+ import Animated, {
4
+ withDelay,
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ withSpring,
8
+ withTiming,
9
+ } from 'react-native-reanimated'
10
+ import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
11
+ import Plus from '../icons/Plus'
12
+ import {
13
+ FloatingActionDefaultVariants,
14
+ FloatingActionStyles,
15
+ } from '../theme/FloatingAction'
16
+ import {ViewStyle} from 'react-native'
17
+ import {PalettesWithNestedKeys} from '../style/varia/types'
18
+ import {getVariantValue} from '../style/varia/utils'
19
+
20
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable)
21
+
22
+ const SPRING_CONFIG = {
23
+ duration: 800,
24
+ overshootClamping: true,
25
+ dampingRatio: 0.8,
26
+ }
27
+
28
+ const FloatingActionContext = createContext<any>(null)
29
+
30
+ const useFloatingContext = () => {
31
+ const ctx = useContext(FloatingActionContext)
32
+ if (!ctx)
33
+ throw new Error('FloatingAction.Item must be inside FloatingAction.Root')
34
+ return ctx
35
+ }
36
+
37
+ type ItemProps = FloatingActionVariants & {
38
+ children: React.ReactNode
39
+ onPress: () => void
40
+ }
41
+
42
+ function Item({children, onPress, ...props}: ItemProps) {
43
+ const {
44
+ direction,
45
+ gap,
46
+ isExpanded,
47
+ index,
48
+ variant,
49
+ size,
50
+ colorPalette = 'accent',
51
+ } = {...useFloatingContext(), ...props}
52
+ FloatingActionStyles.useVariants({
53
+ variant,
54
+ size,
55
+ })
56
+
57
+ const iconHeight = getVariantValue(
58
+ FloatingActionStyles.button(colorPalette),
59
+ 'size',
60
+ size,
61
+ 'height',
62
+ )
63
+ const animatedStyles = useAnimatedStyle(() => {
64
+ const multiplier = direction === 'toTop' ? -1 : 1
65
+ const OFFSET_FROM_MAIN = iconHeight + gap
66
+
67
+ const moveValue = isExpanded.value
68
+ ? (OFFSET_FROM_MAIN + (gap + iconHeight) * (index - 1)) * multiplier
69
+ : 0
70
+
71
+ const delay = index * 30
72
+
73
+ return {
74
+ opacity: withDelay(
75
+ delay,
76
+ withTiming(isExpanded.value ? 1 : 0, {duration: 150}),
77
+ ),
78
+ transform: [
79
+ {translateY: withDelay(delay, withSpring(moveValue, SPRING_CONFIG))},
80
+ {
81
+ scale: withDelay(
82
+ delay,
83
+ withTiming(isExpanded.value ? 1 : 0.95, {duration: 200}),
84
+ ),
85
+ },
86
+ ],
87
+ }
88
+ })
89
+
90
+ return (
91
+ <AnimatedPressable
92
+ style={[
93
+ animatedStyles,
94
+ styles.itemButton,
95
+ FloatingActionStyles.item(colorPalette),
96
+ ]}
97
+ onPress={onPress}>
98
+ {children}
99
+ </AnimatedPressable>
100
+ )
101
+ }
102
+
103
+ type directions = 'toTop' | 'toBottom'
104
+ type FloatingActionVariants = UnistylesVariants<typeof FloatingActionStyles>
105
+ type FloatingActionProps = FloatingActionVariants & {
106
+ colorPalette?: PalettesWithNestedKeys
107
+ gap?: ViewStyle['gap']
108
+ direction?: directions
109
+ top?: ViewStyle['top']
110
+ bottom?: ViewStyle['bottom']
111
+ right?: ViewStyle['right']
112
+ left?: ViewStyle['left']
113
+ children: React.ReactNode
114
+ }
115
+
116
+ function Root({
117
+ variant = FloatingActionDefaultVariants.variant,
118
+ size = FloatingActionDefaultVariants.size,
119
+ colorPalette = 'accent',
120
+ children,
121
+ gap = 10,
122
+ direction = 'toTop',
123
+ top = null,
124
+ bottom = null,
125
+ right = null,
126
+ left = null,
127
+ }: FloatingActionProps) {
128
+ FloatingActionStyles.useVariants({
129
+ variant,
130
+ size,
131
+ })
132
+
133
+ const isExpanded = useSharedValue(false)
134
+
135
+ const plusIconStyle = useAnimatedStyle(() => ({
136
+ transform: [{rotate: withTiming(isExpanded.value ? '45deg' : '0deg')}],
137
+ }))
138
+
139
+ const arrayChildren = React.Children.toArray(children)
140
+
141
+ const iconHeight = getVariantValue(
142
+ FloatingActionStyles.button(colorPalette),
143
+ 'size',
144
+ size,
145
+ 'height',
146
+ )
147
+ const iconColor = getVariantValue(
148
+ FloatingActionStyles.buttonIcon(colorPalette),
149
+ 'variant',
150
+ variant,
151
+ 'color',
152
+ )
153
+ console.log('🚀 ~ iconColor:', iconColor)
154
+
155
+ return (
156
+ <View
157
+ style={[
158
+ styles.buttonContainer(top, bottom, left, right),
159
+ FloatingActionStyles.buttonContainer(colorPalette),
160
+ ]}>
161
+ <AnimatedPressable
162
+ onPress={() => (isExpanded.value = !isExpanded.value)}
163
+ style={[
164
+ plusIconStyle,
165
+ styles.button,
166
+ FloatingActionStyles.button(colorPalette),
167
+ ]}>
168
+ <Plus size={iconHeight - 20} color={iconColor} />
169
+ </AnimatedPressable>
170
+ {arrayChildren.map((child: any, i) => (
171
+ <FloatingActionContext.Provider
172
+ key={i}
173
+ value={{
174
+ direction,
175
+ gap,
176
+ isExpanded,
177
+ index: i + 1,
178
+ variant,
179
+ size,
180
+ colorPalette,
181
+ }}>
182
+ {child}
183
+ </FloatingActionContext.Provider>
184
+ ))}
185
+ </View>
186
+ )
187
+ }
188
+
189
+ const FloatingAction = {
190
+ Root,
191
+ Item,
192
+ }
193
+ export default FloatingAction
194
+
195
+ const styles = StyleSheet.create({
196
+ buttonContainer: (top, bottom, left, right) => ({
197
+ position: 'absolute',
198
+ ...(top !== null && top !== undefined ? {top} : {}),
199
+ ...(bottom !== null && bottom !== undefined ? {bottom} : {}),
200
+ ...(left !== null && left !== undefined ? {left} : {}),
201
+ ...(right !== null && right !== undefined ? {right} : {}),
202
+ zIndex: 99,
203
+ alignItems: 'center',
204
+ }),
205
+ button: {
206
+ zIndex: 1,
207
+ justifyContent: 'center',
208
+ alignItems: 'center',
209
+ },
210
+ itemButton: {
211
+ position: 'absolute',
212
+ justifyContent: 'center',
213
+ alignItems: 'center',
214
+ },
215
+ })
@@ -68,7 +68,7 @@ const Icon = ({
68
68
  <Svg
69
69
  width={size || width}
70
70
  height={size || height}
71
- viewBox="0 0 24 24"
71
+ viewBox="0 0 23 23"
72
72
  // viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
73
73
  fill="none"
74
74
  {...rest}>
@@ -0,0 +1,112 @@
1
+ import {StyleSheet} from 'react-native-unistyles'
2
+ import {PalettesWithNestedKeys} from '../style/varia/types'
3
+ import {textStyle} from '../style/varia/textStyles'
4
+
5
+ export const FloatingActionDefaultVariants = {
6
+ variant: 'solid',
7
+ size: 'md',
8
+ } as const
9
+
10
+ export const FloatingActionStyles = StyleSheet.create(theme => ({
11
+ buttonContainer: (colorPalette: PalettesWithNestedKeys) => ({
12
+ variants: {
13
+ variant: {
14
+ solid: {},
15
+ subtle: {},
16
+ outline: {},
17
+ ghost: {},
18
+ },
19
+ size: {
20
+ sm: {},
21
+ md: {},
22
+ lg: {},
23
+ },
24
+ },
25
+ }),
26
+ button: (colorPalette: PalettesWithNestedKeys) => ({
27
+ borderRadius: theme.radii.full,
28
+ variants: {
29
+ variant: {
30
+ solid: {
31
+ backgroundColor: theme.colors[colorPalette].default,
32
+ },
33
+ outline: {
34
+ borderWidth: 1,
35
+ borderColor: theme.colors[colorPalette].a7,
36
+ },
37
+ subtle: {
38
+ backgroundColor: theme.colors[colorPalette]['a3'],
39
+ },
40
+ ghost: {
41
+ backgroundColor: 'transparent',
42
+ },
43
+ },
44
+ size: {
45
+ sm: {
46
+ height: theme.sizes['8'],
47
+ width: theme.sizes['8'],
48
+ },
49
+ md: {
50
+ height: theme.sizes['10'],
51
+ width: theme.sizes['10'],
52
+ },
53
+ lg: {
54
+ height: theme.sizes['16'],
55
+ width: theme.sizes['16'],
56
+ },
57
+ },
58
+ },
59
+ }),
60
+ buttonIcon: (colorPalette: PalettesWithNestedKeys) => ({
61
+ variants: {
62
+ variant: {
63
+ solid: {
64
+ color: theme.colors.fg.default,
65
+ },
66
+ outline: {
67
+ color: theme.colors[colorPalette].text,
68
+ },
69
+ ghost: {
70
+ color: theme.colors.gray.text,
71
+ },
72
+ subtle: {
73
+ color: theme.colors[colorPalette].text,
74
+ },
75
+ },
76
+ },
77
+ }),
78
+ item: (colorPalette: PalettesWithNestedKeys) => ({
79
+ borderRadius: theme.radii.full,
80
+ variants: {
81
+ variant: {
82
+ solid: {
83
+ backgroundColor: theme.colors[colorPalette].default,
84
+ },
85
+ outline: {
86
+ borderWidth: 1,
87
+ borderColor: theme.colors[colorPalette].a7,
88
+ },
89
+ subtle: {
90
+ backgroundColor: theme.colors[colorPalette]['a3'],
91
+ },
92
+ ghost: {
93
+ backgroundColor: 'transparent',
94
+ },
95
+ },
96
+ size: {
97
+ sm: {
98
+ height: theme.sizes['8'],
99
+ width: theme.sizes['8'],
100
+ },
101
+ md: {
102
+ height: theme.sizes['10'],
103
+ width: theme.sizes['10'],
104
+ },
105
+ lg: {
106
+ height: theme.sizes['16'],
107
+ width: theme.sizes['16'],
108
+ },
109
+ },
110
+ },
111
+ }),
112
+ }))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-varia",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "bin": {
5
5
  "varia": "bin/cli.js"
6
6
  },