@compsych/mobile-ui 1.0.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 +1015 -0
- package/package.json +26 -0
- package/src/Alert.tsx +372 -0
- package/src/Avatar.tsx +255 -0
- package/src/Badge.tsx +189 -0
- package/src/BodyText.tsx +62 -0
- package/src/Breadcrumb.tsx +192 -0
- package/src/Button.tsx +228 -0
- package/src/Card.tsx +152 -0
- package/src/Checkbox.tsx +182 -0
- package/src/Chip.tsx +291 -0
- package/src/Divider.tsx +60 -0
- package/src/EmptyState.tsx +364 -0
- package/src/HeaderText.tsx +69 -0
- package/src/Input.tsx +228 -0
- package/src/Pagination.tsx +353 -0
- package/src/ProgressTracker.tsx +160 -0
- package/src/RadioButton.tsx +177 -0
- package/src/Slider.tsx +347 -0
- package/src/Switch.tsx +183 -0
- package/src/Tooltip.tsx +214 -0
- package/src/index.ts +62 -0
- package/src/tokens.ts +121 -0
package/src/Tooltip.tsx
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
import { sys } from './tokens';
|
|
4
|
+
|
|
5
|
+
export type TooltipVariant = 'filled' | 'elevated';
|
|
6
|
+
/**
|
|
7
|
+
* The direction the arrow points — i.e. where the tooltip's target is
|
|
8
|
+
* relative to the bubble.
|
|
9
|
+
*
|
|
10
|
+
* `bottom` → bubble sits above target, arrow points down
|
|
11
|
+
* `top` → bubble sits below target, arrow points up
|
|
12
|
+
* `left` → bubble sits right of target, arrow points left
|
|
13
|
+
* `right` → bubble sits left of target, arrow points right
|
|
14
|
+
* `none` → no arrow
|
|
15
|
+
*/
|
|
16
|
+
export type TooltipDirection = 'none' | 'top' | 'bottom' | 'left' | 'right';
|
|
17
|
+
|
|
18
|
+
export interface TooltipProps {
|
|
19
|
+
text: string;
|
|
20
|
+
variant?: TooltipVariant;
|
|
21
|
+
direction?: TooltipDirection;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { colorRoles: cr, dimensions: dim, typeScale: ts } = sys;
|
|
25
|
+
|
|
26
|
+
// ── Arrow dimensions ─────────────────────────────────────────────────────────
|
|
27
|
+
const ARROW_BASE = 16; // px — wide axis
|
|
28
|
+
const ARROW_HEIGHT = 6; // px — narrow axis
|
|
29
|
+
|
|
30
|
+
// ── Component ────────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
export function Tooltip({
|
|
33
|
+
text,
|
|
34
|
+
variant = 'filled',
|
|
35
|
+
direction = 'none',
|
|
36
|
+
}: TooltipProps) {
|
|
37
|
+
const isFilled = variant === 'filled';
|
|
38
|
+
|
|
39
|
+
const bg = isFilled
|
|
40
|
+
? cr.surface.inverse.sysInverseSurface
|
|
41
|
+
: cr.surface.surfaceContainer.sysSurfaceContainerLowest;
|
|
42
|
+
|
|
43
|
+
const textColor = isFilled
|
|
44
|
+
? cr.surface.inverse.sysInverseOnSurface
|
|
45
|
+
: cr.surface.surface.sysOnSurface;
|
|
46
|
+
|
|
47
|
+
// ── Arrow (CSS triangle using zero-size View + borders) ───────────────────
|
|
48
|
+
// Half-base for side calculations
|
|
49
|
+
const half = ARROW_BASE / 2;
|
|
50
|
+
|
|
51
|
+
function renderArrow() {
|
|
52
|
+
if (direction === 'none') return null;
|
|
53
|
+
|
|
54
|
+
// Shared transparent sides
|
|
55
|
+
const transparent = 'transparent';
|
|
56
|
+
|
|
57
|
+
let arrowStyle: object;
|
|
58
|
+
|
|
59
|
+
switch (direction) {
|
|
60
|
+
case 'bottom':
|
|
61
|
+
// Triangle pointing down — sits below bubble
|
|
62
|
+
arrowStyle = {
|
|
63
|
+
width: 0,
|
|
64
|
+
height: 0,
|
|
65
|
+
borderLeftWidth: half,
|
|
66
|
+
borderRightWidth: half,
|
|
67
|
+
borderTopWidth: ARROW_HEIGHT,
|
|
68
|
+
borderLeftColor: transparent,
|
|
69
|
+
borderRightColor: transparent,
|
|
70
|
+
borderTopColor: bg,
|
|
71
|
+
};
|
|
72
|
+
break;
|
|
73
|
+
case 'top':
|
|
74
|
+
// Triangle pointing up — sits above bubble
|
|
75
|
+
arrowStyle = {
|
|
76
|
+
width: 0,
|
|
77
|
+
height: 0,
|
|
78
|
+
borderLeftWidth: half,
|
|
79
|
+
borderRightWidth: half,
|
|
80
|
+
borderBottomWidth: ARROW_HEIGHT,
|
|
81
|
+
borderLeftColor: transparent,
|
|
82
|
+
borderRightColor: transparent,
|
|
83
|
+
borderBottomColor: bg,
|
|
84
|
+
};
|
|
85
|
+
break;
|
|
86
|
+
case 'left':
|
|
87
|
+
// Triangle pointing left — sits to the left of bubble
|
|
88
|
+
arrowStyle = {
|
|
89
|
+
width: 0,
|
|
90
|
+
height: 0,
|
|
91
|
+
borderTopWidth: half,
|
|
92
|
+
borderBottomWidth: half,
|
|
93
|
+
borderRightWidth: ARROW_HEIGHT,
|
|
94
|
+
borderTopColor: transparent,
|
|
95
|
+
borderBottomColor: transparent,
|
|
96
|
+
borderRightColor: bg,
|
|
97
|
+
};
|
|
98
|
+
break;
|
|
99
|
+
case 'right':
|
|
100
|
+
// Triangle pointing right — sits to the right of bubble
|
|
101
|
+
arrowStyle = {
|
|
102
|
+
width: 0,
|
|
103
|
+
height: 0,
|
|
104
|
+
borderTopWidth: half,
|
|
105
|
+
borderBottomWidth: half,
|
|
106
|
+
borderLeftWidth: ARROW_HEIGHT,
|
|
107
|
+
borderTopColor: transparent,
|
|
108
|
+
borderBottomColor: transparent,
|
|
109
|
+
borderLeftColor: bg,
|
|
110
|
+
};
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return <View accessible={false} style={arrowStyle!} />;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ── Bubble ────────────────────────────────────────────────────────────────
|
|
118
|
+
const bubble = (
|
|
119
|
+
<View
|
|
120
|
+
accessible
|
|
121
|
+
accessibilityRole="text"
|
|
122
|
+
accessibilityLabel={text}
|
|
123
|
+
style={[
|
|
124
|
+
styles.bubble,
|
|
125
|
+
{
|
|
126
|
+
backgroundColor: bg,
|
|
127
|
+
paddingHorizontal: dim.spacing.padding.sysPadding12,
|
|
128
|
+
paddingVertical: dim.spacing.padding.sysPadding8,
|
|
129
|
+
borderRadius: dim.borderRadius.sysRadiusSm,
|
|
130
|
+
},
|
|
131
|
+
!isFilled && styles.elevated,
|
|
132
|
+
!isFilled && {
|
|
133
|
+
borderWidth: dim.borderWidth.sysStrokeThin,
|
|
134
|
+
borderColor: cr.outline.sysOutline,
|
|
135
|
+
},
|
|
136
|
+
]}
|
|
137
|
+
>
|
|
138
|
+
<Text
|
|
139
|
+
style={{
|
|
140
|
+
color: textColor,
|
|
141
|
+
fontSize: ts.bodySmall.sysFontSize,
|
|
142
|
+
lineHeight: ts.bodySmall.sysLineHeight,
|
|
143
|
+
fontWeight: '400',
|
|
144
|
+
textAlign: 'center',
|
|
145
|
+
includeFontPadding: false,
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
{text}
|
|
149
|
+
</Text>
|
|
150
|
+
</View>
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// ── Layout — arrow position determines stacking order ────────────────────
|
|
154
|
+
if (direction === 'none') {
|
|
155
|
+
return bubble;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (direction === 'bottom') {
|
|
159
|
+
return (
|
|
160
|
+
<View style={styles.colCenter}>
|
|
161
|
+
{bubble}
|
|
162
|
+
{renderArrow()}
|
|
163
|
+
</View>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (direction === 'top') {
|
|
168
|
+
return (
|
|
169
|
+
<View style={styles.colCenter}>
|
|
170
|
+
{renderArrow()}
|
|
171
|
+
{bubble}
|
|
172
|
+
</View>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (direction === 'right') {
|
|
177
|
+
return (
|
|
178
|
+
<View style={styles.rowCenter}>
|
|
179
|
+
{bubble}
|
|
180
|
+
{renderArrow()}
|
|
181
|
+
</View>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// left
|
|
186
|
+
return (
|
|
187
|
+
<View style={styles.rowCenter}>
|
|
188
|
+
{renderArrow()}
|
|
189
|
+
{bubble}
|
|
190
|
+
</View>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const styles = StyleSheet.create({
|
|
195
|
+
bubble: {
|
|
196
|
+
alignSelf: 'flex-start',
|
|
197
|
+
},
|
|
198
|
+
elevated: {
|
|
199
|
+
shadowColor: '#000',
|
|
200
|
+
shadowOffset: { width: 0, height: 2 },
|
|
201
|
+
shadowOpacity: 0.06,
|
|
202
|
+
shadowRadius: 4,
|
|
203
|
+
elevation: 1,
|
|
204
|
+
},
|
|
205
|
+
colCenter: {
|
|
206
|
+
alignItems: 'center',
|
|
207
|
+
alignSelf: 'flex-start',
|
|
208
|
+
},
|
|
209
|
+
rowCenter: {
|
|
210
|
+
flexDirection: 'row',
|
|
211
|
+
alignItems: 'center',
|
|
212
|
+
alignSelf: 'flex-start',
|
|
213
|
+
},
|
|
214
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// ComPsych Mobile UI — React Native Component Library
|
|
2
|
+
// Version 1.0.0
|
|
3
|
+
|
|
4
|
+
export { Alert } from './Alert';
|
|
5
|
+
export type { AlertProps, AlertVariant, AlertSize } from './Alert';
|
|
6
|
+
|
|
7
|
+
export { Avatar } from './Avatar';
|
|
8
|
+
export type { AvatarProps, AvatarSize, AvatarVariant } from './Avatar';
|
|
9
|
+
|
|
10
|
+
export { Badge } from './Badge';
|
|
11
|
+
export type { BadgeProps, BadgeSize, BadgeStyle } from './Badge';
|
|
12
|
+
|
|
13
|
+
export { Breadcrumb } from './Breadcrumb';
|
|
14
|
+
export type { BreadcrumbProps, BreadcrumbItem, BreadcrumbSize } from './Breadcrumb';
|
|
15
|
+
|
|
16
|
+
export { Button } from './Button';
|
|
17
|
+
export type { ButtonProps, ButtonVariant, ButtonSize } from './Button';
|
|
18
|
+
|
|
19
|
+
export { Card } from './Card';
|
|
20
|
+
export type { CardProps, CardVariant, CardSize } from './Card';
|
|
21
|
+
|
|
22
|
+
export { Checkbox } from './Checkbox';
|
|
23
|
+
export type { CheckboxProps, CheckboxSize, CheckboxCheckedState } from './Checkbox';
|
|
24
|
+
|
|
25
|
+
export { Chip } from './Chip';
|
|
26
|
+
export type { ChipProps, ChipSize, ChipUsage } from './Chip';
|
|
27
|
+
|
|
28
|
+
export { Divider } from './Divider';
|
|
29
|
+
export type { DividerProps, DividerVariant, DividerWeight } from './Divider';
|
|
30
|
+
|
|
31
|
+
export { EmptyState } from './EmptyState';
|
|
32
|
+
export type { EmptyStateProps, EmptyStateStyle, EmptyStateViewport } from './EmptyState';
|
|
33
|
+
|
|
34
|
+
export { Input } from './Input';
|
|
35
|
+
export type { InputProps, InputSize } from './Input';
|
|
36
|
+
|
|
37
|
+
export { Pagination } from './Pagination';
|
|
38
|
+
export type { PaginationProps, PaginationSize } from './Pagination';
|
|
39
|
+
|
|
40
|
+
export { ProgressTracker, ProgressBar } from './ProgressTracker';
|
|
41
|
+
export type { ProgressTrackerProps, ProgressTrackerSize, ProgressBarProps, TrackerStep, StepState } from './ProgressTracker';
|
|
42
|
+
|
|
43
|
+
export { RadioButton } from './RadioButton';
|
|
44
|
+
export type { RadioButtonProps, RadioButtonSize } from './RadioButton';
|
|
45
|
+
|
|
46
|
+
export { Slider } from './Slider';
|
|
47
|
+
export type { SliderProps } from './Slider';
|
|
48
|
+
|
|
49
|
+
export { Switch } from './Switch';
|
|
50
|
+
export type { SwitchProps } from './Switch';
|
|
51
|
+
|
|
52
|
+
export { Tooltip } from './Tooltip';
|
|
53
|
+
export type { TooltipProps, TooltipVariant, TooltipDirection } from './Tooltip';
|
|
54
|
+
|
|
55
|
+
export { BodyText } from './BodyText';
|
|
56
|
+
export type { BodyTextProps, BodyVariant } from './BodyText';
|
|
57
|
+
|
|
58
|
+
export { HeaderText } from './HeaderText';
|
|
59
|
+
export type { HeaderTextProps, HeaderVariant } from './HeaderText';
|
|
60
|
+
|
|
61
|
+
// Re-export tokens for consumers who need direct access
|
|
62
|
+
export { sys } from './tokens';
|
package/src/tokens.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export const sys = {
|
|
2
|
+
colorRoles: {
|
|
3
|
+
accent: {
|
|
4
|
+
primary: {
|
|
5
|
+
sysPrimary: '#075cba',
|
|
6
|
+
sysOnPrimary: '#ffffff',
|
|
7
|
+
sysPrimaryContainer: '#070f36',
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
addOn: {
|
|
11
|
+
primaryFixed: {
|
|
12
|
+
sysOnPrimaryFixed: '#075cba',
|
|
13
|
+
sysOnPrimaryFixedVariant: '#4285f4',
|
|
14
|
+
sysPrimaryFixedDim: '#e3f2fd',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
custom: {
|
|
18
|
+
info: {
|
|
19
|
+
sysInfo: '#226cee',
|
|
20
|
+
sysInfoContainer: '#daecff',
|
|
21
|
+
sysOnInfo: '#ffffff',
|
|
22
|
+
sysOnInfoContainer: '#162755',
|
|
23
|
+
},
|
|
24
|
+
success: {
|
|
25
|
+
sysSuccess: '#278647',
|
|
26
|
+
sysSuccessContainer: '#c4e9d0',
|
|
27
|
+
sysOnSuccess: '#ffffff',
|
|
28
|
+
sysOnSuccessContainer: '#030c09',
|
|
29
|
+
},
|
|
30
|
+
warning: {
|
|
31
|
+
sysWarning: '#d67d00',
|
|
32
|
+
sysWarningContainer: '#fdeed9',
|
|
33
|
+
sysOnWarning: '#ffffff',
|
|
34
|
+
sysOnWarningContainer: '#3a2304',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
error: {
|
|
38
|
+
sysError: '#d82727',
|
|
39
|
+
sysErrorContainer: '#f7d4d4',
|
|
40
|
+
sysOnError: '#ffffff',
|
|
41
|
+
sysOnErrorContainer: '#570f0f',
|
|
42
|
+
},
|
|
43
|
+
outline: {
|
|
44
|
+
sysOutline: '#ebecf0',
|
|
45
|
+
sysOutlineFixed: '#8a96a6',
|
|
46
|
+
sysOutlineVariant: '#d7dbe0',
|
|
47
|
+
},
|
|
48
|
+
surface: {
|
|
49
|
+
surface: {
|
|
50
|
+
sysSurface: '#f3f4f6',
|
|
51
|
+
sysOnSurface: '#1b1d22',
|
|
52
|
+
sysOnSurfaceVariant: '#565f6c',
|
|
53
|
+
},
|
|
54
|
+
surfaceContainer: {
|
|
55
|
+
sysSurfaceContainerLowest: '#ffffff',
|
|
56
|
+
sysSurfaceContainerLow: '#f9fafb',
|
|
57
|
+
sysSurfaceContainer: '#f3f4f6',
|
|
58
|
+
sysSurfaceContainerHighest: '#e6e8ea',
|
|
59
|
+
},
|
|
60
|
+
inverse: {
|
|
61
|
+
sysInverseSurface: '#565f6c',
|
|
62
|
+
sysInverseOnSurface: '#ffffff',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
transparent: {
|
|
66
|
+
neutral: {
|
|
67
|
+
sysBlack10: '#0000001a',
|
|
68
|
+
sysWhite20: '#ffffff33',
|
|
69
|
+
},
|
|
70
|
+
primary: {
|
|
71
|
+
sysPrimary08: '#075cba14',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
dimensions: {
|
|
76
|
+
borderRadius: {
|
|
77
|
+
sysRadiusXs: 4,
|
|
78
|
+
sysRadiusSm: 8,
|
|
79
|
+
sysRadiusMd: 12,
|
|
80
|
+
sysRadiusLg: 16,
|
|
81
|
+
sysRadiusXl: 24,
|
|
82
|
+
sysRadiusFull: 999,
|
|
83
|
+
},
|
|
84
|
+
borderWidth: {
|
|
85
|
+
sysStrokeThin: 1,
|
|
86
|
+
sysStrokeMedium: 1.5,
|
|
87
|
+
sysStrokeThick: 2,
|
|
88
|
+
sysStrokeBold: 4,
|
|
89
|
+
},
|
|
90
|
+
spacing: {
|
|
91
|
+
padding: {
|
|
92
|
+
sysPadding2: 2,
|
|
93
|
+
sysPadding4: 4,
|
|
94
|
+
sysPadding8: 8,
|
|
95
|
+
sysPadding12: 12,
|
|
96
|
+
sysPadding16: 16,
|
|
97
|
+
sysPadding20: 20,
|
|
98
|
+
sysPadding24: 24,
|
|
99
|
+
sysPadding32: 32,
|
|
100
|
+
sysPadding48: 48,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
typeScale: {
|
|
105
|
+
displayLarge: { sysFontSize: 80, sysLineHeight: 80, sysTracking: -2.4, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
106
|
+
displayMedium: { sysFontSize: 72, sysLineHeight: 79.2, sysTracking: -1.44, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
107
|
+
displaySmall: { sysFontSize: 64, sysLineHeight: 76.8, sysTracking: -0.64, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
108
|
+
headlineLarge: { sysFontSize: 48, sysLineHeight: 57.6, sysTracking: -0.48, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
109
|
+
headlineMedium: { sysFontSize: 40, sysLineHeight: 48, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
110
|
+
headlineSmall: { sysFontSize: 32, sysLineHeight: 38.4, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
111
|
+
titleLarge: { sysFontSize: 28, sysLineHeight: 36.4, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
112
|
+
titleMedium: { sysFontSize: 24, sysLineHeight: 31.2, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
113
|
+
titleSmall: { sysFontSize: 20, sysLineHeight: 28, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
114
|
+
bodyLarge: { sysFontSize: 20, sysLineHeight: 30, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
115
|
+
bodyMedium: { sysFontSize: 16, sysLineHeight: 24, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
116
|
+
bodySmall: { sysFontSize: 14, sysLineHeight: 20, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
117
|
+
labelLarge: { sysFontSize: 16, sysLineHeight: 22.4, sysTracking: 0, sysFontWeight: 'regular', sysFontWeightEmphasized: 'medium' },
|
|
118
|
+
labelMedium: { sysFontSize: 14, sysLineHeight: 20, sysTracking: 0.07, sysFontWeight: 'medium', sysFontWeightEmphasized: 'semibold' },
|
|
119
|
+
labelSmall: { sysFontSize: 12, sysLineHeight: 18, sysTracking: 0.12, sysFontWeight: 'medium', sysFontWeightEmphasized: 'semibold' },
|
|
120
|
+
},
|
|
121
|
+
} as const;
|