@compsych/mobile-ui 1.0.10 → 1.0.13

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.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/src/components/ActionSheet/index.tsx +124 -57
  3. package/src/components/Alert/index.tsx +19 -10
  4. package/src/components/Avatar/index.tsx +95 -92
  5. package/src/components/Badge/index.tsx +39 -36
  6. package/src/components/BodyText/index.tsx +5 -5
  7. package/src/components/Breadcrumb/index.tsx +32 -30
  8. package/src/components/Button/Button.test.tsx +13 -7
  9. package/src/components/Button/index.tsx +114 -92
  10. package/src/components/ChatBubble/ChatBubble.test.tsx +77 -0
  11. package/src/components/ChatBubble/index.tsx +187 -0
  12. package/src/components/ChatInput/ChatInput.test.tsx +90 -0
  13. package/src/components/ChatInput/index.tsx +263 -0
  14. package/src/components/Checkbox/index.tsx +24 -21
  15. package/src/components/Chip/index.tsx +75 -72
  16. package/src/components/Divider/index.tsx +3 -3
  17. package/src/components/EmptyState/index.tsx +72 -55
  18. package/src/components/HeaderText/index.tsx +5 -5
  19. package/src/components/Input/index.tsx +40 -37
  20. package/src/components/List/index.tsx +2 -3
  21. package/src/components/Pagination/index.tsx +56 -43
  22. package/src/components/PlanCard/index.tsx +118 -50
  23. package/src/components/ProgressTracker/index.tsx +44 -26
  24. package/src/components/PromotionCard/index.tsx +217 -212
  25. package/src/components/RadioButton/index.tsx +27 -25
  26. package/src/components/ScreenContainer/ScreenContainer.test.tsx +12 -2
  27. package/src/components/ScreenContainer/index.tsx +22 -12
  28. package/src/components/SegmentedControl/index.tsx +37 -30
  29. package/src/components/SelectionCard/index.tsx +38 -26
  30. package/src/components/ServiceCard/index.tsx +162 -130
  31. package/src/components/Slider/index.tsx +77 -77
  32. package/src/components/Snackbar/index.tsx +69 -57
  33. package/src/components/Switch/index.tsx +13 -12
  34. package/src/components/Tooltip/index.tsx +3 -3
  35. package/src/index.ts +13 -0
  36. package/src/theme/ThemeContext.ts +11 -0
  37. package/src/theme/ThemeProvider.tsx +40 -0
  38. package/src/theme/__tests__/ThemeProvider.test.tsx +101 -0
  39. package/src/theme/__tests__/defaultTheme.test.ts +36 -0
  40. package/src/theme/__tests__/mergeTheme.test.ts +94 -0
  41. package/src/theme/defaultTheme.ts +15 -0
  42. package/src/theme/index.ts +8 -0
  43. package/src/theme/mergeTheme.ts +47 -0
  44. package/src/theme/types.ts +39 -0
  45. package/src/theme/useTheme.ts +16 -0
