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    InterBlack: { fontFamily: 'Inter-Black' },
121    InterBlackItalic: { fontFamily: 'Inter-BlackItalic' },
122    InterBold: { fontFamily: 'Inter-Bold' },
123    InterBoldItalic: { fontFamily: 'Inter-BoldItalic' },
124    InterExtraBold: { fontFamily: 'Inter-ExtraBold' },
125    InterExtraBoldItalic: { fontFamily: 'Inter-ExtraBoldItalic' },
126    InterExtraLight: { fontFamily: 'Inter-ExtraLight' },
127    InterExtraLightItalic: { fontFamily: 'Inter-ExtraLightItalic' },
128    InterRegular: { fontFamily: 'Inter-Regular' },
129    InterItalic: { fontFamily: 'Inter-Italic' },
130    InterLight: { fontFamily: 'Inter-Light' },
131    InterLightItalic: { fontFamily: 'Inter-LightItalic' },
132    InterMedium: { fontFamily: 'Inter-Medium' },
133    InterMediumItalic: { fontFamily: 'Inter-MediumItalic' },
134    InterSemiBold: { fontFamily: 'Inter-SemiBold' },
135    InterSemiBoldItalic: { fontFamily: 'Inter-SemiBoldItalic' },
136    InterThin: { fontFamily: 'Inter-Thin' },
137    InterThinItalic: { fontFamily: 'Inter-ThinItalic' },
138  },
139
140  weight: {
141    thin: { fontWeight: '100' as TextStyle['fontWeight'] },
142    extralight: { fontWeight: '200' as TextStyle['fontWeight'] },
143    light: { fontWeight: '300' as TextStyle['fontWeight'] },
144    normal: { fontWeight: '400' as TextStyle['fontWeight'] },
145    medium: { fontWeight: '500' as TextStyle['fontWeight'] },
146    semibold: { fontWeight: '600' as TextStyle['fontWeight'] },
147    bold: { fontWeight: '700' as TextStyle['fontWeight'] },
148    extrabold: { fontWeight: '800' as TextStyle['fontWeight'] },
149    black: { fontWeight: '900' as TextStyle['fontWeight'] },
150  },
151
152  color: {
153    default: { color: lightTheme.text.default },
154    error: { color: lightTheme.text.error },
155    warning: { color: lightTheme.text.warning },
156    success: { color: lightTheme.text.success },
157    secondary: { color: lightTheme.text.secondary },
158    primary: { color: lightTheme.button.primary.background },
159    link: { color: lightTheme.link.default },
160  },
161};
162
163export const textDark = {
164  base: {
165    color: darkTheme.text.default,
166  },
167
168  color: {
169    default: { color: darkTheme.text.default },
170    error: { color: darkTheme.text.error },
171    warning: { color: darkTheme.text.warning },
172    success: { color: darkTheme.text.success },
173    secondary: { color: darkTheme.text.secondary },
174    primary: { color: darkTheme.button.primary.background },
175    link: { color: darkTheme.link.default },
176  },
177};
178
179export const bg = {
180  none: { backgroundColor: 'transparent' },
181  default: { backgroundColor: lightTheme.background.default },
182  secondary: { backgroundColor: lightTheme.background.secondary },
183  overlay: { backgroundColor: lightTheme.background.overlay },
184  success: { backgroundColor: lightTheme.background.success },
185  warning: { backgroundColor: lightTheme.background.warning },
186  error: { backgroundColor: lightTheme.background.error },
187};
188
189export const bgDark = {
190  default: { backgroundColor: darkTheme.background.default },
191  secondary: { backgroundColor: darkTheme.background.secondary },
192  overlay: { backgroundColor: darkTheme.background.overlay },
193  success: { backgroundColor: darkTheme.background.success },
194  warning: { backgroundColor: darkTheme.background.warning },
195  error: { backgroundColor: darkTheme.background.error },
196};
197
198type NavigationTheme = {
199  dark: boolean;
200  colors: {
201    primary: string;
202    background: string;
203    card: string;
204    text: string;
205    border: string;
206    notification: string;
207  };
208};
209
210export const lightNavigationTheme: NavigationTheme = {
211  dark: false,
212  colors: {
213    primary: lightTheme.button.primary.background,
214    background: lightTheme.background.screen,
215    card: lightTheme.background.default,
216    text: lightTheme.text.default,
217    border: lightTheme.border.default,
218    notification: lightTheme.highlight.accent,
219  },
220};
221
222export const darkNavigationTheme: NavigationTheme = {
223  dark: true,
224  colors: {
225    primary: darkTheme.link.default,
226    background: darkTheme.background.screen,
227    card: darkTheme.background.screen,
228    text: darkTheme.text.default,
229    border: darkTheme.border.default,
230    notification: darkTheme.highlight.accent,
231  },
232};
233