@oneplatformdev/react-native-uikit 0.0.0-stage → 1.1.0
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 +376 -2
- package/bin/cli.cjs +372 -0
- package/package.json +34 -4
- package/registry/manifest.json +113 -0
- package/src/components/BottomModal/index.ts +2 -0
- package/src/components/BottomModal/presenters/useBottomModal.ts +114 -0
- package/src/components/BottomModal/presenters/useBottomModalInsets.ts +19 -0
- package/src/components/BottomModal/types/types.ts +23 -0
- package/src/components/BottomModal/ui/BottomModal.tsx +110 -0
- package/src/components/BottomModal/ui/styles.ts +115 -0
- package/src/components/Button/index.ts +8 -0
- package/src/components/Button/presenters/useButton.ts +72 -0
- package/src/components/Button/types/types.ts +39 -0
- package/src/components/Button/ui/Button.tsx +121 -0
- package/src/components/Button/ui/styles.ts +82 -0
- package/src/components/ConnectionContainer/index.ts +2 -0
- package/src/components/ConnectionContainer/presenters/useConnectionContainer.ts +77 -0
- package/src/components/ConnectionContainer/types/types.ts +14 -0
- package/src/components/ConnectionContainer/ui/ConnectionContainer.tsx +51 -0
- package/src/components/ConnectionContainer/ui/styles.ts +35 -0
- package/src/components/CustomAlert/index.ts +2 -0
- package/src/components/CustomAlert/presenters/useCustomAlert.ts +24 -0
- package/src/components/CustomAlert/types/types.ts +20 -0
- package/src/components/CustomAlert/ui/CustomAlert.tsx +77 -0
- package/src/components/CustomAlert/ui/styles.ts +71 -0
- package/src/components/HeaderWithBackButton/index.ts +2 -0
- package/src/components/HeaderWithBackButton/presenters/useHeaderWithBackButton.ts +17 -0
- package/src/components/HeaderWithBackButton/types/types.ts +21 -0
- package/src/components/HeaderWithBackButton/ui/HeaderWithBackButton.tsx +90 -0
- package/src/components/HeaderWithBackButton/ui/styles.ts +58 -0
- package/src/components/Input/index.ts +8 -0
- package/src/components/Input/presenters/useInput.ts +104 -0
- package/src/components/Input/types/types.ts +36 -0
- package/src/components/Input/ui/Input.tsx +161 -0
- package/src/components/Input/ui/styles.ts +80 -0
- package/src/components/Loader/index.ts +2 -0
- package/src/components/Loader/types/types.ts +12 -0
- package/src/components/Loader/ui/Loader.tsx +29 -0
- package/src/components/Loader/ui/styles.ts +14 -0
- package/src/components/Logger/index.ts +2 -0
- package/src/components/Logger/presenters/useLogger.ts +13 -0
- package/src/components/Logger/types/types.ts +56 -0
- package/src/components/Logger/ui/Logger.tsx +85 -0
- package/src/components/Logger/ui/components/LoggerItem.tsx +117 -0
- package/src/components/Logger/ui/styles.ts +121 -0
- package/src/components/Logger/utils/groupLoggerEntries.ts +40 -0
- package/src/components/Logger/utils/loggerPresentation.ts +69 -0
- package/src/components/ScreenContainer/index.ts +2 -0
- package/src/components/ScreenContainer/presenters/useScreenContainer.ts +12 -0
- package/src/components/ScreenContainer/types/types.ts +19 -0
- package/src/components/ScreenContainer/ui/ScreenContainer.tsx +83 -0
- package/src/components/ScreenContainer/ui/styles.ts +31 -0
- package/src/components/Typography/index.ts +2 -0
- package/src/components/Typography/types/types.ts +14 -0
- package/src/components/Typography/ui/Typography.tsx +37 -0
- package/src/components/Typography/ui/styles.ts +26 -0
- package/src/index.ts +13 -0
- package/src/provider/LocalizationContext.tsx +14 -0
- package/src/provider/ModeContext.tsx +9 -0
- package/src/provider/index.ts +12 -0
- package/src/provider/types.ts +31 -0
- package/src/theme/ThemeProvider.tsx +7 -0
- package/src/theme/UIProvider.tsx +60 -0
- package/src/theme/createTheme.ts +66 -0
- package/src/theme/defaultTheme.ts +215 -0
- package/src/theme/index.ts +4 -0
- package/src/theme/types.ts +265 -0
- package/src/utils/index.ts +94 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createDefaultButtonTheme, createDefaultInputTheme, defaultTheme } from './defaultTheme';
|
|
2
|
+
import type { UITheme, UIThemeOverride } from './types';
|
|
3
|
+
|
|
4
|
+
const isTokenObject = (value: unknown): value is Record<string, unknown> => {
|
|
5
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const mergeNestedTokens = (defaults: object, overrides: object | undefined): object => {
|
|
9
|
+
const defaultTokens = defaults as Record<string, unknown>;
|
|
10
|
+
const overrideTokens = (overrides ?? {}) as Record<string, unknown>;
|
|
11
|
+
const result: Record<string, unknown> = { ...defaultTokens };
|
|
12
|
+
|
|
13
|
+
Object.keys(overrideTokens).forEach(key => {
|
|
14
|
+
const defaultToken = defaultTokens[key];
|
|
15
|
+
const overrideToken = overrideTokens[key];
|
|
16
|
+
|
|
17
|
+
result[key] =
|
|
18
|
+
isTokenObject(defaultToken) && isTokenObject(overrideToken)
|
|
19
|
+
? { ...defaultToken, ...overrideToken }
|
|
20
|
+
: overrideToken;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const createTheme = (overrides: UIThemeOverride = {}): UITheme => {
|
|
27
|
+
const spacing = { ...defaultTheme.spacing, ...overrides.spacing };
|
|
28
|
+
const radius = { ...defaultTheme.radius, ...overrides.radius };
|
|
29
|
+
const buttonDefaults = createDefaultButtonTheme(spacing, radius);
|
|
30
|
+
const buttonOverrides = overrides.button;
|
|
31
|
+
const inputDefaults = createDefaultInputTheme(spacing, radius);
|
|
32
|
+
const theme = {
|
|
33
|
+
mode: overrides.mode ?? defaultTheme.mode,
|
|
34
|
+
colors: {
|
|
35
|
+
...defaultTheme.colors,
|
|
36
|
+
...overrides.colors,
|
|
37
|
+
},
|
|
38
|
+
fonts: mergeNestedTokens(defaultTheme.fonts, overrides.fonts),
|
|
39
|
+
spacing,
|
|
40
|
+
radius,
|
|
41
|
+
typography: mergeNestedTokens(defaultTheme.typography, overrides.typography),
|
|
42
|
+
button: {
|
|
43
|
+
variants: {
|
|
44
|
+
primary: { ...buttonDefaults.variants.primary, ...buttonOverrides?.variants?.primary },
|
|
45
|
+
secondary: { ...buttonDefaults.variants.secondary, ...buttonOverrides?.variants?.secondary },
|
|
46
|
+
outline: { ...buttonDefaults.variants.outline, ...buttonOverrides?.variants?.outline },
|
|
47
|
+
ghost: { ...buttonDefaults.variants.ghost, ...buttonOverrides?.variants?.ghost },
|
|
48
|
+
},
|
|
49
|
+
sizes: {
|
|
50
|
+
sm: { ...buttonDefaults.sizes.sm, ...buttonOverrides?.sizes?.sm },
|
|
51
|
+
md: { ...buttonDefaults.sizes.md, ...buttonOverrides?.sizes?.md },
|
|
52
|
+
lg: { ...buttonDefaults.sizes.lg, ...buttonOverrides?.sizes?.lg },
|
|
53
|
+
},
|
|
54
|
+
numberOfLines: buttonOverrides?.numberOfLines,
|
|
55
|
+
},
|
|
56
|
+
input: {
|
|
57
|
+
colors: { ...inputDefaults.colors, ...overrides.input?.colors },
|
|
58
|
+
geometry: { ...inputDefaults.geometry, ...overrides.input?.geometry },
|
|
59
|
+
typography: { ...inputDefaults.typography, ...overrides.input?.typography },
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Augmented token keys are compile-time declarations; this assertion bridges them
|
|
64
|
+
// to the dynamically merged runtime categories above.
|
|
65
|
+
return theme as UITheme;
|
|
66
|
+
};
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { DefaultUIRadius, DefaultUISpacing, DefaultUITheme, UIButtonTheme, UIInputTheme } from './types';
|
|
2
|
+
|
|
3
|
+
const defaultSpacing: DefaultUISpacing = {
|
|
4
|
+
xs: 4,
|
|
5
|
+
sm: 8,
|
|
6
|
+
md: 12,
|
|
7
|
+
lg: 16,
|
|
8
|
+
xl: 24,
|
|
9
|
+
xxl: 32,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const defaultRadius: DefaultUIRadius = {
|
|
13
|
+
sm: 6,
|
|
14
|
+
md: 10,
|
|
15
|
+
lg: 16,
|
|
16
|
+
full: 999,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const createDefaultButtonTheme = (
|
|
20
|
+
spacing: DefaultUISpacing,
|
|
21
|
+
radius: DefaultUIRadius,
|
|
22
|
+
): UIButtonTheme => ({
|
|
23
|
+
variants: {
|
|
24
|
+
primary: {
|
|
25
|
+
background: 'primary',
|
|
26
|
+
foreground: 'onPrimary',
|
|
27
|
+
border: 'primary',
|
|
28
|
+
disabledBackground: 'disabled',
|
|
29
|
+
disabledForeground: 'onDisabled',
|
|
30
|
+
disabledBorder: 'disabled',
|
|
31
|
+
},
|
|
32
|
+
secondary: {
|
|
33
|
+
background: 'surface',
|
|
34
|
+
foreground: 'text',
|
|
35
|
+
border: 'transparent',
|
|
36
|
+
disabledBackground: 'disabled',
|
|
37
|
+
disabledForeground: 'onDisabled',
|
|
38
|
+
disabledBorder: 'disabled',
|
|
39
|
+
},
|
|
40
|
+
outline: {
|
|
41
|
+
background: 'transparent',
|
|
42
|
+
foreground: 'primary',
|
|
43
|
+
border: 'primary',
|
|
44
|
+
disabledBackground: 'disabled',
|
|
45
|
+
disabledForeground: 'onDisabled',
|
|
46
|
+
disabledBorder: 'disabled',
|
|
47
|
+
},
|
|
48
|
+
ghost: {
|
|
49
|
+
background: 'transparent',
|
|
50
|
+
foreground: 'primary',
|
|
51
|
+
border: 'transparent',
|
|
52
|
+
disabledBackground: 'disabled',
|
|
53
|
+
disabledForeground: 'onDisabled',
|
|
54
|
+
disabledBorder: 'disabled',
|
|
55
|
+
borderWidth: 0,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
sizes: {
|
|
59
|
+
sm: {
|
|
60
|
+
minHeight: spacing.xxl,
|
|
61
|
+
paddingHorizontal: spacing.md,
|
|
62
|
+
paddingVertical: spacing.xs,
|
|
63
|
+
radius: radius.sm,
|
|
64
|
+
borderWidth: 1,
|
|
65
|
+
gap: spacing.xs,
|
|
66
|
+
labelVariant: 'label',
|
|
67
|
+
labelWeight: 'semiBold',
|
|
68
|
+
},
|
|
69
|
+
md: {
|
|
70
|
+
minHeight: spacing.xxl + spacing.md,
|
|
71
|
+
paddingHorizontal: spacing.lg,
|
|
72
|
+
paddingVertical: spacing.sm,
|
|
73
|
+
radius: radius.md,
|
|
74
|
+
borderWidth: 1,
|
|
75
|
+
gap: spacing.sm,
|
|
76
|
+
labelVariant: 'label',
|
|
77
|
+
labelWeight: 'semiBold',
|
|
78
|
+
},
|
|
79
|
+
lg: {
|
|
80
|
+
minHeight: spacing.xxl + spacing.xl,
|
|
81
|
+
paddingHorizontal: spacing.xl,
|
|
82
|
+
paddingVertical: spacing.md,
|
|
83
|
+
radius: radius.lg,
|
|
84
|
+
borderWidth: 1,
|
|
85
|
+
gap: spacing.md,
|
|
86
|
+
labelVariant: 'body',
|
|
87
|
+
labelWeight: 'semiBold',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export const createDefaultInputTheme = (
|
|
93
|
+
spacing: DefaultUISpacing,
|
|
94
|
+
radius: DefaultUIRadius,
|
|
95
|
+
): UIInputTheme => ({
|
|
96
|
+
colors: {
|
|
97
|
+
background: 'background',
|
|
98
|
+
border: 'border',
|
|
99
|
+
focusedBorder: 'primary',
|
|
100
|
+
errorBorder: 'error',
|
|
101
|
+
disabledBackground: 'disabled',
|
|
102
|
+
disabledBorder: 'disabled',
|
|
103
|
+
text: 'text',
|
|
104
|
+
disabledText: 'onDisabled',
|
|
105
|
+
placeholder: 'textMuted',
|
|
106
|
+
label: 'textMuted',
|
|
107
|
+
helper: 'textMuted',
|
|
108
|
+
error: 'error',
|
|
109
|
+
},
|
|
110
|
+
geometry: {
|
|
111
|
+
marginBottom: 0,
|
|
112
|
+
minHeight: 48,
|
|
113
|
+
textMinHeight: 46,
|
|
114
|
+
paddingHorizontal: spacing.md,
|
|
115
|
+
borderWidth: 1,
|
|
116
|
+
radius: radius.md,
|
|
117
|
+
labelGap: spacing.xs,
|
|
118
|
+
supportingGap: spacing.xs,
|
|
119
|
+
startAccessoryGap: spacing.sm,
|
|
120
|
+
endAccessoryGap: 0,
|
|
121
|
+
passwordToggleGap: spacing.sm,
|
|
122
|
+
multilinePaddingVertical: spacing.sm,
|
|
123
|
+
},
|
|
124
|
+
typography: {
|
|
125
|
+
inputFont: 'medium',
|
|
126
|
+
inputFontSize: 14,
|
|
127
|
+
includeFontPadding: false,
|
|
128
|
+
labelVariant: 'caption',
|
|
129
|
+
helperVariant: 'caption',
|
|
130
|
+
errorVariant: 'caption',
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export const defaultTheme: DefaultUITheme = {
|
|
135
|
+
mode: 'light',
|
|
136
|
+
colors: {
|
|
137
|
+
primary: '#9CCC8B',
|
|
138
|
+
onPrimary: '#FFFFFF',
|
|
139
|
+
background: '#FFFFFF',
|
|
140
|
+
surface: '#F3F4F6',
|
|
141
|
+
border: '#D1D1D6',
|
|
142
|
+
text: '#111827',
|
|
143
|
+
textMuted: '#6B7280',
|
|
144
|
+
disabled: '#E5E7EB',
|
|
145
|
+
onDisabled: '#6B7280',
|
|
146
|
+
icon: '#6B7280',
|
|
147
|
+
error: '#D92D20',
|
|
148
|
+
success: '#15803D',
|
|
149
|
+
warning: '#B45309',
|
|
150
|
+
transparent: 'transparent',
|
|
151
|
+
|
|
152
|
+
card: '#BAC2BF',
|
|
153
|
+
text_light: '#6B7280',
|
|
154
|
+
text_inverted: '#FFFFFF',
|
|
155
|
+
activeButtonBackground: '#9CCC8B',
|
|
156
|
+
inactiveButtonBackground: '#E5E7EB',
|
|
157
|
+
activeButtonText: '#FFFFFF',
|
|
158
|
+
inactiveButtonText: '#6B7280',
|
|
159
|
+
},
|
|
160
|
+
fonts: {
|
|
161
|
+
regular: { fontWeight: '400' },
|
|
162
|
+
medium: { fontWeight: '500' },
|
|
163
|
+
semiBold: { fontWeight: '600' },
|
|
164
|
+
bold: { fontWeight: '700' },
|
|
165
|
+
},
|
|
166
|
+
spacing: defaultSpacing,
|
|
167
|
+
radius: defaultRadius,
|
|
168
|
+
typography: {
|
|
169
|
+
display: {
|
|
170
|
+
font: 'bold',
|
|
171
|
+
fontSize: 32,
|
|
172
|
+
lineHeight: 40,
|
|
173
|
+
},
|
|
174
|
+
h1: {
|
|
175
|
+
font: 'bold',
|
|
176
|
+
fontSize: 28,
|
|
177
|
+
lineHeight: 36,
|
|
178
|
+
},
|
|
179
|
+
h2: {
|
|
180
|
+
font: 'bold',
|
|
181
|
+
fontSize: 24,
|
|
182
|
+
lineHeight: 32,
|
|
183
|
+
},
|
|
184
|
+
h3: {
|
|
185
|
+
font: 'semiBold',
|
|
186
|
+
fontSize: 20,
|
|
187
|
+
lineHeight: 28,
|
|
188
|
+
},
|
|
189
|
+
title: {
|
|
190
|
+
font: 'semiBold',
|
|
191
|
+
fontSize: 18,
|
|
192
|
+
lineHeight: 24,
|
|
193
|
+
},
|
|
194
|
+
body: {
|
|
195
|
+
font: 'regular',
|
|
196
|
+
fontSize: 16,
|
|
197
|
+
lineHeight: 24,
|
|
198
|
+
},
|
|
199
|
+
label: {
|
|
200
|
+
font: 'medium',
|
|
201
|
+
fontSize: 14,
|
|
202
|
+
lineHeight: 20,
|
|
203
|
+
},
|
|
204
|
+
caption: {
|
|
205
|
+
font: 'regular',
|
|
206
|
+
fontSize: 12,
|
|
207
|
+
lineHeight: 16,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
button: createDefaultButtonTheme(defaultSpacing, defaultRadius),
|
|
211
|
+
input: createDefaultInputTheme(defaultSpacing, defaultRadius),
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/** @deprecated Use defaultTheme. */
|
|
215
|
+
export const defaultLightTheme = defaultTheme;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import type { TextStyle } from 'react-native';
|
|
2
|
+
import type { ButtonSize, ButtonVariant } from '../components/Button/types/types';
|
|
3
|
+
|
|
4
|
+
export type ThemeMode = 'light' | 'dark';
|
|
5
|
+
|
|
6
|
+
/** Add project color tokens through module augmentation. */
|
|
7
|
+
export interface UIColorsExtension {}
|
|
8
|
+
|
|
9
|
+
/** Add project font tokens through module augmentation. */
|
|
10
|
+
export interface UIFontsExtension {}
|
|
11
|
+
|
|
12
|
+
/** Add project spacing tokens through module augmentation. */
|
|
13
|
+
export interface UISpacingExtension {}
|
|
14
|
+
|
|
15
|
+
/** Add project radius tokens through module augmentation. */
|
|
16
|
+
export interface UIRadiusExtension {}
|
|
17
|
+
|
|
18
|
+
/** Add project typography tokens through module augmentation. */
|
|
19
|
+
export interface UITypographyExtension {}
|
|
20
|
+
|
|
21
|
+
type ValidatedExtensions<TExtensions, TValue> = {
|
|
22
|
+
[K in keyof TExtensions]: TExtensions[K] extends TValue ? TExtensions[K] : never;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type DefaultUIColors = {
|
|
26
|
+
primary: string;
|
|
27
|
+
onPrimary: string;
|
|
28
|
+
background: string;
|
|
29
|
+
surface: string;
|
|
30
|
+
border: string;
|
|
31
|
+
text: string;
|
|
32
|
+
textMuted: string;
|
|
33
|
+
disabled: string;
|
|
34
|
+
onDisabled: string;
|
|
35
|
+
icon: string;
|
|
36
|
+
error: string;
|
|
37
|
+
success: string;
|
|
38
|
+
warning: string;
|
|
39
|
+
transparent: string;
|
|
40
|
+
|
|
41
|
+
/** @deprecated Use surface. */
|
|
42
|
+
card: string;
|
|
43
|
+
/** @deprecated Use textMuted. */
|
|
44
|
+
text_light: string;
|
|
45
|
+
/** @deprecated Use onPrimary. */
|
|
46
|
+
text_inverted: string;
|
|
47
|
+
/** @deprecated Use primary. */
|
|
48
|
+
activeButtonBackground: string;
|
|
49
|
+
/** @deprecated Use disabled. */
|
|
50
|
+
inactiveButtonBackground: string;
|
|
51
|
+
/** @deprecated Use onPrimary. */
|
|
52
|
+
activeButtonText: string;
|
|
53
|
+
/** @deprecated Use onDisabled. */
|
|
54
|
+
inactiveButtonText: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type ExtendedUIColors = ValidatedExtensions<UIColorsExtension, string>;
|
|
58
|
+
|
|
59
|
+
export type UIColors = DefaultUIColors & ExtendedUIColors;
|
|
60
|
+
|
|
61
|
+
export type UIColorKey = keyof UIColors;
|
|
62
|
+
|
|
63
|
+
export type UIFontToken = Pick<TextStyle, 'fontFamily' | 'fontStyle' | 'fontWeight'>;
|
|
64
|
+
|
|
65
|
+
export type DefaultUIFonts = {
|
|
66
|
+
regular: UIFontToken;
|
|
67
|
+
medium: UIFontToken;
|
|
68
|
+
semiBold: UIFontToken;
|
|
69
|
+
bold: UIFontToken;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type ExtendedUIFonts = ValidatedExtensions<UIFontsExtension, UIFontToken>;
|
|
73
|
+
|
|
74
|
+
export type UIFonts = DefaultUIFonts & ExtendedUIFonts;
|
|
75
|
+
|
|
76
|
+
export type UIFontKey = keyof UIFonts;
|
|
77
|
+
|
|
78
|
+
export type DefaultUISpacing = {
|
|
79
|
+
xs: number;
|
|
80
|
+
sm: number;
|
|
81
|
+
md: number;
|
|
82
|
+
lg: number;
|
|
83
|
+
xl: number;
|
|
84
|
+
xxl: number;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
type ExtendedUISpacing = ValidatedExtensions<UISpacingExtension, number>;
|
|
88
|
+
|
|
89
|
+
export type UISpacing = DefaultUISpacing & ExtendedUISpacing;
|
|
90
|
+
|
|
91
|
+
export type DefaultUIRadius = {
|
|
92
|
+
sm: number;
|
|
93
|
+
md: number;
|
|
94
|
+
lg: number;
|
|
95
|
+
full: number;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
type ExtendedUIRadius = ValidatedExtensions<UIRadiusExtension, number>;
|
|
99
|
+
|
|
100
|
+
export type UIRadius = DefaultUIRadius & ExtendedUIRadius;
|
|
101
|
+
|
|
102
|
+
export type UITypographyToken = {
|
|
103
|
+
font: UIFontKey;
|
|
104
|
+
fontSize: number;
|
|
105
|
+
lineHeight?: number;
|
|
106
|
+
letterSpacing?: number;
|
|
107
|
+
includeFontPadding?: TextStyle['includeFontPadding'];
|
|
108
|
+
flexShrink?: TextStyle['flexShrink'];
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export type DefaultTypographyVariant =
|
|
112
|
+
| 'display'
|
|
113
|
+
| 'h1'
|
|
114
|
+
| 'h2'
|
|
115
|
+
| 'h3'
|
|
116
|
+
| 'title'
|
|
117
|
+
| 'body'
|
|
118
|
+
| 'label'
|
|
119
|
+
| 'caption';
|
|
120
|
+
|
|
121
|
+
export type DefaultUITypography = Record<DefaultTypographyVariant, UITypographyToken>;
|
|
122
|
+
|
|
123
|
+
type ExtendedUITypography = ValidatedExtensions<UITypographyExtension, UITypographyToken>;
|
|
124
|
+
|
|
125
|
+
export type UITypography = DefaultUITypography & ExtendedUITypography;
|
|
126
|
+
|
|
127
|
+
export type TypographyVariant = keyof UITypography;
|
|
128
|
+
|
|
129
|
+
export type UIButtonVariantTheme = {
|
|
130
|
+
background: UIColorKey;
|
|
131
|
+
foreground: UIColorKey;
|
|
132
|
+
border: UIColorKey;
|
|
133
|
+
disabledBackground: UIColorKey;
|
|
134
|
+
disabledForeground: UIColorKey;
|
|
135
|
+
disabledBorder: UIColorKey;
|
|
136
|
+
borderWidth?: number;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export type UIButtonSizeTheme = {
|
|
140
|
+
minHeight: number;
|
|
141
|
+
paddingHorizontal: number;
|
|
142
|
+
paddingVertical: number;
|
|
143
|
+
radius: number;
|
|
144
|
+
borderWidth: number;
|
|
145
|
+
gap: number;
|
|
146
|
+
labelVariant: TypographyVariant;
|
|
147
|
+
labelWeight: UIFontKey;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export type UIButtonTheme = {
|
|
151
|
+
variants: Record<ButtonVariant, UIButtonVariantTheme>;
|
|
152
|
+
sizes: Record<ButtonSize, UIButtonSizeTheme>;
|
|
153
|
+
numberOfLines?: number;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export type UIButtonThemeOverride = {
|
|
157
|
+
variants?: { [K in ButtonVariant]?: Partial<UIButtonVariantTheme> };
|
|
158
|
+
sizes?: { [K in ButtonSize]?: Partial<UIButtonSizeTheme> };
|
|
159
|
+
numberOfLines?: number;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export interface UIInputTheme {
|
|
163
|
+
colors: {
|
|
164
|
+
background: UIColorKey;
|
|
165
|
+
border: UIColorKey;
|
|
166
|
+
focusedBorder: UIColorKey;
|
|
167
|
+
errorBorder: UIColorKey;
|
|
168
|
+
disabledBackground: UIColorKey;
|
|
169
|
+
disabledBorder: UIColorKey;
|
|
170
|
+
text: UIColorKey;
|
|
171
|
+
disabledText: UIColorKey;
|
|
172
|
+
placeholder: UIColorKey;
|
|
173
|
+
label: UIColorKey;
|
|
174
|
+
helper: UIColorKey;
|
|
175
|
+
error: UIColorKey;
|
|
176
|
+
};
|
|
177
|
+
geometry: {
|
|
178
|
+
marginBottom: number;
|
|
179
|
+
minHeight: number;
|
|
180
|
+
textMinHeight: number;
|
|
181
|
+
paddingHorizontal: number;
|
|
182
|
+
borderWidth: number;
|
|
183
|
+
radius: number;
|
|
184
|
+
labelGap: number;
|
|
185
|
+
supportingGap: number;
|
|
186
|
+
startAccessoryGap: number;
|
|
187
|
+
endAccessoryGap: number;
|
|
188
|
+
passwordToggleGap: number;
|
|
189
|
+
multilinePaddingVertical: number;
|
|
190
|
+
};
|
|
191
|
+
typography: {
|
|
192
|
+
inputFont: UIFontKey;
|
|
193
|
+
inputFontSize: number;
|
|
194
|
+
includeFontPadding: boolean;
|
|
195
|
+
labelVariant: TypographyVariant;
|
|
196
|
+
helperVariant: TypographyVariant;
|
|
197
|
+
errorVariant: TypographyVariant;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type UIInputThemeOverride = {
|
|
202
|
+
colors?: Partial<UIInputTheme['colors']>;
|
|
203
|
+
geometry?: Partial<UIInputTheme['geometry']>;
|
|
204
|
+
typography?: Partial<UIInputTheme['typography']>;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export type DefaultUITheme = {
|
|
208
|
+
mode: ThemeMode;
|
|
209
|
+
colors: DefaultUIColors;
|
|
210
|
+
fonts: DefaultUIFonts;
|
|
211
|
+
spacing: DefaultUISpacing;
|
|
212
|
+
radius: DefaultUIRadius;
|
|
213
|
+
typography: DefaultUITypography;
|
|
214
|
+
button: UIButtonTheme;
|
|
215
|
+
input: UIInputTheme;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export type UITheme = {
|
|
219
|
+
mode: ThemeMode;
|
|
220
|
+
colors: UIColors;
|
|
221
|
+
fonts: UIFonts;
|
|
222
|
+
spacing: UISpacing;
|
|
223
|
+
radius: UIRadius;
|
|
224
|
+
typography: UITypography;
|
|
225
|
+
button: UIButtonTheme;
|
|
226
|
+
input: UIInputTheme;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
type NestedTokenOverrides<TTokens> = {
|
|
230
|
+
[K in keyof TTokens]?: TTokens[K] extends object ? Partial<TTokens[K]> : TTokens[K];
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
export type UIThemeOverride = {
|
|
234
|
+
mode?: ThemeMode;
|
|
235
|
+
colors?: Partial<DefaultUIColors> & Partial<ExtendedUIColors>;
|
|
236
|
+
fonts?: NestedTokenOverrides<DefaultUIFonts> & Partial<ExtendedUIFonts>;
|
|
237
|
+
spacing?: Partial<DefaultUISpacing> & Partial<ExtendedUISpacing>;
|
|
238
|
+
radius?: Partial<DefaultUIRadius> & Partial<ExtendedUIRadius>;
|
|
239
|
+
typography?: NestedTokenOverrides<DefaultUITypography> & Partial<ExtendedUITypography>;
|
|
240
|
+
button?: UIButtonThemeOverride;
|
|
241
|
+
input?: UIInputThemeOverride;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/** @deprecated Use UIColors. */
|
|
245
|
+
export type UIKitColors = Pick<
|
|
246
|
+
UIColors,
|
|
247
|
+
| 'primary'
|
|
248
|
+
| 'background'
|
|
249
|
+
| 'border'
|
|
250
|
+
| 'card'
|
|
251
|
+
| 'text'
|
|
252
|
+
| 'text_inverted'
|
|
253
|
+
| 'activeButtonBackground'
|
|
254
|
+
| 'inactiveButtonBackground'
|
|
255
|
+
| 'activeButtonText'
|
|
256
|
+
| 'inactiveButtonText'
|
|
257
|
+
| 'icon'
|
|
258
|
+
| 'error'
|
|
259
|
+
>;
|
|
260
|
+
|
|
261
|
+
/** @deprecated Use UITheme. */
|
|
262
|
+
export type UIKitTheme = {
|
|
263
|
+
mode: ThemeMode;
|
|
264
|
+
colors: UIKitColors;
|
|
265
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { Dimensions, useWindowDimensions } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export type DesignBaseline = Readonly<{
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}>;
|
|
8
|
+
|
|
9
|
+
export type ScalingFunctions = {
|
|
10
|
+
scaleHorizontal: (value?: number) => number;
|
|
11
|
+
scaleVertical: (value?: number) => number;
|
|
12
|
+
scaleFontSize: (value?: number) => number;
|
|
13
|
+
scaleLineHeight: (value?: number) => number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const defaultDesignBaseline: DesignBaseline = {
|
|
17
|
+
width: 390,
|
|
18
|
+
height: 844,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
let configuredDesignBaseline: DesignBaseline = defaultDesignBaseline;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Configures the process-wide design baseline. Call this before rendering the application.
|
|
25
|
+
*/
|
|
26
|
+
export const configureScaling = ({ width, height }: DesignBaseline): void => {
|
|
27
|
+
if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) {
|
|
28
|
+
throw new RangeError('Scaling baseline width and height must be finite positive numbers.');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
configuredDesignBaseline = { width, height };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ScalingRatios = {
|
|
35
|
+
horizontal: number;
|
|
36
|
+
vertical: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getScalingRatios = (width: number, height: number, baseline: DesignBaseline): ScalingRatios => {
|
|
40
|
+
const horizontal = width / baseline.width;
|
|
41
|
+
const vertical = height / baseline.height;
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
horizontal,
|
|
45
|
+
vertical,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const createScalingFunctions = (width: number, height: number, baseline: DesignBaseline): ScalingFunctions => {
|
|
50
|
+
const ratios = getScalingRatios(width, height, baseline);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
scaleHorizontal: (value: number = 1): number => value * ratios.horizontal,
|
|
54
|
+
scaleVertical: (value: number = 1): number => value * ratios.vertical,
|
|
55
|
+
scaleFontSize: (value: number = 1): number => value * ratios.horizontal,
|
|
56
|
+
scaleLineHeight: (value: number = 1): number => value * ratios.horizontal,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const getCurrentScalingRatios = (): ScalingRatios => {
|
|
61
|
+
const { width, height } = Dimensions.get('window');
|
|
62
|
+
return getScalingRatios(width, height, configuredDesignBaseline);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const scaleHorizontal = (value: number = 1): number => {
|
|
66
|
+
return value * getCurrentScalingRatios().horizontal;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const scaleVertical = (value: number = 1): number => {
|
|
70
|
+
return value * getCurrentScalingRatios().vertical;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const scaleFontSize = (value: number = 1): number => {
|
|
74
|
+
return value * getCurrentScalingRatios().horizontal;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const scaleLineHeight = (value: number = 1): number => {
|
|
78
|
+
return value * getCurrentScalingRatios().horizontal;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const useScaling = (): ScalingFunctions => {
|
|
82
|
+
const { width, height } = useWindowDimensions();
|
|
83
|
+
const { width: baselineWidth, height: baselineHeight } = configuredDesignBaseline;
|
|
84
|
+
|
|
85
|
+
return useMemo(
|
|
86
|
+
() => createScalingFunctions(width, height, { width: baselineWidth, height: baselineHeight }),
|
|
87
|
+
[width, height, baselineWidth, baselineHeight],
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @deprecated This is a module-load snapshot. Use useWindowDimensions or Dimensions.get('window').
|
|
93
|
+
*/
|
|
94
|
+
export const size: { width: number; height: number } = Dimensions.get('window');
|