@@ -0,0 +1,90 @@
1
+ import React from 'react';
2
+
3
+ import { fireEvent, render } from '@testing-library/react-native';
4
+
5
+ import { ChatInput } from './index';
6
+
7
+ jest.mock('@expo/vector-icons', () => ({
8
+ Ionicons: 'Ionicons',
9
+ }));
10
+
11
+ describe('ChatInput', () => {
12
+ it('renders placeholder text', () => {
13
+ const { getByPlaceholderText } = render(
14
+ <ChatInput
15
+ value=""
16
+ onChangeText={jest.fn()}
17
+ onSend={jest.fn()}
18
+ placeholder="Ask Sol Anything..."
19
+ />,
20
+ );
21
+ expect(getByPlaceholderText('Ask Sol Anything...')).toBeTruthy();
22
+ });
23
+
24
+ it('calls onChangeText when text is typed', () => {
25
+ const onChangeText = jest.fn();
26
+ const { getByPlaceholderText } = render(
27
+ <ChatInput
28
+ value=""
29
+ onChangeText={onChangeText}
30
+ onSend={jest.fn()}
31
+ placeholder="Type here"
32
+ />,
33
+ );
34
+ fireEvent.changeText(getByPlaceholderText('Type here'), 'Hello');
35
+ expect(onChangeText).toHaveBeenCalledWith('Hello');
36
+ });
37
+
38
+ it('calls onSend when send button is pressed and text is present', () => {
39
+ const onSend = jest.fn();
40
+ const { getByLabelText } = render(
41
+ <ChatInput value="Hello" onChangeText={jest.fn()} onSend={onSend} />,
42
+ );
43
+ fireEvent.press(getByLabelText('Send'));
44
+ expect(onSend).toHaveBeenCalledTimes(1);
45
+ });
46
+
47
+ it('does not call onSend when text is empty', () => {
48
+ const onSend = jest.fn();
49
+ const { getByLabelText } = render(
50
+ <ChatInput value="" onChangeText={jest.fn()} onSend={onSend} />,
51
+ );
52
+ fireEvent.press(getByLabelText('Send'));
53
+ expect(onSend).not.toHaveBeenCalled();
54
+ });
55
+
56
+ it('renders attach button and calls onAttach when pressed', () => {
57
+ const onAttach = jest.fn();
58
+ const { getByLabelText } = render(
59
+ <ChatInput
60
+ value=""
61
+ onChangeText={jest.fn()}
62
+ onSend={jest.fn()}
63
+ onAttach={onAttach}
64
+ />,
65
+ );
66
+ fireEvent.press(getByLabelText('Add attachment'));
67
+ expect(onAttach).toHaveBeenCalledTimes(1);
68
+ });
69
+
70
+ it('does not render attach button when onAttach is not provided', () => {
71
+ const { queryByLabelText } = render(
72
+ <ChatInput value="" onChangeText={jest.fn()} onSend={jest.fn()} />,
73
+ );
74
+ expect(queryByLabelText('Add attachment')).toBeNull();
75
+ });
76
+
77
+ it('input is not editable when disabled', () => {
78
+ const { getByLabelText } = render(
79
+ <ChatInput
80
+ value=""
81
+ onChangeText={jest.fn()}
82
+ onSend={jest.fn()}
83
+ disabled
84
+ placeholder="Ask Sol Anything..."
85
+ />,
86
+ );
87
+ const input = getByLabelText('Ask Sol Anything...');
88
+ expect(input.props.editable).toBe(false);
89
+ });
90
+ });
@@ -0,0 +1,263 @@
1
+ import React, { useMemo, useRef, useState } from 'react';
2
+
3
+ import {
4
+ Image,
5
+ ImageSourcePropType,
6
+ Pressable,
7
+ ScrollView,
8
+ StyleProp,
9
+ StyleSheet,
10
+ TextInput,
11
+ View,
12
+ ViewStyle,
13
+ } from 'react-native';
14
+
15
+ import { Ionicons } from '@expo/vector-icons';
16
+
17
+ import { useTheme } from '../../theme';
18
+
19
+ export interface ChatAttachment {
20
+ uri: string;
21
+ source?: ImageSourcePropType;
22
+ }
23
+
24
+ export interface ChatInputProps {
25
+ value: string;
26
+ onChangeText: (text: string) => void;
27
+ onSend: () => void;
28
+ onAttach?: () => void;
29
+ placeholder?: string;
30
+ attachments?: ChatAttachment[];
31
+ onRemoveAttachment?: (index: number) => void;
32
+ disabled?: boolean;
33
+ style?: StyleProp<ViewStyle>;
34
+ }
35
+
36
+ export function ChatInput({
37
+ value,
38
+ onChangeText,
39
+ onSend,
40
+ onAttach,
41
+ placeholder = 'Ask Sol Anything...',
42
+ attachments,
43
+ onRemoveAttachment,
44
+ disabled = false,
45
+ style,
46
+ }: ChatInputProps) {
47
+ const { colorRoles: cr, dimensions: dim, iconography: ico } = useTheme();
48
+ const [isFocused, setIsFocused] = useState(false);
49
+ const inputRef = useRef<TextInput>(null);
50
+
51
+ const hasText = value.trim().length > 0;
52
+ const hasAttachments = !!attachments && attachments.length > 0;
53
+ const canSend = (hasText || hasAttachments) && !disabled;
54
+
55
+ const tokenStyles = useMemo(
56
+ () => ({
57
+ container: {
58
+ borderRadius: dim.borderRadius.sysRadiusLg,
59
+ borderWidth: isFocused
60
+ ? dim.borderWidth.sysStrokeMedium
61
+ : dim.borderWidth.sysStrokeThin,
62
+ borderColor: isFocused
63
+ ? cr.accent.primary.sysPrimary
64
+ : cr.outline.sysOutlineVariant,
65
+ backgroundColor: cr.surface.surfaceContainer.sysSurfaceContainerLowest,
66
+ paddingVertical: dim.spacing.padding.sysPadding8,
67
+ paddingHorizontal: dim.spacing.padding.sysPadding12,
68
+ gap: dim.spacing.padding.sysPadding8,
69
+ },
70
+ attachBtn: {
71
+ width: 32,
72
+ height: 32,
73
+ borderRadius: dim.borderRadius.sysRadiusFull,
74
+ alignItems: 'center' as const,
75
+ justifyContent: 'center' as const,
76
+ flexShrink: 0,
77
+ },
78
+ sendBtn: {
79
+ width: 32,
80
+ height: 32,
81
+ borderRadius: dim.borderRadius.sysRadiusFull,
82
+ alignItems: 'center' as const,
83
+ justifyContent: 'center' as const,
84
+ flexShrink: 0,
85
+ backgroundColor: canSend
86
+ ? cr.custom.warning.sysWarning
87
+ : cr.surface.surfaceContainer.sysSurfaceContainerHighest,
88
+ },
89
+ attachThumb: {
90
+ width: 48,
91
+ height: 48,
92
+ borderRadius: dim.borderRadius.sysRadiusSm,
93
+ overflow: 'hidden' as const,
94
+ },
95
+ }),
96
+ [cr, dim, isFocused, canSend],
97
+ );
98
+
99
+ return (
100
+ <View style={[styles.wrapper, disabled && styles.disabled, style]}>
101
+ {/* Attachment strip */}
102
+ {hasAttachments && (
103
+ <ScrollView
104
+ horizontal
105
+ showsHorizontalScrollIndicator={false}
106
+ style={styles.attachStrip}
107
+ contentContainerStyle={styles.attachStripContent}
108
+ >
109
+ {attachments!.map((att, i) => (
110
+ <View key={i} style={styles.attachItem}>
111
+ <Image
112
+ source={att.source ?? { uri: att.uri }}
113
+ style={tokenStyles.attachThumb}
114
+ resizeMode="cover"
115
+ accessibilityLabel={`Attachment ${i + 1}`}
116
+ />
117
+ {onRemoveAttachment && (
118
+ <Pressable
119
+ onPress={() => onRemoveAttachment(i)}
120
+ style={styles.removeBtn}
121
+ accessibilityRole="button"
122
+ accessibilityLabel={`Remove attachment ${i + 1}`}
123
+ >
124
+ <Ionicons
125
+ name="close-circle"
126
+ size={16}
127
+ color={cr.surface.surface.sysOnSurfaceVariant}
128
+ />
129
+ </Pressable>
130
+ )}
131
+ </View>
132
+ ))}
133
+ </ScrollView>
134
+ )}
135
+
136
+ {/* Input row */}
137
+ <View
138
+ style={[
139
+ tokenStyles.container,
140
+ styles.inputRow,
141
+ isFocused && {
142
+ // focus ring via transparent primary halo
143
+ shadowColor: cr.accent.primary.sysPrimary,
144
+ shadowOffset: { width: 0, height: 0 },
145
+ shadowOpacity: 0.08,
146
+ shadowRadius: 4,
147
+ },
148
+ ]}
149
+ >
150
+ {/* Attach button */}
151
+ {onAttach && (
152
+ <Pressable
153
+ onPress={onAttach}
154
+ disabled={disabled}
155
+ style={({ pressed }) => [
156
+ tokenStyles.attachBtn,
157
+ pressed && styles.pressed,
158
+ ]}
159
+ accessibilityRole="button"
160
+ accessibilityLabel="Add attachment"
161
+ >
162
+ <Ionicons
163
+ name="add"
164
+ size={ico.sysSizeSm}
165
+ color={
166
+ disabled
167
+ ? cr.surface.surface.sysOnSurfaceVariant
168
+ : cr.surface.surface.sysOnSurface
169
+ }
170
+ />
171
+ </Pressable>
172
+ )}
173
+
174
+ {/* Text field */}
175
+ <TextInput
176
+ ref={inputRef}
177
+ value={value}
178
+ onChangeText={onChangeText}
179
+ placeholder={placeholder}
180
+ placeholderTextColor={cr.surface.surface.sysOnSurfaceVariant}
181
+ editable={!disabled}
182
+ multiline
183
+ onFocus={() => setIsFocused(true)}
184
+ onBlur={() => setIsFocused(false)}
185
+ style={[
186
+ styles.textInput,
187
+ {
188
+ color: cr.surface.surface.sysOnSurface,
189
+ fontSize: 16,
190
+ lineHeight: 24,
191
+ },
192
+ ]}
193
+ accessibilityLabel={placeholder}
194
+ returnKeyType="default"
195
+ />
196
+
197
+ {/* Send button */}
198
+ <Pressable
199
+ onPress={canSend ? onSend : undefined}
200
+ disabled={!canSend}
201
+ style={({ pressed }) => [
202
+ tokenStyles.sendBtn,
203
+ pressed && canSend && styles.pressed,
204
+ ]}
205
+ accessibilityRole="button"
206
+ accessibilityLabel="Send"
207
+ accessibilityState={{ disabled: !canSend }}
208
+ >
209
+ <Ionicons
210
+ name="arrow-up"
211
+ size={ico.sysSizeSm}
212
+ color={
213
+ canSend
214
+ ? cr.custom.warning.sysOnWarning
215
+ : cr.surface.surface.sysOnSurfaceVariant
216
+ }
217
+ />
218
+ </Pressable>
219
+ </View>
220
+ </View>
221
+ );
222
+ }
223
+
224
+ const styles = StyleSheet.create({
225
+ wrapper: {
226
+ gap: 4,
227
+ },
228
+ disabled: {
229
+ opacity: 0.48,
230
+ },
231
+ inputRow: {
232
+ flexDirection: 'row',
233
+ alignItems: 'flex-end',
234
+ },
235
+ textInput: {
236
+ flex: 1,
237
+ includeFontPadding: false,
238
+ padding: 0,
239
+ margin: 0,
240
+ maxHeight: 120,
241
+ },
242
+ attachStrip: {
243
+ flexShrink: 0,
244
+ },
245
+ attachStripContent: {
246
+ flexDirection: 'row',
247
+ gap: 8,
248
+ paddingHorizontal: 4,
249
+ },
250
+ attachItem: {
251
+ position: 'relative',
252
+ },
253
+ removeBtn: {
254
+ position: 'absolute',
255
+ top: -4,
256
+ right: -4,
257
+ backgroundColor: '#fff',
258
+ borderRadius: 8,
259
+ },
260
+ pressed: {
261
+ opacity: 0.7,
262
+ },
263
+ });
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useMemo, useState } from 'react';
2
2
 
