react-native-varia 0.0.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.
- package/README.md +53 -0
- package/bin/cli.js +200 -0
- package/lib/components/Badge.tsx +96 -0
- package/lib/components/Button.tsx +131 -0
- package/lib/components/CircleProgress.tsx +180 -0
- package/lib/components/Divider.tsx +43 -0
- package/lib/components/GradientBackground.tsx +68 -0
- package/lib/components/GradientText.tsx +121 -0
- package/lib/components/Icon.tsx +13 -0
- package/lib/components/IconWrapper.tsx +109 -0
- package/lib/components/Input.tsx +120 -0
- package/lib/components/Link.tsx +87 -0
- package/lib/components/Modal.tsx +157 -0
- package/lib/components/ReText.tsx +124 -0
- package/lib/components/Slider.tsx +334 -0
- package/lib/components/Slideshow.tsx +317 -0
- package/lib/components/SlidingDrawer.tsx +307 -0
- package/lib/components/Spinner.tsx +44 -0
- package/lib/components/Switch.tsx +224 -0
- package/lib/components/Text.tsx +107 -0
- package/lib/components/index.tsx +83 -0
- package/lib/mixins.ts +180 -0
- package/lib/patterns/index.tsx +426 -0
- package/lib/theme/Badge.recipe.tsx +68 -0
- package/lib/theme/Button.recipe-old.tsx +67 -0
- package/lib/theme/Button.recipe.tsx +83 -0
- package/lib/theme/CircleProgress.recipe.tsx +42 -0
- package/lib/theme/GradientBackground.recipe.tsx +38 -0
- package/lib/theme/GradientText.recipe.tsx +49 -0
- package/lib/theme/Icon.recipe.tsx +122 -0
- package/lib/theme/IconWrapper.recipe.tsx +121 -0
- package/lib/theme/Input.recipe.tsx +110 -0
- package/lib/theme/Link.recipe.tsx +51 -0
- package/lib/theme/Modal.recipe.tsx +34 -0
- package/lib/theme/ReText.recipe.tsx +7 -0
- package/lib/theme/Slider.recipe.tsx +226 -0
- package/lib/theme/Slideshow.recipe.tsx +142 -0
- package/lib/theme/SlidingDrawer.recipe.tsx +91 -0
- package/lib/theme/Spinner.recipe.tsx +8 -0
- package/lib/theme/Switch.recipe.tsx +70 -0
- package/lib/theme/Text.recipe.tsx +10 -0
- package/lib/types.ts +70 -0
- package/lib/utils.ts +80 -0
- package/package.json +18 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {View, StyleSheet, type ColorValue} from 'react-native'
|
|
2
|
+
import Svg, {Defs, LinearGradient, Stop, Rect} from 'react-native-svg'
|
|
3
|
+
import {withUnistyles} from 'react-native-unistyles'
|
|
4
|
+
import {gradientBackgroundTokens} from '../theme/GradientBackground.recipe'
|
|
5
|
+
|
|
6
|
+
interface GradientBackgroundProps {
|
|
7
|
+
colorPalette?: keyof typeof gradientBackgroundTokens.variants.colorPalette
|
|
8
|
+
direction?: keyof typeof gradientBackgroundTokens.variants.direction
|
|
9
|
+
// colors: Record<string, ColorValue>;
|
|
10
|
+
colors: Record<string, ColorValue>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const BaseGradientBackground = ({
|
|
14
|
+
colorPalette = gradientBackgroundTokens.defaultProps.colorPalette,
|
|
15
|
+
direction = gradientBackgroundTokens.defaultProps.direction,
|
|
16
|
+
colors,
|
|
17
|
+
}: GradientBackgroundProps) => {
|
|
18
|
+
const tokenColorKey =
|
|
19
|
+
gradientBackgroundTokens.variants.colorPalette[colorPalette]
|
|
20
|
+
const startColor =
|
|
21
|
+
tokenColorKey.startColor in colors
|
|
22
|
+
? colors[tokenColorKey.startColor]
|
|
23
|
+
: tokenColorKey.startColor
|
|
24
|
+
|
|
25
|
+
const endColor =
|
|
26
|
+
tokenColorKey.endColor in colors
|
|
27
|
+
? colors[tokenColorKey.endColor]
|
|
28
|
+
: tokenColorKey.endColor
|
|
29
|
+
|
|
30
|
+
const directionVariant =
|
|
31
|
+
gradientBackgroundTokens.variants.direction[direction]
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<View style={styles.container}>
|
|
35
|
+
<Svg
|
|
36
|
+
width="100%"
|
|
37
|
+
height="100%"
|
|
38
|
+
viewBox="0 0 100 100"
|
|
39
|
+
preserveAspectRatio="none">
|
|
40
|
+
<Defs>
|
|
41
|
+
<LinearGradient
|
|
42
|
+
id="grad"
|
|
43
|
+
x1={directionVariant?.x1}
|
|
44
|
+
y1={directionVariant?.y1}
|
|
45
|
+
x2={directionVariant?.x2}
|
|
46
|
+
y2={directionVariant?.y2}>
|
|
47
|
+
<Stop offset="0%" stopColor={startColor} stopOpacity="1" />
|
|
48
|
+
<Stop offset="100%" stopColor={endColor} stopOpacity="1" />
|
|
49
|
+
</LinearGradient>
|
|
50
|
+
</Defs>
|
|
51
|
+
<Rect width="100" height="100" fill="url(#grad)" />
|
|
52
|
+
</Svg>
|
|
53
|
+
</View>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const styles = StyleSheet.create({
|
|
58
|
+
container: {
|
|
59
|
+
...StyleSheet.absoluteFillObject,
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// export default GradientBackground;
|
|
64
|
+
const GradientBackground = withUnistyles(BaseGradientBackground, theme => ({
|
|
65
|
+
colors: theme.colors,
|
|
66
|
+
}))
|
|
67
|
+
|
|
68
|
+
export default GradientBackground
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {View, type ColorValue} from 'react-native'
|
|
2
|
+
import Svg, {
|
|
3
|
+
Defs,
|
|
4
|
+
LinearGradient,
|
|
5
|
+
Stop,
|
|
6
|
+
Text,
|
|
7
|
+
type NumberProp,
|
|
8
|
+
} from 'react-native-svg'
|
|
9
|
+
import {StyleSheet, withUnistyles} from 'react-native-unistyles'
|
|
10
|
+
import {gradientTextTokens} from '../theme/GradientText.recipe'
|
|
11
|
+
import {TextSemanticSizes} from '../style/types'
|
|
12
|
+
|
|
13
|
+
interface GradientTextProps {
|
|
14
|
+
colorPalette?: keyof typeof gradientTextTokens.variants.colorPalette
|
|
15
|
+
direction?: keyof typeof gradientTextTokens.variants.direction
|
|
16
|
+
// colors: Record<string, ColorValue>;
|
|
17
|
+
colors: Record<string, ColorValue>
|
|
18
|
+
as?: TextSemanticSizes
|
|
19
|
+
fontSize?: number | undefined
|
|
20
|
+
children?: React.ReactNode
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const BaseGradientText = ({
|
|
24
|
+
as = 'body',
|
|
25
|
+
fontSize,
|
|
26
|
+
colorPalette = gradientTextTokens.defaultProps.colorPalette,
|
|
27
|
+
direction = gradientTextTokens.defaultProps.direction,
|
|
28
|
+
colors,
|
|
29
|
+
children,
|
|
30
|
+
}: GradientTextProps) => {
|
|
31
|
+
const tokenColorKey = gradientTextTokens.variants.colorPalette[colorPalette]
|
|
32
|
+
const startColor =
|
|
33
|
+
tokenColorKey.startColor in colors
|
|
34
|
+
? colors[tokenColorKey.startColor]
|
|
35
|
+
: tokenColorKey.startColor
|
|
36
|
+
|
|
37
|
+
const endColor =
|
|
38
|
+
tokenColorKey.endColor in colors
|
|
39
|
+
? colors[tokenColorKey.endColor]
|
|
40
|
+
: tokenColorKey.endColor
|
|
41
|
+
|
|
42
|
+
const directionVariant = gradientTextTokens.variants.direction[direction]
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<View style={{flexDirection: 'row'}}>
|
|
46
|
+
<View style={{width: '100%'}}>
|
|
47
|
+
<Svg height={styles[as](fontSize).fontSize + 20} width="100%">
|
|
48
|
+
<Defs>
|
|
49
|
+
<LinearGradient
|
|
50
|
+
id="gradient"
|
|
51
|
+
x1={directionVariant?.x1 as NumberProp}
|
|
52
|
+
y1={directionVariant?.y1 as NumberProp}
|
|
53
|
+
x2={directionVariant?.x2 as NumberProp}
|
|
54
|
+
y2={directionVariant?.y2 as NumberProp}>
|
|
55
|
+
<Stop offset="0%" stopColor={startColor as ColorValue} />
|
|
56
|
+
<Stop offset="100%" stopColor={endColor as ColorValue} />
|
|
57
|
+
</LinearGradient>
|
|
58
|
+
</Defs>
|
|
59
|
+
<Text
|
|
60
|
+
fill="url(#gradient)"
|
|
61
|
+
fontSize={styles[as](fontSize).fontSize}
|
|
62
|
+
fontWeight={400}
|
|
63
|
+
x="50%"
|
|
64
|
+
y={styles[as](fontSize).fontSize}
|
|
65
|
+
textAnchor="middle">
|
|
66
|
+
{children}
|
|
67
|
+
</Text>
|
|
68
|
+
</Svg>
|
|
69
|
+
</View>
|
|
70
|
+
</View>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const styles = StyleSheet.create(theme => ({
|
|
75
|
+
h1: fontSize => ({
|
|
76
|
+
//@ts-ignore
|
|
77
|
+
fontSize: fontSize || theme.fontSizes.xxl,
|
|
78
|
+
}),
|
|
79
|
+
h2: fontSize => ({
|
|
80
|
+
//@ts-ignore
|
|
81
|
+
fontSize: fontSize || theme.fontSizes.xl,
|
|
82
|
+
}),
|
|
83
|
+
h3: fontSize => ({
|
|
84
|
+
//@ts-ignore
|
|
85
|
+
fontSize: fontSize || theme.fontSizes.lg,
|
|
86
|
+
}),
|
|
87
|
+
h4: fontSize => ({
|
|
88
|
+
//@ts-ignore
|
|
89
|
+
fontSize: fontSize || theme.fontSizes.md,
|
|
90
|
+
}),
|
|
91
|
+
h5: fontSize => ({
|
|
92
|
+
//@ts-ignore
|
|
93
|
+
fontSize: fontSize || theme.fontSizes.sm,
|
|
94
|
+
}),
|
|
95
|
+
h6: fontSize => ({
|
|
96
|
+
//@ts-ignore
|
|
97
|
+
fontSize: fontSize || theme.fontSizes.xs,
|
|
98
|
+
}),
|
|
99
|
+
h7: fontSize => ({
|
|
100
|
+
//@ts-ignore
|
|
101
|
+
fontSize: fontSize || theme.fontSizes.xs,
|
|
102
|
+
}),
|
|
103
|
+
h8: fontSize => ({
|
|
104
|
+
//@ts-ignore
|
|
105
|
+
fontSize: fontSize || theme.fontSizes.xxs,
|
|
106
|
+
}),
|
|
107
|
+
h9: fontSize => ({
|
|
108
|
+
//@ts-ignore
|
|
109
|
+
fontSize: fontSize || theme.fontSizes.xxs,
|
|
110
|
+
}),
|
|
111
|
+
body: fontSize => ({
|
|
112
|
+
//@ts-ignore
|
|
113
|
+
fontSize: fontSize || theme.fontSizes.md,
|
|
114
|
+
}),
|
|
115
|
+
}))
|
|
116
|
+
|
|
117
|
+
const GradientText = withUnistyles(BaseGradientText, theme => ({
|
|
118
|
+
colors: theme.colors,
|
|
119
|
+
}))
|
|
120
|
+
|
|
121
|
+
export default GradientText
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { IconWrapperProps, ThemedIcon } from '../components/IconWrapper';
|
|
3
|
+
|
|
4
|
+
const IconName = ({color, ...props}: Omit<IconWrapperProps, 'children' | 'colors'>) => {
|
|
5
|
+
return (
|
|
6
|
+
<ThemedIcon {...props} color={color}>
|
|
7
|
+
<>
|
|
8
|
+
{/* Icon content */}
|
|
9
|
+
</>
|
|
10
|
+
</ThemedIcon>
|
|
11
|
+
);
|
|
12
|
+
};
|
|
13
|
+
export default IconName;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
Fragment,
|
|
5
|
+
isValidElement,
|
|
6
|
+
ReactElement,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
} from 'react'
|
|
9
|
+
import Svg from 'react-native-svg'
|
|
10
|
+
import {View} from 'react-native'
|
|
11
|
+
import {withUnistyles} from 'react-native-unistyles'
|
|
12
|
+
import {IconTokens} from '../theme/IconWrapper.recipe'
|
|
13
|
+
import {ThemeColors} from '../style/types'
|
|
14
|
+
|
|
15
|
+
interface SVGChildProps {
|
|
16
|
+
color?: string
|
|
17
|
+
}
|
|
18
|
+
export type IconWrapperProps = {
|
|
19
|
+
size?: keyof typeof IconTokens.variants.size
|
|
20
|
+
colorPalette?: keyof typeof IconTokens.variants.colorPalette
|
|
21
|
+
children?: ReactElement<SVGChildProps>
|
|
22
|
+
scale?: number
|
|
23
|
+
color?: ThemeColors
|
|
24
|
+
rotation?: number
|
|
25
|
+
colors?: any
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param name string key icon name
|
|
30
|
+
* @param scale optional number scale icon size
|
|
31
|
+
* @param color optional ThemeColor color
|
|
32
|
+
* @param rotate optional number rotation of the icon
|
|
33
|
+
* @returns Icon react component
|
|
34
|
+
*/
|
|
35
|
+
const Icon = ({
|
|
36
|
+
size = IconTokens.defaultProps.size,
|
|
37
|
+
colorPalette = IconTokens.defaultProps.colorPalette,
|
|
38
|
+
children,
|
|
39
|
+
scale = IconTokens.defaultProps.scale,
|
|
40
|
+
color,
|
|
41
|
+
rotation,
|
|
42
|
+
colors,
|
|
43
|
+
...rest
|
|
44
|
+
}: IconWrapperProps) => {
|
|
45
|
+
const colorPaletteKey = IconTokens.variants.colorPalette[colorPalette]
|
|
46
|
+
const colorScheme =
|
|
47
|
+
colorPaletteKey.color in colors
|
|
48
|
+
? colors[colorPaletteKey.color]
|
|
49
|
+
: colorPaletteKey.color
|
|
50
|
+
const resolvedColor = color
|
|
51
|
+
? color in colors
|
|
52
|
+
? colors[color]
|
|
53
|
+
: color
|
|
54
|
+
: colorScheme
|
|
55
|
+
|
|
56
|
+
const width = IconTokens.variants.size[size].width ?? 0
|
|
57
|
+
const height = IconTokens.variants.size[size].height ?? 0
|
|
58
|
+
const viewBoxWidth = IconTokens.variants.size[size].viewBoxWidth ?? 0
|
|
59
|
+
const viewBoxHeight = IconTokens.variants.size[size].viewBoxHeight ?? 0
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<View
|
|
63
|
+
style={{
|
|
64
|
+
width: scale * width,
|
|
65
|
+
height: scale * height,
|
|
66
|
+
transform: rotation ? [{rotate: `${rotation}deg`}] : [],
|
|
67
|
+
}}>
|
|
68
|
+
<Svg
|
|
69
|
+
width={scale * width}
|
|
70
|
+
height={scale * height}
|
|
71
|
+
viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
|
|
72
|
+
fill="none"
|
|
73
|
+
{...rest}>
|
|
74
|
+
{Children.map(children, child => {
|
|
75
|
+
if (isFragmentElement(child)) {
|
|
76
|
+
return cloneElement(
|
|
77
|
+
child,
|
|
78
|
+
{},
|
|
79
|
+
Children.map(child.props.children, pathChild => {
|
|
80
|
+
if (isValidElement(pathChild)) {
|
|
81
|
+
return cloneElement(
|
|
82
|
+
pathChild as React.ReactElement<{stroke?: string}>,
|
|
83
|
+
{
|
|
84
|
+
stroke: resolvedColor ?? colorScheme,
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
return pathChild
|
|
89
|
+
}),
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
return child
|
|
93
|
+
})}
|
|
94
|
+
</Svg>
|
|
95
|
+
</View>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default Icon
|
|
100
|
+
|
|
101
|
+
export const ThemedIcon = withUnistyles(Icon, (theme, rt) => ({
|
|
102
|
+
colors: theme.colors,
|
|
103
|
+
}))
|
|
104
|
+
|
|
105
|
+
function isFragmentElement(
|
|
106
|
+
node: ReactNode,
|
|
107
|
+
): node is React.ReactElement<{children?: ReactNode}> {
|
|
108
|
+
return isValidElement(node) && node.type === Fragment
|
|
109
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type InputModeOptions,
|
|
3
|
+
type KeyboardTypeOptions,
|
|
4
|
+
type StyleProp,
|
|
5
|
+
TextInput,
|
|
6
|
+
TextStyle,
|
|
7
|
+
View,
|
|
8
|
+
type ViewStyle,
|
|
9
|
+
} from 'react-native'
|
|
10
|
+
// import Text from './Text';
|
|
11
|
+
import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
|
|
12
|
+
// import Text from './Text';
|
|
13
|
+
import {InputTokens, InputStyles} from '../theme/Input.recipe'
|
|
14
|
+
import Text from './Text'
|
|
15
|
+
|
|
16
|
+
type InputVariants = UnistylesVariants<typeof InputStyles>
|
|
17
|
+
|
|
18
|
+
type InputProps = InputVariants & {
|
|
19
|
+
label?: string
|
|
20
|
+
onChange?: (value: string) => void
|
|
21
|
+
placeholder: string
|
|
22
|
+
inputMode?: InputModeOptions
|
|
23
|
+
keyboardType?: KeyboardTypeOptions
|
|
24
|
+
flex?: number
|
|
25
|
+
maxWidth?: number | string
|
|
26
|
+
password?: boolean
|
|
27
|
+
onFocus?: () => void
|
|
28
|
+
value: any
|
|
29
|
+
containerMixins?: StyleProp<ViewStyle> | StyleProp<ViewStyle>[]
|
|
30
|
+
labelMixins?:
|
|
31
|
+
| StyleProp<ViewStyle>
|
|
32
|
+
| StyleProp<ViewStyle>[]
|
|
33
|
+
| StyleProp<TextStyle>
|
|
34
|
+
| StyleProp<TextStyle>[]
|
|
35
|
+
inputMixins?: StyleProp<ViewStyle> | StyleProp<ViewStyle>[]
|
|
36
|
+
// containerStyle?: StyleProp<ViewStyle>;
|
|
37
|
+
// labelStyle?: StyleProp<ViewStyle>;
|
|
38
|
+
// inputStyle?: StyleProp<ViewStyle>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const Input = ({
|
|
42
|
+
colorPalette = InputTokens.defaultProps.colorPalette,
|
|
43
|
+
size = InputTokens.defaultProps.size,
|
|
44
|
+
spacing = InputTokens.defaultProps.spacing,
|
|
45
|
+
label,
|
|
46
|
+
placeholder,
|
|
47
|
+
onChange,
|
|
48
|
+
inputMode,
|
|
49
|
+
keyboardType,
|
|
50
|
+
flex = 1,
|
|
51
|
+
maxWidth = '100%',
|
|
52
|
+
password = false,
|
|
53
|
+
onFocus = () => {},
|
|
54
|
+
value,
|
|
55
|
+
containerMixins,
|
|
56
|
+
labelMixins,
|
|
57
|
+
inputMixins,
|
|
58
|
+
}: // containerStyle,
|
|
59
|
+
// labelStyle,
|
|
60
|
+
// inputStyle,
|
|
61
|
+
InputProps) => {
|
|
62
|
+
InputStyles.useVariants({
|
|
63
|
+
colorPalette,
|
|
64
|
+
size,
|
|
65
|
+
spacing,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<View
|
|
70
|
+
style={[
|
|
71
|
+
styles.container(flex, maxWidth),
|
|
72
|
+
// containerStyle && styles.customStyle(containerStyle),
|
|
73
|
+
containerMixins && containerMixins,
|
|
74
|
+
]}>
|
|
75
|
+
{label && (
|
|
76
|
+
<Text
|
|
77
|
+
as="h5"
|
|
78
|
+
style={
|
|
79
|
+
[
|
|
80
|
+
// styles.label,
|
|
81
|
+
InputStyles.label,
|
|
82
|
+
// labelStyle && styles.customStyle(labelStyle),
|
|
83
|
+
labelMixins && labelMixins,
|
|
84
|
+
] as any
|
|
85
|
+
}>
|
|
86
|
+
{label}
|
|
87
|
+
</Text>
|
|
88
|
+
)}
|
|
89
|
+
<TextInput
|
|
90
|
+
style={[
|
|
91
|
+
// styles.input,
|
|
92
|
+
InputStyles.input,
|
|
93
|
+
// inputStyle && styles.customStyle(inputStyle),
|
|
94
|
+
inputMixins && inputMixins,
|
|
95
|
+
]}
|
|
96
|
+
value={value}
|
|
97
|
+
placeholder={placeholder}
|
|
98
|
+
inputMode={inputMode}
|
|
99
|
+
keyboardType={keyboardType}
|
|
100
|
+
secureTextEntry={password}
|
|
101
|
+
onFocus={onFocus}
|
|
102
|
+
onChangeText={onChange}
|
|
103
|
+
/>
|
|
104
|
+
</View>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const styles = StyleSheet.create({
|
|
109
|
+
container: (flex, maxWidth) => ({
|
|
110
|
+
flex,
|
|
111
|
+
width: '100%',
|
|
112
|
+
maxWidth,
|
|
113
|
+
gap: 5,
|
|
114
|
+
}),
|
|
115
|
+
// customStyle: style => ({
|
|
116
|
+
// ...style,
|
|
117
|
+
// }),
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
export default Input
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Alert,
|
|
3
|
+
Linking,
|
|
4
|
+
TextStyle,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
type StyleProp,
|
|
7
|
+
type ViewStyle,
|
|
8
|
+
} from 'react-native'
|
|
9
|
+
import Text from './Text'
|
|
10
|
+
import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
|
|
11
|
+
import LinkStyles from '../theme/Link.recipe'
|
|
12
|
+
import {TextSemanticSizes} from '../style/types'
|
|
13
|
+
type LinkVariants = UnistylesVariants<typeof LinkStyles>
|
|
14
|
+
|
|
15
|
+
type LinkProps = LinkVariants & {
|
|
16
|
+
text: string
|
|
17
|
+
url: string
|
|
18
|
+
underline?: boolean
|
|
19
|
+
as?: TextSemanticSizes
|
|
20
|
+
fontSize?: number
|
|
21
|
+
color?: string
|
|
22
|
+
style?: StyleProp<ViewStyle>
|
|
23
|
+
mixins?:
|
|
24
|
+
| StyleProp<ViewStyle>
|
|
25
|
+
| StyleProp<ViewStyle>[]
|
|
26
|
+
| StyleProp<TextStyle>
|
|
27
|
+
| StyleProp<TextStyle>[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const Link = ({
|
|
31
|
+
colorPalette,
|
|
32
|
+
size,
|
|
33
|
+
text,
|
|
34
|
+
url,
|
|
35
|
+
underline,
|
|
36
|
+
as,
|
|
37
|
+
fontSize,
|
|
38
|
+
color,
|
|
39
|
+
mixins,
|
|
40
|
+
}: LinkProps) => {
|
|
41
|
+
LinkStyles.useVariants({
|
|
42
|
+
colorPalette,
|
|
43
|
+
size,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<TouchableOpacity
|
|
48
|
+
onPress={async () => {
|
|
49
|
+
try {
|
|
50
|
+
await Linking.openURL(url)
|
|
51
|
+
} catch {
|
|
52
|
+
Alert.alert('No se pudo abrir este enlace')
|
|
53
|
+
}
|
|
54
|
+
}}>
|
|
55
|
+
<Text
|
|
56
|
+
as={as}
|
|
57
|
+
fontSize={fontSize}
|
|
58
|
+
// color={color}
|
|
59
|
+
style={
|
|
60
|
+
[
|
|
61
|
+
styles.link(
|
|
62
|
+
underline ? 'underline' : 'none',
|
|
63
|
+
// linkTokens.variants,
|
|
64
|
+
// linkTokens.customVariants
|
|
65
|
+
),
|
|
66
|
+
LinkStyles.link,
|
|
67
|
+
// style && styles.customStyle(style),
|
|
68
|
+
color && {color},
|
|
69
|
+
mixins && mixins,
|
|
70
|
+
] as any
|
|
71
|
+
}>
|
|
72
|
+
{text}
|
|
73
|
+
</Text>
|
|
74
|
+
</TouchableOpacity>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const styles = StyleSheet.create({
|
|
79
|
+
link: (underline): any => ({
|
|
80
|
+
textDecorationLine: underline,
|
|
81
|
+
}),
|
|
82
|
+
// customStyle: style => ({
|
|
83
|
+
// ...style,
|
|
84
|
+
// }),
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
export default Link
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {TouchableOpacity, TouchableWithoutFeedback, View} from 'react-native'
|
|
2
|
+
import Animated, {FadeIn, FadeOut, Keyframe} from 'react-native-reanimated'
|
|
3
|
+
import {StyleSheet, UnistylesVariants} from 'react-native-unistyles'
|
|
4
|
+
import Text from './Text'
|
|
5
|
+
import Svg, {Path} from 'react-native-svg'
|
|
6
|
+
import {ModalStyles, ModalTokens} from '../theme/Modal.recipe'
|
|
7
|
+
|
|
8
|
+
type ModalVariants = UnistylesVariants<typeof ModalStyles>
|
|
9
|
+
|
|
10
|
+
type ModalProps = ModalVariants & {
|
|
11
|
+
isOpen: boolean
|
|
12
|
+
setIsOpen: (isOpen: boolean) => void
|
|
13
|
+
children: React.ReactNode
|
|
14
|
+
heading?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Define animations outside of the component to avoid re-creation on each render
|
|
18
|
+
const enteringModalContent = new Keyframe({
|
|
19
|
+
0: {opacity: 0, transform: [{scale: 0.8}]},
|
|
20
|
+
20: {opacity: 0.5, transform: [{scale: 0.9}]},
|
|
21
|
+
100: {opacity: 1, transform: [{scale: 1}]},
|
|
22
|
+
}).duration(300)
|
|
23
|
+
|
|
24
|
+
const exitingModalContent = new Keyframe({
|
|
25
|
+
0: {opacity: 1, transform: [{scale: 1}]},
|
|
26
|
+
100: {opacity: 0, transform: [{scale: 0.8}]},
|
|
27
|
+
}).duration(200)
|
|
28
|
+
|
|
29
|
+
const Modal = ({
|
|
30
|
+
isOpen,
|
|
31
|
+
setIsOpen,
|
|
32
|
+
heading,
|
|
33
|
+
children,
|
|
34
|
+
colorPalette = ModalTokens.defaultProps.colorPalette,
|
|
35
|
+
}: ModalProps) => {
|
|
36
|
+
// const tokens = useTokens('modal')();
|
|
37
|
+
if (!isOpen) return null
|
|
38
|
+
|
|
39
|
+
// const resolvedColorScheme =
|
|
40
|
+
// colorScheme ??
|
|
41
|
+
// (tokens.defaultProps.colorScheme as keyof ModalColorSchemeVariants);
|
|
42
|
+
|
|
43
|
+
ModalStyles.useVariants({
|
|
44
|
+
colorPalette,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Animated.View
|
|
49
|
+
style={styles.overlay}
|
|
50
|
+
entering={FadeIn.duration(200)}
|
|
51
|
+
exiting={FadeOut.duration(250)}>
|
|
52
|
+
<TouchableWithoutFeedback onPress={() => setIsOpen(false)}>
|
|
53
|
+
<View style={StyleSheet.absoluteFillObject} />
|
|
54
|
+
</TouchableWithoutFeedback>
|
|
55
|
+
<Animated.View
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
style={[styles.modalBox(), ModalStyles.container]}
|
|
58
|
+
entering={enteringModalContent}
|
|
59
|
+
exiting={exitingModalContent}>
|
|
60
|
+
<View style={styles.header(!heading)}>
|
|
61
|
+
<Text style={styles.headerTitle}>{!!heading && heading}</Text>
|
|
62
|
+
<View
|
|
63
|
+
style={{
|
|
64
|
+
position: 'absolute',
|
|
65
|
+
right: 0,
|
|
66
|
+
top: 0,
|
|
67
|
+
}}>
|
|
68
|
+
<CloseButton onClose={() => setIsOpen(false)} />
|
|
69
|
+
</View>
|
|
70
|
+
</View>
|
|
71
|
+
<View style={styles.content}>{children}</View>
|
|
72
|
+
</Animated.View>
|
|
73
|
+
</Animated.View>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// type ModalTokenType = ReturnType<Tokens['modal']>;
|
|
78
|
+
// type VariantsType = ModalTokenType['variants'];
|
|
79
|
+
|
|
80
|
+
const styles = StyleSheet.create(theme => {
|
|
81
|
+
return {
|
|
82
|
+
overlay: {
|
|
83
|
+
...StyleSheet.absoluteFillObject,
|
|
84
|
+
backgroundColor: 'black',
|
|
85
|
+
zIndex: 1000,
|
|
86
|
+
justifyContent: 'center',
|
|
87
|
+
alignItems: 'center',
|
|
88
|
+
},
|
|
89
|
+
modalBox: () => ({
|
|
90
|
+
width: '80%',
|
|
91
|
+
justifyContent: 'center',
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
padding: 20,
|
|
94
|
+
borderRadius: 10,
|
|
95
|
+
// backgroundColor: theme.colors.background,
|
|
96
|
+
// boxShadow: '0px 0px 50px rgba(250, 250, 250, 0.6)',
|
|
97
|
+
// variants: {
|
|
98
|
+
// colorScheme: variants.colorScheme as any,
|
|
99
|
+
// },
|
|
100
|
+
}),
|
|
101
|
+
header: padding => ({
|
|
102
|
+
flexDirection: 'row',
|
|
103
|
+
justifyContent: 'space-between',
|
|
104
|
+
alignItems: 'center',
|
|
105
|
+
width: '100%',
|
|
106
|
+
marginBottom: 10,
|
|
107
|
+
padding: padding && 10,
|
|
108
|
+
}),
|
|
109
|
+
headerTitle: {
|
|
110
|
+
textAlign: 'center',
|
|
111
|
+
flex: 1,
|
|
112
|
+
},
|
|
113
|
+
closeButton: {
|
|
114
|
+
color: 'white',
|
|
115
|
+
},
|
|
116
|
+
content: {
|
|
117
|
+
width: '100%',
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
export default Modal
|
|
123
|
+
|
|
124
|
+
export interface CloseButtonProps {
|
|
125
|
+
scale?: number
|
|
126
|
+
color?: undefined
|
|
127
|
+
onClose: () => void
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const defaultColor = 'white'
|
|
131
|
+
|
|
132
|
+
const CloseButton = ({
|
|
133
|
+
onClose,
|
|
134
|
+
scale = 1,
|
|
135
|
+
color,
|
|
136
|
+
...rest
|
|
137
|
+
}: CloseButtonProps) => (
|
|
138
|
+
<TouchableOpacity onPress={onClose}>
|
|
139
|
+
<Svg
|
|
140
|
+
// TODO: fix types
|
|
141
|
+
//@ts-ignore
|
|
142
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
143
|
+
width={scale * 24}
|
|
144
|
+
height={scale * 24}
|
|
145
|
+
viewBox={`0 0 ${24} ${24}`}
|
|
146
|
+
fill="none"
|
|
147
|
+
{...rest}>
|
|
148
|
+
<Path
|
|
149
|
+
stroke={color || defaultColor}
|
|
150
|
+
strokeLinecap="round"
|
|
151
|
+
strokeLinejoin="round"
|
|
152
|
+
strokeWidth={1.5}
|
|
153
|
+
d="m7.757 7.757 8.486 8.486M7.757 16.243l8.486-8.486"
|
|
154
|
+
/>
|
|
155
|
+
</Svg>
|
|
156
|
+
</TouchableOpacity>
|
|
157
|
+
)
|