1import { spacing, lightTheme, darkTheme, borderRadius } from '@expo/styleguide-native';
2import { TextStyle, Platform } from 'react-native';
3
4type SpacingKey = `${keyof typeof spacing}`;
5type DescriptiveScale = 'micro' | 'tiny' | 'small' | 'medium' | 'large' | 'xl';
6type Scale = Record<SpacingKey | DescriptiveScale, number>;
7
8export const scale: Scale = {
9  micro: spacing[0.5],
10  tiny: spacing[1],
11  small: spacing[3],
12  medium: spacing[4],
13  large: spacing[6],
14  xl: spacing[8],
15  ...spacing,
16};
17
18function fullSpacingScaleForAttributes(attributes: string[]) {
19  const obj = {};
20
21  Object.keys(scale).forEach((key) => {
22    key = `${key}`;
23    const value = {};
24
25    attributes.forEach((attribute) => {
26      value[attribute] = scale[key];
27    });
28
29    obj[key] = value;
30  });
31
32  return obj as Record<SpacingKey | DescriptiveScale, any>;
33}
34
35export const padding = {
36  padding: fullSpacingScaleForAttributes(['padding']),
37  px: fullSpacingScaleForAttributes(['paddingHorizontal']),
38  py: fullSpacingScaleForAttributes(['paddingVertical']),
39  pb: fullSpacingScaleForAttributes(['paddingBottom']),
40  pt: fullSpacingScaleForAttributes(['paddingTop']),
41};
42
43export const margin = {
44  margin: fullSpacingScaleForAttributes(['margin']),
45  mx: fullSpacingScaleForAttributes(['marginHorizontal']),
46  my: fullSpacingScaleForAttributes(['marginVertical']),
47  mb: fullSpacingScaleForAttributes(['marginBottom']),
48  mt: fullSpacingScaleForAttributes(['marginTop']),
49};
50
51export const width = fullSpacingScaleForAttributes(['width']);
52export const height = fullSpacingScaleForAttributes(['height']);
53
54export const rounded = {
55  rounded: {
56    none: { borderRadius: 0 },
57    small: { borderRadius: borderRadius.small },
58    medium: { borderRadius: borderRadius.medium },
59    large: { borderRadius: borderRadius.large },
60    full: { borderRadius: 99999 },
61  },
62
63  roundedTop: {
64    none: { borderTopLeftRadius: 0, borderTopRightRadius: 0 },
65    small: { borderTopLeftRadius: borderRadius.small, borderTopRightRadius: borderRadius.small },
66    medium: {
67      borderTopLeftRadius: borderRadius.medium,
68      borderTopRightRadius: borderRadius.medium,
69    },
70    large: { borderTopLeftRadius: borderRadius.large, borderTopRightRadius: borderRadius.large },
71    full: { borderTopLeftRadius: 9999, borderTopRightRadius: 9999 },
72  },
73
74  roundedBottom: {
75    none: { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 },
76    small: {
77      borderBottomLeftRadius: borderRadius.small,
78      borderBottomRightRadius: borderRadius.small,
79    },
80    medium: {
81      borderBottomLeftRadius: borderRadius.medium,
82      borderBottomRightRadius: borderRadius.medium,
83    },
84    large: {
85      borderBottomLeftRadius: borderRadius.large,
86      borderBottomRightRadius: borderRadius.large,
87    },
88    full: { borderBottomLeftRadius: 9999, borderBottomRightRadius: 9999 },
89  },
90};
91
92export const text = {
93  align: {
94    center: { textAlign: 'center' as TextStyle['textAlign'] },
95  },
96
97  size: {
98    small: {
99      fontSize: 12,
100      lineHeight: 14,
101    },
102    medium: {
103      fontSize: 16,
104      lineHeight: 18,
105    },
106    large: {
107      fontSize: 18,
108      lineHeight: 24,
109    },
110  },
111
112  leading: {
113    large: { lineHeight: 18 },
114  },
115
116  type: {
117    mono: {
118      fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
119    },
120  },
121
122  weight: {
123    thin: { fontWeight: '100' as TextStyle['fontWeight'] },
124    extralight: { fontWeight: '200' as TextStyle['fontWeight'] },
125    light: { fontWeight: '300' as TextStyle['fontWeight'] },
126    normal: { fontWeight: '400' as TextStyle['fontWeight'] },
127    medium: { fontWeight: '500' as TextStyle['fontWeight'] },
128    semibold: { fontWeight: '600' as TextStyle['fontWeight'] },
129    bold: { fontWeight: '700' as TextStyle['fontWeight'] },
130    extrabold: { fontWeight: '800' as TextStyle['fontWeight'] },
131    black: { fontWeight: '900' as TextStyle['fontWeight'] },
132  },
133
134  color: {
135    default: { color: lightTheme.text.default },
136    error: { color: lightTheme.text.error },
137    warning: { color: lightTheme.text.warning },
138    success: { color: lightTheme.text.success },
139    secondary: { color: lightTheme.text.secondary },
140    primary: { color: lightTheme.button.primary.background },
141    link: { color: lightTheme.link.default },
142  },
143};
144
145export const textDark = {
146  base: {
147    color: darkTheme.text.default,
148  },
149
150  color: {
151    default: { color: darkTheme.text.default },
152    error: { color: darkTheme.text.error },
153    warning: { color: darkTheme.text.warning },
154    success: { color: darkTheme.text.success },
155    secondary: { color: darkTheme.text.secondary },
156    primary: { color: darkTheme.button.primary.background },
157    link: { color: darkTheme.link.default },
158  },
159};
160
161export const bg = {
162  none: { backgroundColor: 'transparent' },
163  default: { backgroundColor: lightTheme.background.default },
164  secondary: { backgroundColor: lightTheme.background.secondary },
165  overlay: { backgroundColor: lightTheme.background.overlay },
166  success: { backgroundColor: lightTheme.background.success },
167  warning: { backgroundColor: lightTheme.background.warning },
168  error: { backgroundColor: lightTheme.background.error },
169};
170
171export const bgDark = {
172  default: { backgroundColor: darkTheme.background.default },
173  secondary: { backgroundColor: darkTheme.background.secondary },
174  overlay: { backgroundColor: darkTheme.background.overlay },
175  success: { backgroundColor: darkTheme.background.success },
176  warning: { backgroundColor: darkTheme.background.warning },
177  error: { backgroundColor: darkTheme.background.error },
178};
179
180type NavigationTheme = {
181  dark: boolean;
182  colors: {
183    primary: string;
184    background: string;
185    card: string;
186    text: string;
187    border: string;
188    notification: string;
189  };
190};
191
192export const lightNavigationTheme: NavigationTheme = {
193  dark: false,
194  colors: {
195    primary: lightTheme.button.primary.background,
196    background: lightTheme.background.secondary,
197    card: lightTheme.background.default,
198    text: lightTheme.text.default,
199    border: lightTheme.border.default,
200    notification: lightTheme.highlight.accent,
201  },
202};
203
204export const darkNavigationTheme: NavigationTheme = {
205  dark: true,
206  colors: {
207    primary: darkTheme.link.default,
208    background: darkTheme.background.default,
209    card: darkTheme.background.secondary,
210    text: darkTheme.text.default,
211    border: darkTheme.border.default,
212    notification: darkTheme.highlight.accent,
213  },
214};
215