@titan-design/react-ui 0.0.2 → 0.1.1
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/dist/{chunk-NA3EES23.mjs → chunk-MGW37MPO.mjs} +26 -4
- package/dist/chunk-MGW37MPO.mjs.map +1 -0
- package/dist/index.d.mts +115 -2
- package/dist/index.d.ts +115 -2
- package/dist/index.js +262 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +225 -3
- package/dist/index.mjs.map +1 -1
- package/dist/theme/index.d.mts +124 -109
- package/dist/theme/index.d.ts +124 -109
- package/dist/theme/index.js +24 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/index.mjs +1 -1
- package/package.json +12 -5
- package/src/components/custom/DateTime/DateTime.stories.tsx +180 -0
- package/src/components/custom/DateTime/DateTime.test.tsx +152 -0
- package/src/components/custom/DateTime/DateTime.tsx +235 -0
- package/src/components/custom/DateTime/index.ts +2 -0
- package/src/components/custom/EmptyState/EmptyState.stories.tsx +99 -0
- package/src/components/custom/EmptyState/EmptyState.test.tsx +106 -0
- package/src/components/custom/EmptyState/EmptyState.tsx +68 -0
- package/src/components/custom/EmptyState/index.ts +2 -0
- package/src/components/custom/Metric/Metric.stories.tsx +133 -0
- package/src/components/custom/Metric/Metric.test.tsx +120 -0
- package/src/components/custom/Metric/Metric.tsx +92 -0
- package/src/components/custom/Metric/index.ts +2 -0
- package/src/components/custom/Sidebar/Sidebar.stories.tsx +227 -0
- package/src/components/custom/Sidebar/Sidebar.test.tsx +185 -0
- package/src/components/custom/Sidebar/Sidebar.tsx +257 -0
- package/src/components/custom/Sidebar/index.ts +18 -0
- package/src/components/custom/Table/Table.stories.tsx +481 -0
- package/src/components/custom/Table/Table.test.tsx +531 -0
- package/src/components/custom/Table/Table.tsx +696 -0
- package/src/components/custom/Table/index.ts +22 -0
- package/src/components/custom/Typography/Typography.stories.tsx +153 -0
- package/src/components/custom/Typography/Typography.test.tsx +107 -0
- package/src/components/custom/Typography/Typography.tsx +218 -0
- package/src/components/custom/Typography/index.ts +19 -0
- package/src/components/custom/index.ts +8 -0
- package/src/components/custom/stepper/Stepper.stories.tsx +245 -0
- package/src/components/custom/stepper/Stepper.test.tsx +230 -0
- package/src/components/custom/stepper/Stepper.tsx +250 -0
- package/src/components/custom/stepper/index.ts +10 -0
- package/src/components/index.ts +5 -0
- package/src/components/ui/alert/Alert.stories.tsx +154 -0
- package/src/components/ui/alert/Alert.test.tsx +202 -0
- package/src/components/ui/alert/Alert.tsx +170 -0
- package/src/components/ui/alert/index.ts +8 -0
- package/src/components/ui/autocomplete/Autocomplete.stories.tsx +299 -0
- package/src/components/ui/autocomplete/Autocomplete.test.tsx +247 -0
- package/src/components/ui/autocomplete/Autocomplete.tsx +332 -0
- package/src/components/ui/autocomplete/index.ts +2 -0
- package/src/components/ui/avatar/Avatar.stories.tsx +105 -0
- package/src/components/ui/avatar/Avatar.test.tsx +135 -0
- package/src/components/ui/avatar/Avatar.tsx +168 -0
- package/src/components/ui/avatar/index.ts +2 -0
- package/src/components/ui/badge/Badge.stories.tsx +100 -0
- package/src/components/ui/badge/Badge.test.tsx +86 -0
- package/src/components/ui/badge/Badge.tsx +105 -0
- package/src/components/ui/badge/index.ts +2 -0
- package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +70 -0
- package/src/components/ui/breadcrumbs/Breadcrumbs.test.tsx +156 -0
- package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +127 -0
- package/src/components/ui/breadcrumbs/index.ts +2 -0
- package/src/components/ui/button/Button.stories.tsx +216 -0
- package/src/components/ui/button/Button.test.tsx +132 -0
- package/src/components/ui/button/Button.tsx +242 -0
- package/src/components/ui/button/index.ts +10 -0
- package/src/components/ui/card/Card.stories.tsx +443 -0
- package/src/components/ui/card/Card.test.tsx +265 -0
- package/src/components/ui/card/Card.tsx +380 -0
- package/src/components/ui/card/index.ts +20 -0
- package/src/components/ui/checkbox/Checkbox.stories.tsx +126 -0
- package/src/components/ui/checkbox/Checkbox.test.tsx +152 -0
- package/src/components/ui/checkbox/Checkbox.tsx +163 -0
- package/src/components/ui/checkbox/index.ts +2 -0
- package/src/components/ui/chip/Chip.stories.tsx +112 -0
- package/src/components/ui/chip/Chip.test.tsx +119 -0
- package/src/components/ui/chip/Chip.tsx +151 -0
- package/src/components/ui/chip/index.ts +2 -0
- package/src/components/ui/collapse/Collapse.stories.tsx +313 -0
- package/src/components/ui/collapse/Collapse.test.tsx +298 -0
- package/src/components/ui/collapse/Collapse.tsx +275 -0
- package/src/components/ui/collapse/index.ts +18 -0
- package/src/components/ui/data-row/DataRow.stories.tsx +78 -0
- package/src/components/ui/data-row/DataRow.test.tsx +78 -0
- package/src/components/ui/data-row/DataRow.tsx +29 -0
- package/src/components/ui/data-row/index.ts +2 -0
- package/src/components/ui/divider/Divider.stories.tsx +71 -0
- package/src/components/ui/divider/Divider.test.tsx +55 -0
- package/src/components/ui/divider/Divider.tsx +37 -0
- package/src/components/ui/divider/index.ts +2 -0
- package/src/components/ui/drawer/Drawer.stories.tsx +228 -0
- package/src/components/ui/drawer/Drawer.test.tsx +142 -0
- package/src/components/ui/drawer/Drawer.tsx +228 -0
- package/src/components/ui/drawer/index.ts +9 -0
- package/src/components/ui/form-field/FormField.stories.tsx +260 -0
- package/src/components/ui/form-field/FormField.test.tsx +280 -0
- package/src/components/ui/form-field/FormField.tsx +308 -0
- package/src/components/ui/form-field/index.ts +2 -0
- package/src/components/ui/help-tip/HelpTip.stories.tsx +250 -0
- package/src/components/ui/help-tip/HelpTip.test.tsx +198 -0
- package/src/components/ui/help-tip/HelpTip.tsx +229 -0
- package/src/components/ui/help-tip/index.ts +2 -0
- package/src/components/ui/icon-box/IconBox.stories.tsx +139 -0
- package/src/components/ui/icon-box/IconBox.test.tsx +120 -0
- package/src/components/ui/icon-box/IconBox.tsx +57 -0
- package/src/components/ui/icon-box/index.ts +1 -0
- package/src/components/ui/index.ts +36 -0
- package/src/components/ui/input/Input.stories.tsx +192 -0
- package/src/components/ui/input/Input.test.tsx +86 -0
- package/src/components/ui/input/Input.tsx +273 -0
- package/src/components/ui/input/index.ts +2 -0
- package/src/components/ui/link/Link.stories.tsx +78 -0
- package/src/components/ui/link/Link.test.tsx +94 -0
- package/src/components/ui/link/Link.tsx +86 -0
- package/src/components/ui/link/index.ts +2 -0
- package/src/components/ui/list-item/ListItem.stories.tsx +146 -0
- package/src/components/ui/list-item/ListItem.test.tsx +128 -0
- package/src/components/ui/list-item/ListItem.tsx +89 -0
- package/src/components/ui/list-item/index.ts +14 -0
- package/src/components/ui/menu/Menu.stories.tsx +180 -0
- package/src/components/ui/menu/Menu.test.tsx +353 -0
- package/src/components/ui/menu/Menu.tsx +222 -0
- package/src/components/ui/menu/index.ts +2 -0
- package/src/components/ui/modal/Modal.stories.tsx +350 -0
- package/src/components/ui/modal/Modal.test.tsx +159 -0
- package/src/components/ui/modal/Modal.tsx +254 -0
- package/src/components/ui/modal/index.ts +19 -0
- package/src/components/ui/popover/Popover.stories.tsx +190 -0
- package/src/components/ui/popover/Popover.test.tsx +277 -0
- package/src/components/ui/popover/Popover.tsx +162 -0
- package/src/components/ui/popover/index.ts +2 -0
- package/src/components/ui/progress/Progress.stories.tsx +190 -0
- package/src/components/ui/progress/Progress.test.tsx +181 -0
- package/src/components/ui/progress/Progress.tsx +320 -0
- package/src/components/ui/progress/index.ts +9 -0
- package/src/components/ui/radio/Radio.stories.tsx +199 -0
- package/src/components/ui/radio/Radio.test.tsx +166 -0
- package/src/components/ui/radio/Radio.tsx +200 -0
- package/src/components/ui/radio/index.ts +2 -0
- package/src/components/ui/section/Section.stories.tsx +111 -0
- package/src/components/ui/section/Section.test.tsx +121 -0
- package/src/components/ui/section/Section.tsx +52 -0
- package/src/components/ui/section/index.ts +6 -0
- package/src/components/ui/select/Select.stories.tsx +286 -0
- package/src/components/ui/select/Select.test.tsx +180 -0
- package/src/components/ui/select/Select.tsx +236 -0
- package/src/components/ui/select/index.ts +2 -0
- package/src/components/ui/skeleton/Skeleton.stories.tsx +153 -0
- package/src/components/ui/skeleton/Skeleton.test.tsx +162 -0
- package/src/components/ui/skeleton/Skeleton.tsx +229 -0
- package/src/components/ui/skeleton/index.ts +16 -0
- package/src/components/ui/spinner/Spinner.stories.tsx +67 -0
- package/src/components/ui/spinner/Spinner.test.tsx +67 -0
- package/src/components/ui/spinner/Spinner.tsx +72 -0
- package/src/components/ui/spinner/index.ts +2 -0
- package/src/components/ui/stack/Stack.stories.tsx +127 -0
- package/src/components/ui/stack/Stack.test.tsx +184 -0
- package/src/components/ui/stack/Stack.tsx +76 -0
- package/src/components/ui/stack/index.ts +2 -0
- package/src/components/ui/surface/Surface.stories.tsx +91 -0
- package/src/components/ui/surface/Surface.test.tsx +63 -0
- package/src/components/ui/surface/Surface.tsx +51 -0
- package/src/components/ui/surface/index.ts +1 -0
- package/src/components/ui/switch/Switch.stories.tsx +111 -0
- package/src/components/ui/switch/Switch.test.tsx +112 -0
- package/src/components/ui/switch/Switch.tsx +103 -0
- package/src/components/ui/switch/index.ts +2 -0
- package/src/components/ui/tabs/Tabs.stories.tsx +213 -0
- package/src/components/ui/tabs/Tabs.test.tsx +192 -0
- package/src/components/ui/tabs/Tabs.tsx +253 -0
- package/src/components/ui/tabs/index.ts +16 -0
- package/src/components/ui/toast/Toast.stories.tsx +255 -0
- package/src/components/ui/toast/Toast.test.tsx +207 -0
- package/src/components/ui/toast/Toast.tsx +327 -0
- package/src/components/ui/toast/index.ts +8 -0
- package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +415 -0
- package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +224 -0
- package/src/components/ui/toolbar-button/ToolbarButton.tsx +307 -0
- package/src/components/ui/toolbar-button/index.ts +7 -0
- package/src/components/ui/tooltip/Tooltip.stories.tsx +126 -0
- package/src/components/ui/tooltip/Tooltip.test.tsx +179 -0
- package/src/components/ui/tooltip/Tooltip.tsx +143 -0
- package/src/components/ui/tooltip/index.ts +2 -0
- package/src/index.ts +10 -0
- package/src/test/setup.ts +19 -0
- package/src/theme/Colors.stories.tsx +258 -0
- package/src/theme/config.ts +193 -0
- package/src/theme/elevation.stories.tsx +346 -0
- package/src/theme/elevation.test.ts +27 -0
- package/src/theme/elevation.ts +567 -0
- package/src/theme/index.ts +39 -0
- package/src/theme/shadows.stories.tsx +523 -0
- package/src/theme/shadows.ts +439 -0
- package/src/theme/tokens/index.ts +2 -0
- package/src/theme/tokens/primitives.ts +354 -0
- package/src/theme/tokens/semantic.ts +381 -0
- package/src/types/jest-axe.d.ts +16 -0
- package/src/types/nativewind.d.ts +54 -0
- package/src/utils/cn.ts +14 -0
- package/src/utils/colors.ts +140 -0
- package/src/utils/form.ts +188 -0
- package/src/utils/index.ts +29 -0
- package/src/utils/useTheme.ts +72 -0
- package/dist/chunk-NA3EES23.mjs.map +0 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Design Tokens
|
|
3
|
+
*
|
|
4
|
+
* Meaningful tokens following DTCG (Design Tokens Community Group) naming conventions.
|
|
5
|
+
* Pattern: {category}-{intent}-{variant?}-{state?}
|
|
6
|
+
*
|
|
7
|
+
* Categories:
|
|
8
|
+
* - brand-* : Brand colors (primary, secondary, accent)
|
|
9
|
+
* - status-* : Feedback colors (success, error, warning, info)
|
|
10
|
+
* - result-* : Outcome indicators (improve, degrade, inconclusive, neutral)
|
|
11
|
+
* - data-* : Data visualization colors (chart series)
|
|
12
|
+
* - on-* : Text on colored backgrounds
|
|
13
|
+
* - surface-* : Elevated containers (NOT "paper")
|
|
14
|
+
* - background-* : Page backgrounds
|
|
15
|
+
* - text-* : Text colors
|
|
16
|
+
* - border-* : Border colors
|
|
17
|
+
* - interactive-* : Hover/focus/active/disabled states
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { primitiveColors as p, discreteRainbow } from './primitives'
|
|
21
|
+
|
|
22
|
+
// Light mode semantic colors (default)
|
|
23
|
+
export const semanticColorsLight = {
|
|
24
|
+
// Brand colors (brand-*)
|
|
25
|
+
'brand-primary': p.accent[400], // #FF7900
|
|
26
|
+
'brand-primary-light': p.accent[200], // #FF9630
|
|
27
|
+
'brand-primary-dark': p.accent[700], // #D0620C
|
|
28
|
+
'brand-primary-subtle': 'rgba(255, 121, 0, 0.08)',
|
|
29
|
+
'brand-primary-hover': p.accent[500],
|
|
30
|
+
'brand-primary-active': p.accent[600],
|
|
31
|
+
|
|
32
|
+
'brand-secondary': p.steel[500], // #406D87
|
|
33
|
+
'brand-secondary-light': p.steel[300], // #678498
|
|
34
|
+
'brand-secondary-dark': p.steel[700], // #32556D
|
|
35
|
+
'brand-secondary-subtle': 'rgba(64, 109, 135, 0.08)',
|
|
36
|
+
'brand-secondary-hover': p.steel[600],
|
|
37
|
+
'brand-secondary-active': p.steel[700],
|
|
38
|
+
|
|
39
|
+
// Text on brand backgrounds (on-*)
|
|
40
|
+
'on-brand-primary': p.white,
|
|
41
|
+
'on-brand-secondary': p.white,
|
|
42
|
+
|
|
43
|
+
// Status colors (status-*)
|
|
44
|
+
'status-success': p.teal[500], // #14B8A6
|
|
45
|
+
'status-success-light': p.teal[400], // #43C6B7
|
|
46
|
+
'status-success-dark': p.teal[700], // #0E8074
|
|
47
|
+
'status-success-subtle': p.teal[50],
|
|
48
|
+
|
|
49
|
+
'status-error': p.red[600], // #D14343
|
|
50
|
+
'status-error-light': p.red[400], // #DA6868
|
|
51
|
+
'status-error-dark': p.red[700], // #922E2E
|
|
52
|
+
'status-error-subtle': p.red[50],
|
|
53
|
+
|
|
54
|
+
'status-warning': p.amber[500], // #FFB020
|
|
55
|
+
'status-warning-light': p.amber[400], // #FFBF4C
|
|
56
|
+
'status-warning-dark': p.amber[600], // #B27B16
|
|
57
|
+
'status-warning-subtle': p.amber[50],
|
|
58
|
+
|
|
59
|
+
'status-info': p.sky[500], // #2196F3
|
|
60
|
+
'status-info-light': p.sky[400], // #64B6F7
|
|
61
|
+
'status-info-dark': p.sky[700], // #0B79D0
|
|
62
|
+
'status-info-subtle': p.sky[50],
|
|
63
|
+
|
|
64
|
+
// Text on status backgrounds (on-status-*)
|
|
65
|
+
'on-status-success': p.white,
|
|
66
|
+
'on-status-error': p.white,
|
|
67
|
+
'on-status-warning': p.white,
|
|
68
|
+
'on-status-info': p.white,
|
|
69
|
+
|
|
70
|
+
// Result/outcome indicators (result-*)
|
|
71
|
+
'result-improve': '#4caf50', // Green - positive outcome
|
|
72
|
+
'result-improve-light': 'rgba(76, 175, 80, 0.12)',
|
|
73
|
+
'result-improve-dark': '#248a24',
|
|
74
|
+
'result-degrade': '#ef5350', // Red - negative outcome
|
|
75
|
+
'result-degrade-light': 'rgba(239, 83, 80, 0.12)',
|
|
76
|
+
'result-degrade-dark': '#b30000',
|
|
77
|
+
'result-inconclusive': '#9E9A97', // Gray - no clear result
|
|
78
|
+
'result-inconclusive-light': 'rgba(158, 154, 151, 0.12)',
|
|
79
|
+
'result-neutral': p.neutral[500], // Neutral baseline
|
|
80
|
+
|
|
81
|
+
// Text on result backgrounds (on-result-*)
|
|
82
|
+
'on-result-improve': p.white,
|
|
83
|
+
'on-result-degrade': p.white,
|
|
84
|
+
'on-result-inconclusive': p.white,
|
|
85
|
+
|
|
86
|
+
// Data visualization colors (data-*)
|
|
87
|
+
// First 10 colors from discrete rainbow optimized for charts
|
|
88
|
+
'data-1': discreteRainbow[9], // #1965B0 - Blue
|
|
89
|
+
'data-2': discreteRainbow[14], // #4EB265 - Green
|
|
90
|
+
'data-3': discreteRainbow[17], // #F7F056 - Yellow
|
|
91
|
+
'data-4': discreteRainbow[25], // #DC050C - Red
|
|
92
|
+
'data-5': discreteRainbow[8], // #882E72 - Purple
|
|
93
|
+
'data-6': discreteRainbow[20], // #F4A736 - Orange
|
|
94
|
+
'data-7': discreteRainbow[13], // #7BAFDE - Light Blue
|
|
95
|
+
'data-8': discreteRainbow[15], // #90C987 - Light Green
|
|
96
|
+
'data-9': discreteRainbow[3], // #CAACCB - Lavender
|
|
97
|
+
'data-10': discreteRainbow[22], // #EE8026 - Dark Orange
|
|
98
|
+
|
|
99
|
+
// Text colors (text-*)
|
|
100
|
+
'text-primary': '#121828',
|
|
101
|
+
'text-secondary': '#65748B',
|
|
102
|
+
'text-tertiary': p.neutral[400],
|
|
103
|
+
'text-disabled': 'rgba(55, 65, 81, 0.48)',
|
|
104
|
+
'text-inverse': p.white,
|
|
105
|
+
'text-link': p.blue[600],
|
|
106
|
+
'text-link-hover': p.blue[700],
|
|
107
|
+
|
|
108
|
+
// Surface colors (surface-*) - for elevated containers
|
|
109
|
+
'surface-base': p.white,
|
|
110
|
+
'surface-elevated': p.neutral[50], // #FAFAFA - slightly off-white for elevated cards
|
|
111
|
+
'surface-raised': p.neutral[100], // #F3F4F6 - light gray for raised cards
|
|
112
|
+
'surface-overlay': p.white,
|
|
113
|
+
'surface-input': p.neutral[50], // Input field background (filled variant)
|
|
114
|
+
|
|
115
|
+
// Background colors (background-*)
|
|
116
|
+
'background-base': '#EBEBEB',
|
|
117
|
+
'background-default': p.white,
|
|
118
|
+
'background-subtle': p.neutral[50],
|
|
119
|
+
|
|
120
|
+
// Border colors (border-*)
|
|
121
|
+
'border-default': '#E8E9EB',
|
|
122
|
+
'border-subtle': p.neutral[100],
|
|
123
|
+
'border-strong': p.neutral[300],
|
|
124
|
+
'border-focus': p.blue[600],
|
|
125
|
+
'border-input': p.neutral[300], // Input field border
|
|
126
|
+
'border-input-hover': p.neutral[400], // Input field border on hover
|
|
127
|
+
'border-input-focus': p.blue[600], // Input field border on focus
|
|
128
|
+
'border-input-error': p.red[600], // Input field border on error
|
|
129
|
+
|
|
130
|
+
// Interactive states (interactive-*)
|
|
131
|
+
'interactive-hover': 'rgba(55, 65, 81, 0.04)',
|
|
132
|
+
'interactive-focus': 'rgba(55, 65, 81, 0.12)',
|
|
133
|
+
'interactive-active': 'rgba(55, 65, 81, 0.16)',
|
|
134
|
+
'interactive-selected': 'rgba(55, 65, 81, 0.08)',
|
|
135
|
+
'interactive-disabled': 'rgba(55, 65, 81, 0.12)',
|
|
136
|
+
'interactive-disabled-text': 'rgba(55, 65, 81, 0.26)',
|
|
137
|
+
|
|
138
|
+
// Divider
|
|
139
|
+
'divider': '#E8E9EB',
|
|
140
|
+
|
|
141
|
+
// Avatar default
|
|
142
|
+
'avatar-background': p.neutral[500],
|
|
143
|
+
'avatar-text': p.white,
|
|
144
|
+
} as const
|
|
145
|
+
|
|
146
|
+
// Dark mode semantic colors
|
|
147
|
+
export const semanticColorsDark = {
|
|
148
|
+
// Brand colors stay the same in dark mode
|
|
149
|
+
'brand-primary': p.accent[400],
|
|
150
|
+
'brand-primary-light': p.accent[200],
|
|
151
|
+
'brand-primary-dark': p.accent[700],
|
|
152
|
+
'brand-primary-subtle': 'rgba(255, 121, 0, 0.12)',
|
|
153
|
+
'brand-primary-hover': p.accent[300],
|
|
154
|
+
'brand-primary-active': p.accent[200],
|
|
155
|
+
|
|
156
|
+
'brand-secondary': p.steel[500],
|
|
157
|
+
'brand-secondary-light': p.steel[300],
|
|
158
|
+
'brand-secondary-dark': p.steel[700],
|
|
159
|
+
'brand-secondary-subtle': 'rgba(64, 109, 135, 0.12)',
|
|
160
|
+
'brand-secondary-hover': p.steel[400],
|
|
161
|
+
'brand-secondary-active': p.steel[300],
|
|
162
|
+
|
|
163
|
+
// Text on brand backgrounds
|
|
164
|
+
'on-brand-primary': p.white,
|
|
165
|
+
'on-brand-secondary': p.white,
|
|
166
|
+
|
|
167
|
+
// Status colors
|
|
168
|
+
'status-success': p.teal[500],
|
|
169
|
+
'status-success-light': p.teal[400],
|
|
170
|
+
'status-success-dark': p.teal[700],
|
|
171
|
+
'status-success-subtle': 'rgba(20, 184, 166, 0.12)',
|
|
172
|
+
|
|
173
|
+
'status-error': p.red[600],
|
|
174
|
+
'status-error-light': p.red[400],
|
|
175
|
+
'status-error-dark': p.red[700],
|
|
176
|
+
'status-error-subtle': 'rgba(209, 67, 67, 0.12)',
|
|
177
|
+
|
|
178
|
+
'status-warning': p.amber[500],
|
|
179
|
+
'status-warning-light': p.amber[400],
|
|
180
|
+
'status-warning-dark': p.amber[600],
|
|
181
|
+
'status-warning-subtle': 'rgba(255, 176, 32, 0.12)',
|
|
182
|
+
|
|
183
|
+
'status-info': p.sky[500],
|
|
184
|
+
'status-info-light': p.sky[400],
|
|
185
|
+
'status-info-dark': p.sky[700],
|
|
186
|
+
'status-info-subtle': 'rgba(33, 150, 243, 0.12)',
|
|
187
|
+
|
|
188
|
+
// Text on status backgrounds
|
|
189
|
+
'on-status-success': p.white,
|
|
190
|
+
'on-status-error': p.white,
|
|
191
|
+
'on-status-warning': p.white,
|
|
192
|
+
'on-status-info': p.white,
|
|
193
|
+
|
|
194
|
+
// Result/outcome indicators (result-*)
|
|
195
|
+
'result-improve': '#4caf50',
|
|
196
|
+
'result-improve-light': 'rgba(76, 175, 80, 0.16)',
|
|
197
|
+
'result-improve-dark': '#248a24',
|
|
198
|
+
'result-degrade': '#ef5350',
|
|
199
|
+
'result-degrade-light': 'rgba(239, 83, 80, 0.16)',
|
|
200
|
+
'result-degrade-dark': '#b30000',
|
|
201
|
+
'result-inconclusive': '#9E9A97',
|
|
202
|
+
'result-inconclusive-light': 'rgba(158, 154, 151, 0.16)',
|
|
203
|
+
'result-neutral': p.neutral[400],
|
|
204
|
+
|
|
205
|
+
// Text on result backgrounds
|
|
206
|
+
'on-result-improve': p.white,
|
|
207
|
+
'on-result-degrade': p.white,
|
|
208
|
+
'on-result-inconclusive': p.white,
|
|
209
|
+
|
|
210
|
+
// Data visualization colors (same in dark mode for consistency)
|
|
211
|
+
'data-1': discreteRainbow[9],
|
|
212
|
+
'data-2': discreteRainbow[14],
|
|
213
|
+
'data-3': discreteRainbow[17],
|
|
214
|
+
'data-4': discreteRainbow[25],
|
|
215
|
+
'data-5': discreteRainbow[8],
|
|
216
|
+
'data-6': discreteRainbow[20],
|
|
217
|
+
'data-7': discreteRainbow[13],
|
|
218
|
+
'data-8': discreteRainbow[15],
|
|
219
|
+
'data-9': discreteRainbow[3],
|
|
220
|
+
'data-10': discreteRainbow[22],
|
|
221
|
+
|
|
222
|
+
// Text colors - inverted for dark mode
|
|
223
|
+
'text-primary': p.neutral[100],
|
|
224
|
+
'text-secondary': p.neutral[400],
|
|
225
|
+
'text-tertiary': p.neutral[500],
|
|
226
|
+
'text-disabled': 'rgba(255, 255, 255, 0.38)',
|
|
227
|
+
'text-inverse': p.neutral[900],
|
|
228
|
+
'text-link': '#828DF8',
|
|
229
|
+
'text-link-hover': p.blue[400],
|
|
230
|
+
|
|
231
|
+
// Surface colors - dark backgrounds
|
|
232
|
+
'surface-base': p.charcoal[700], // #161616 - main surface
|
|
233
|
+
'surface-elevated': p.charcoal[600], // #191919 - elevated surface
|
|
234
|
+
'surface-raised': p.charcoal[500], // #1C1C1C - raised surface
|
|
235
|
+
'surface-overlay': p.charcoal[600], // #191919 - overlay surface
|
|
236
|
+
'surface-input': p.charcoal[600], // #191919 - input surface
|
|
237
|
+
|
|
238
|
+
// Background colors
|
|
239
|
+
'background-base': p.charcoal[900], // #101010 - darkest charcoal
|
|
240
|
+
'background-default': p.charcoal[700], // #161616 - main background
|
|
241
|
+
'background-subtle': p.charcoal[500], // #1C1C1C - subtle background
|
|
242
|
+
|
|
243
|
+
// Border colors
|
|
244
|
+
'border-default': p.charcoal[400], // #1F1F1F - default border
|
|
245
|
+
'border-subtle': p.charcoal[500], // #1C1C1C - subtle border
|
|
246
|
+
'border-strong': p.charcoal[300], // #2C2C2C - strong border
|
|
247
|
+
'border-focus': '#828DF8',
|
|
248
|
+
'border-input': p.neutral[600],
|
|
249
|
+
'border-input-hover': p.neutral[500],
|
|
250
|
+
'border-input-focus': '#828DF8',
|
|
251
|
+
'border-input-error': p.red[500],
|
|
252
|
+
|
|
253
|
+
// Interactive states
|
|
254
|
+
'interactive-hover': 'rgba(255, 255, 255, 0.04)',
|
|
255
|
+
'interactive-focus': 'rgba(255, 255, 255, 0.12)',
|
|
256
|
+
'interactive-active': 'rgba(255, 255, 255, 0.16)',
|
|
257
|
+
'interactive-selected': 'rgba(255, 255, 255, 0.08)',
|
|
258
|
+
'interactive-disabled': 'rgba(255, 255, 255, 0.12)',
|
|
259
|
+
'interactive-disabled-text': 'rgba(255, 255, 255, 0.26)',
|
|
260
|
+
|
|
261
|
+
// Divider
|
|
262
|
+
'divider': p.charcoal[400], // #1F1F1F - divider color
|
|
263
|
+
|
|
264
|
+
// Avatar default
|
|
265
|
+
'avatar-background': p.neutral[600],
|
|
266
|
+
'avatar-text': p.white,
|
|
267
|
+
} as const
|
|
268
|
+
|
|
269
|
+
// Typography tokens matching existing app
|
|
270
|
+
export const semanticTypography = {
|
|
271
|
+
// Headings (Space Grotesk)
|
|
272
|
+
h1: {
|
|
273
|
+
fontFamily: 'heading',
|
|
274
|
+
fontSize: '3.5rem',
|
|
275
|
+
fontWeight: 700,
|
|
276
|
+
lineHeight: 1.375,
|
|
277
|
+
},
|
|
278
|
+
h2: {
|
|
279
|
+
fontFamily: 'heading',
|
|
280
|
+
fontSize: '3rem',
|
|
281
|
+
fontWeight: 700,
|
|
282
|
+
lineHeight: 1.375,
|
|
283
|
+
},
|
|
284
|
+
h3: {
|
|
285
|
+
fontFamily: 'heading',
|
|
286
|
+
fontSize: '2.25rem',
|
|
287
|
+
fontWeight: 700,
|
|
288
|
+
lineHeight: 1.375,
|
|
289
|
+
},
|
|
290
|
+
h4: {
|
|
291
|
+
fontFamily: 'heading',
|
|
292
|
+
fontSize: '2rem',
|
|
293
|
+
fontWeight: 700,
|
|
294
|
+
lineHeight: 1.375,
|
|
295
|
+
},
|
|
296
|
+
h5: {
|
|
297
|
+
fontFamily: 'heading',
|
|
298
|
+
fontSize: '1.5rem',
|
|
299
|
+
fontWeight: 600,
|
|
300
|
+
lineHeight: 1.375,
|
|
301
|
+
},
|
|
302
|
+
h6: {
|
|
303
|
+
fontFamily: 'heading',
|
|
304
|
+
fontSize: '1.125rem',
|
|
305
|
+
fontWeight: 600,
|
|
306
|
+
lineHeight: 1.375,
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
// Body text (Nunito Sans)
|
|
310
|
+
body1: {
|
|
311
|
+
fontFamily: 'body',
|
|
312
|
+
fontSize: '1rem',
|
|
313
|
+
fontWeight: 400,
|
|
314
|
+
lineHeight: 1.5,
|
|
315
|
+
},
|
|
316
|
+
body2: {
|
|
317
|
+
fontFamily: 'body',
|
|
318
|
+
fontSize: '0.875rem',
|
|
319
|
+
fontWeight: 400,
|
|
320
|
+
lineHeight: 1.57,
|
|
321
|
+
},
|
|
322
|
+
subtitle1: {
|
|
323
|
+
fontFamily: 'body',
|
|
324
|
+
fontSize: '1rem',
|
|
325
|
+
fontWeight: 500,
|
|
326
|
+
lineHeight: 1.75,
|
|
327
|
+
},
|
|
328
|
+
subtitle2: {
|
|
329
|
+
fontFamily: 'body',
|
|
330
|
+
fontSize: '0.875rem',
|
|
331
|
+
fontWeight: 500,
|
|
332
|
+
lineHeight: 1.57,
|
|
333
|
+
},
|
|
334
|
+
caption: {
|
|
335
|
+
fontFamily: 'body',
|
|
336
|
+
fontSize: '0.75rem',
|
|
337
|
+
fontWeight: 400,
|
|
338
|
+
lineHeight: 1.66,
|
|
339
|
+
},
|
|
340
|
+
overline: {
|
|
341
|
+
fontFamily: 'body',
|
|
342
|
+
fontSize: '0.75rem',
|
|
343
|
+
fontWeight: 600,
|
|
344
|
+
lineHeight: 2.5,
|
|
345
|
+
letterSpacing: '0.5px',
|
|
346
|
+
textTransform: 'uppercase' as const,
|
|
347
|
+
},
|
|
348
|
+
button: {
|
|
349
|
+
fontFamily: 'sans',
|
|
350
|
+
fontSize: '0.875rem',
|
|
351
|
+
fontWeight: 600,
|
|
352
|
+
lineHeight: 1.75,
|
|
353
|
+
},
|
|
354
|
+
} as const
|
|
355
|
+
|
|
356
|
+
// Button size tokens
|
|
357
|
+
export const buttonSizes = {
|
|
358
|
+
sm: {
|
|
359
|
+
paddingX: '16px',
|
|
360
|
+
paddingY: '6px',
|
|
361
|
+
fontSize: '0.875rem',
|
|
362
|
+
},
|
|
363
|
+
md: {
|
|
364
|
+
paddingX: '20px',
|
|
365
|
+
paddingY: '8px',
|
|
366
|
+
fontSize: '0.875rem',
|
|
367
|
+
},
|
|
368
|
+
lg: {
|
|
369
|
+
paddingX: '24px',
|
|
370
|
+
paddingY: '11px',
|
|
371
|
+
fontSize: '1rem',
|
|
372
|
+
},
|
|
373
|
+
} as const
|
|
374
|
+
|
|
375
|
+
// Export type for theme mode
|
|
376
|
+
export type ThemeMode = 'light' | 'dark'
|
|
377
|
+
|
|
378
|
+
// Helper to get semantic colors based on mode
|
|
379
|
+
export function getSemanticColors(mode: ThemeMode) {
|
|
380
|
+
return mode === 'dark' ? semanticColorsDark : semanticColorsLight
|
|
381
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare module 'jest-axe' {
|
|
2
|
+
export function axe(
|
|
3
|
+
html: Element | string,
|
|
4
|
+
options?: Record<string, unknown>
|
|
5
|
+
): Promise<{ violations: unknown[] }>
|
|
6
|
+
|
|
7
|
+
export const toHaveNoViolations: {
|
|
8
|
+
toHaveNoViolations(
|
|
9
|
+
results: { violations: unknown[] }
|
|
10
|
+
): { pass: boolean; message(): string }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function configureAxe(
|
|
14
|
+
options?: Record<string, unknown>
|
|
15
|
+
): typeof axe
|
|
16
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NativeWind type augmentations
|
|
3
|
+
*
|
|
4
|
+
* Adds `className` prop support to React Native components.
|
|
5
|
+
* This allows Tailwind classes to be used with NativeWind.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import 'react-native'
|
|
9
|
+
|
|
10
|
+
declare module 'react-native' {
|
|
11
|
+
interface ViewProps {
|
|
12
|
+
className?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface TextProps {
|
|
16
|
+
className?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ImageProps {
|
|
20
|
+
className?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ScrollViewProps {
|
|
24
|
+
className?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface TextInputProps {
|
|
28
|
+
className?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface TouchableOpacityProps {
|
|
32
|
+
className?: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface TouchableHighlightProps {
|
|
36
|
+
className?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface PressableProps {
|
|
40
|
+
className?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ActivityIndicatorProps {
|
|
44
|
+
className?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface FlatListProps<ItemT> {
|
|
48
|
+
className?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface SectionListProps<ItemT, SectionT> {
|
|
52
|
+
className?: string
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/utils/cn.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { clsx, type ClassValue } from 'clsx'
|
|
2
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Utility function to merge Tailwind CSS classes with proper conflict resolution.
|
|
6
|
+
* Combines clsx for conditional classes with tailwind-merge for deduplication.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* cn('p-4 bg-red-500', isActive && 'bg-blue-500', className)
|
|
10
|
+
* // If isActive is true, returns 'p-4 bg-blue-500' (not 'p-4 bg-red-500 bg-blue-500')
|
|
11
|
+
*/
|
|
12
|
+
export function cn(...inputs: ClassValue[]): string {
|
|
13
|
+
return twMerge(clsx(inputs))
|
|
14
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color utility functions for the design system
|
|
3
|
+
*
|
|
4
|
+
* lighten/darken are re-exported from shadows.ts which uses HSV-based
|
|
5
|
+
* color math for more perceptually consistent results across hues.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { lighten, darken } from '../theme/shadows'
|
|
9
|
+
|
|
10
|
+
export type StatusType = 'success' | 'error' | 'warning' | 'info'
|
|
11
|
+
export type ResultType = 'improve' | 'degrade' | 'inconclusive' | 'neutral'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Get the semantic color token for a status type.
|
|
15
|
+
*
|
|
16
|
+
* @param status - The status type
|
|
17
|
+
* @returns The CSS variable reference for the status color
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const color = getStatusColor('success') // 'var(--color-status-success)'
|
|
21
|
+
*/
|
|
22
|
+
export function getStatusColor(status: StatusType): string {
|
|
23
|
+
return `var(--color-status-${status})`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the semantic color token for a result type.
|
|
28
|
+
*
|
|
29
|
+
* @param result - The result type
|
|
30
|
+
* @returns The CSS variable reference for the result color
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const color = getResultColor('improve') // 'var(--color-result-improve)'
|
|
34
|
+
*/
|
|
35
|
+
export function getResultColor(result: ResultType): string {
|
|
36
|
+
return `var(--color-result-${result})`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Apply alpha/opacity to a color.
|
|
41
|
+
* Works with hex colors and rgb values.
|
|
42
|
+
*
|
|
43
|
+
* @param color - The color value (hex or rgb)
|
|
44
|
+
* @param opacity - Opacity value between 0 and 1
|
|
45
|
+
* @returns The color with alpha applied
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* alpha('#5048E5', 0.5) // 'rgba(80, 72, 229, 0.5)'
|
|
49
|
+
* alpha('rgb(80, 72, 229)', 0.5) // 'rgba(80, 72, 229, 0.5)'
|
|
50
|
+
*/
|
|
51
|
+
export function alpha(color: string, opacity: number): string {
|
|
52
|
+
// Clamp opacity between 0 and 1
|
|
53
|
+
const clampedOpacity = Math.max(0, Math.min(1, opacity))
|
|
54
|
+
|
|
55
|
+
// Handle hex colors
|
|
56
|
+
if (color.startsWith('#')) {
|
|
57
|
+
const hex = color.slice(1)
|
|
58
|
+
let r: number, g: number, b: number
|
|
59
|
+
|
|
60
|
+
if (hex.length === 3) {
|
|
61
|
+
r = parseInt(hex[0] + hex[0], 16)
|
|
62
|
+
g = parseInt(hex[1] + hex[1], 16)
|
|
63
|
+
b = parseInt(hex[2] + hex[2], 16)
|
|
64
|
+
} else if (hex.length === 6) {
|
|
65
|
+
r = parseInt(hex.slice(0, 2), 16)
|
|
66
|
+
g = parseInt(hex.slice(2, 4), 16)
|
|
67
|
+
b = parseInt(hex.slice(4, 6), 16)
|
|
68
|
+
} else {
|
|
69
|
+
return color
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Handle rgb colors
|
|
76
|
+
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/)
|
|
77
|
+
if (rgbMatch) {
|
|
78
|
+
const [, r, g, b] = rgbMatch
|
|
79
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle rgba colors - replace the alpha value
|
|
83
|
+
const rgbaMatch = color.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/)
|
|
84
|
+
if (rgbaMatch) {
|
|
85
|
+
const [, r, g, b] = rgbaMatch
|
|
86
|
+
return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return color
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Determine if a color is light or dark.
|
|
94
|
+
* Useful for determining text color contrast.
|
|
95
|
+
*
|
|
96
|
+
* @param color - Hex color value
|
|
97
|
+
* @returns 'light' or 'dark'
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* getLuminance('#FFFFFF') // 'light'
|
|
101
|
+
* getLuminance('#000000') // 'dark'
|
|
102
|
+
*/
|
|
103
|
+
export function getLuminance(color: string): 'light' | 'dark' {
|
|
104
|
+
if (!color.startsWith('#')) return 'dark'
|
|
105
|
+
|
|
106
|
+
const hex = color.slice(1)
|
|
107
|
+
let r: number, g: number, b: number
|
|
108
|
+
|
|
109
|
+
if (hex.length === 3) {
|
|
110
|
+
r = parseInt(hex[0] + hex[0], 16)
|
|
111
|
+
g = parseInt(hex[1] + hex[1], 16)
|
|
112
|
+
b = parseInt(hex[2] + hex[2], 16)
|
|
113
|
+
} else if (hex.length === 6) {
|
|
114
|
+
r = parseInt(hex.slice(0, 2), 16)
|
|
115
|
+
g = parseInt(hex.slice(2, 4), 16)
|
|
116
|
+
b = parseInt(hex.slice(4, 6), 16)
|
|
117
|
+
} else {
|
|
118
|
+
return 'dark'
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Calculate relative luminance using sRGB
|
|
122
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
|
123
|
+
|
|
124
|
+
return luminance > 0.5 ? 'light' : 'dark'
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get a contrasting text color for a given background.
|
|
129
|
+
*
|
|
130
|
+
* @param backgroundColor - The background color (hex)
|
|
131
|
+
* @returns 'white' or 'black' for contrast
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* getContrastText('#5048E5') // 'white'
|
|
135
|
+
* getContrastText('#FFFFFF') // 'black'
|
|
136
|
+
*/
|
|
137
|
+
export function getContrastText(backgroundColor: string): string {
|
|
138
|
+
return getLuminance(backgroundColor) === 'light' ? '#000000' : '#FFFFFF'
|
|
139
|
+
}
|
|
140
|
+
|