3
3
  import {
4
4
  Pressable,
@@ -11,7 +11,7 @@ import {
11
11
 
12
12
  import { Ionicons } from '@expo/vector-icons';
13
13
 
14
- import { sys } from '../../tokens';
14
+ import { useTheme } from '../../theme';
15
15
 
16
16
  export type CheckboxSize = 'sm' | 'md';
17
17
  export type CheckboxCheckedState = boolean | 'indeterminate';
@@ -28,25 +28,6 @@ export interface CheckboxProps {
28
28
  style?: StyleProp<ViewStyle>;
29
29
  }
30
30
 
31
- const { colorRoles: cr, dimensions: dim, typeScale: ts } = sys;
32
-
33
- const SIZE_TOKENS = {
34
- sm: {
35
- box: 20,
36
- hitArea: 36,
37
- fontSize: ts.bodySmall.sysFontSize,
38
- lineHeight: ts.bodySmall.sysLineHeight,
39
- iconSize: 13,
40
- },
41
- md: {
42
- box: 24,
43
- hitArea: 40,
44
- fontSize: ts.bodyMedium.sysFontSize,
45
- lineHeight: ts.bodyMedium.sysLineHeight,
46
- iconSize: 16,
47
- },
48
- };
49
-
50
31
  export function Checkbox({
51
32
  checked: checkedProp,
52
33
  defaultChecked = false,
@@ -58,8 +39,30 @@ export function Checkbox({
58
39
  invalid = false,
59
40
  style,
60
41
  }: CheckboxProps) {
42
+ const { colorRoles: cr, dimensions: dim, typeScale: ts } = useTheme();
61
43
  const [internalChecked, setInternalChecked] =
62
44
  useState<boolean>(defaultChecked);
45
+
46
+ const SIZE_TOKENS = useMemo(
47
+ () => ({
48
+ sm: {
49
+ box: 20,
50
+ hitArea: 36,
51
+ fontSize: ts.bodySmall.sysFontSize,
52
+ lineHeight: ts.bodySmall.sysLineHeight,
53
+ iconSize: 13,
54
+ },
55
+ md: {
56
+ box: 24,
57
+ hitArea: 40,
58
+ fontSize: ts.bodyMedium.sysFontSize,
59
+ lineHeight: ts.bodyMedium.sysLineHeight,
60
+ iconSize: 16,
61
+ },
62
+ }),
63
+ [ts],
64
+ );
65
+
63
66
  const isControlled = checkedProp !== undefined;
64
67
  const checkedState: CheckboxCheckedState = isControlled
65
68
  ? checkedProp
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useMemo } from 'react';
2
2
 
3
3
  import {
4
4
  Pressable,
@@ -11,7 +11,7 @@ import {
11
11
 
12
12
  import { Ionicons } from '@expo/vector-icons';
13
13
 
14
- import { sys } from '../../tokens';
14
+ import { useTheme } from '../../theme';
15
15
 
16
16
  export type ChipSize = 'sm' | 'md' | 'lg' | 'xl';
17
17
  export type ChipUsage =
@@ -35,74 +35,7 @@ export interface ChipProps {
35
35
  style?: StyleProp<ViewStyle>;
36
36
  }
37
37
 
38
- const { colorRoles: cr, dimensions: dim, typeScale: ts } = sys;
39
-
40
- // ── Size tokens ───────────────────────────────────────────────────────────────
41
-
42
- const SIZE_TOKENS = {
43
- sm: {
44
- height: 20,
45
- paddingH: dim.spacing.padding.sysPadding8,
46
- paddingV: dim.spacing.padding.sysPadding4,
47
- gap: dim.spacing.padding.sysPadding4,
48
- fontSize: ts.labelSmall.sysFontSize,
49
- lineHeight: ts.labelSmall.sysLineHeight,
50
- letterSpacing: ts.labelSmall.sysTracking,
51
- iconSize: 16,
52
- closeBtnSize: 16,
53
- closeIconSize: 12,
54
- badgeSize: 16,
55
- badgeFontSize: ts.labelSmall.sysFontSize,
56
- badgeLineHeight: ts.labelSmall.sysLineHeight,
57
- },
58
- md: {
59
- height: 24,
60
- paddingH: dim.spacing.padding.sysPadding12,
61
- paddingV: dim.spacing.padding.sysPadding4,
62
- gap: dim.spacing.padding.sysPadding4,
63
- fontSize: ts.labelMedium.sysFontSize,
64
- lineHeight: ts.labelMedium.sysLineHeight,
65
- letterSpacing: ts.labelMedium.sysTracking,
66
- iconSize: 16,
67
- closeBtnSize: 16,
68
- closeIconSize: 12,
69
- badgeSize: 16,
70
- badgeFontSize: ts.labelSmall.sysFontSize,
71
- badgeLineHeight: ts.labelSmall.sysLineHeight,
72
- },
73
- lg: {
74
- height: 32,
75
- paddingH: dim.spacing.padding.sysPadding16,
76
- paddingV: dim.spacing.padding.sysPadding4,
77
- gap: dim.spacing.padding.sysPadding8,
78
- fontSize: ts.labelMedium.sysFontSize,
79
- lineHeight: ts.labelMedium.sysLineHeight,
80
- letterSpacing: ts.labelMedium.sysTracking,
81
- iconSize: 20,
82
- closeBtnSize: 20,
83
- closeIconSize: 16,
84
- badgeSize: 20,
85
- badgeFontSize: ts.labelSmall.sysFontSize,
86
- badgeLineHeight: ts.labelSmall.sysLineHeight,
87
- },
88
- xl: {
89
- height: 40,
90
- paddingH: dim.spacing.padding.sysPadding16,
91
- paddingV: dim.spacing.padding.sysPadding8,
92
- gap: dim.spacing.padding.sysPadding8,
93
- fontSize: ts.bodyMedium.sysFontSize,
94
- lineHeight: ts.bodyMedium.sysLineHeight,
95
- letterSpacing: ts.bodyMedium.sysTracking,
96
- iconSize: 20,
97
- closeBtnSize: 24,
98
- closeIconSize: 16,
99
- badgeSize: 24,
100
- badgeFontSize: ts.labelMedium.sysFontSize,
101
- badgeLineHeight: ts.labelMedium.sysLineHeight,
102
- },
103
- };
104
-
105
- // ── Usage/color tokens ────────────────────────────────────────────────────────
38
+ // ── Usage/color types ─────────────────────────────────────────────────────────
106
39
 
107
40
  type UsageColors = {
108
41
  bg: string;
@@ -114,7 +47,9 @@ type UsageColors = {
114
47
  elevated: boolean;
115
48
  };
116
49
 
117
- function getUsageColors(usage: ChipUsage): UsageColors {
50
+ type ColorRoles = ReturnType<typeof useTheme>['colorRoles'];
51
+
52
+ function getUsageColors(usage: ChipUsage, cr: ColorRoles): UsageColors {
118
53
  switch (usage) {
119
54
  case 'neutral':
120
55
  return {
@@ -176,8 +111,76 @@ export function Chip({
176
111
  badge,
177
112
  style,
178
113
  }: ChipProps) {
114
+ const { colorRoles: cr, dimensions: dim, typeScale: ts } = useTheme();
115
+
116
+ const SIZE_TOKENS = useMemo(
117
+ () => ({
118
+ sm: {
119
+ height: 20,
120
+ paddingH: dim.spacing.padding.sysPadding8,
121
+ paddingV: dim.spacing.padding.sysPadding4,
122
+ gap: dim.spacing.padding.sysPadding4,
123
+ fontSize: ts.labelSmall.sysFontSize,
124
+ lineHeight: ts.labelSmall.sysLineHeight,
125
+ letterSpacing: ts.labelSmall.sysTracking,
126
+ iconSize: 16,
127
+ closeBtnSize: 16,
128
+ closeIconSize: 12,
129
+ badgeSize: 16,
130
+ badgeFontSize: ts.labelSmall.sysFontSize,
131
+ badgeLineHeight: ts.labelSmall.sysLineHeight,
132
+ },
133
+ md: {
134
+ height: 24,
135
+ paddingH: dim.spacing.padding.sysPadding12,
136
+ paddingV: dim.spacing.padding.sysPadding4,
137
+ gap: dim.spacing.padding.sysPadding4,
138
+ fontSize: ts.labelMedium.sysFontSize,
139
+ lineHeight: ts.labelMedium.sysLineHeight,
140
+ letterSpacing: ts.labelMedium.sysTracking,
141
+ iconSize: 16,
142
+ closeBtnSize: 16,
143
+ closeIconSize: 12,
144
+ badgeSize: 16,
145
+ badgeFontSize: ts.labelSmall.sysFontSize,
146
+ badgeLineHeight: ts.labelSmall.sysLineHeight,
147
+ },
148
+ lg: {
149
+ height: 32,
150
+ paddingH: dim.spacing.padding.sysPadding16,
151
+ paddingV: dim.spacing.padding.sysPadding4,
152
+ gap: dim.spacing.padding.sysPadding8,
153
+ fontSize: ts.labelMedium.sysFontSize,
154
+ lineHeight: ts.labelMedium.sysLineHeight,
155
+ letterSpacing: ts.labelMedium.sysTracking,
156
+ iconSize: 20,
157
+ closeBtnSize: 20,
158
+ closeIconSize: 16,
159
+ badgeSize: 20,
160
+ badgeFontSize: ts.labelSmall.sysFontSize,
161
+ badgeLineHeight: ts.labelSmall.sysLineHeight,
162
+ },
163
+ xl: {
164
+ height: 40,
165
+ paddingH: dim.spacing.padding.sysPadding16,
166
+ paddingV: dim.spacing.padding.sysPadding8,
167
+ gap: dim.spacing.padding.sysPadding8,
168
+ fontSize: ts.bodyMedium.sysFontSize,
169
+ lineHeight: ts.bodyMedium.sysLineHeight,
170
+ letterSpacing: ts.bodyMedium.sysTracking,
171
+ iconSize: 20,
172
+ closeBtnSize: 24,
173
+ closeIconSize: 16,
174
+ badgeSize: 24,
175
+ badgeFontSize: ts.labelMedium.sysFontSize,
176
+ badgeLineHeight: ts.labelMedium.sysLineHeight,
177
+ },
178
+ }),
179
+ [dim, ts],
180
+ );
181
+
179
182
  const s = SIZE_TOKENS[size];
180
- const c = getUsageColors(usage);
183
+ const c = getUsageColors(usage, cr);
181
184
 
182
185
  return (
183
186
  <View
@@ -2,7 +2,7 @@ import React from 'react';
2
2
 
3
3
  import { StyleProp, View, ViewStyle } from 'react-native';
4
4
 
5
- import { sys } from '../../tokens';
5
+ import { useTheme } from '../../theme';
6
6
 
7
7
  export type DividerVariant = 'horizontal' | 'vertical';
8
8
  export type DividerWeight = 'thin' | 'thick';
@@ -14,14 +14,14 @@ export interface DividerProps {
14
14
  style?: StyleProp<ViewStyle>;
15
15
  }
16
16
 
17
- const { colorRoles: cr, dimensions: dim } = sys;
18
-
19
17
  export function Divider({
20
18
  variant = 'horizontal',
21
19
  weight = 'thin',
22
20
  dashed = false,
23
21
  style,
24
22
  }: DividerProps) {
23
+ const { colorRoles: cr, dimensions: dim } = useTheme();
24
+
25
25
  const thickness =
26
26
  weight === 'thin'
27
27
  ? dim.borderWidth.sysStrokeThin