@praxiis/ui 0.0.1 → 0.0.3
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/index.d.mts +3 -111
- package/dist/index.d.ts +3 -111
- package/dist/index.js +6 -200
- package/dist/index.mjs +6 -192
- package/package.json +11 -12
- package/src/README.md +688 -0
- package/src/components/CalendarStrip/CalendarStrip.a11y.ts +51 -0
- package/src/components/CalendarStrip/DayCard/DayCard.a11y.ts +52 -0
- package/src/components/EmptyState/EmptyState.a11y.ts +53 -0
- package/src/components/Header/Header.a11y.ts +82 -0
- package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.a11y.ts +15 -0
- package/src/core/index.ts +1 -1
- package/src/core/restyle/index.ts +1 -1
- package/src/core/restyle/restylePresetRegistry.ts +7 -7
- package/src/index.tsx +2 -11
- package/src/primitives/actions/Button/Button.a11y.ts +38 -0
- package/src/primitives/actions/IconButton/IconButton.a11y.ts +55 -0
- package/src/primitives/content/Avatar/Avatar.a11y.ts +50 -0
- package/src/primitives/content/Badge/Badge.a11y.ts +83 -0
- package/src/primitives/content/Card/Card.a11y.ts +60 -0
- package/src/primitives/content/Chip/Chip.a11y.ts +101 -0
- package/src/primitives/content/Icon/Icon.a11y.ts +43 -0
- package/src/primitives/feedback/ProgressBar/ProgressBar.a11y.ts +68 -0
- package/src/primitives/feedback/Skeleton/Skeleton.a11y.ts +46 -0
- package/src/primitives/feedback/Spinner/Spinner.a11y.ts +47 -0
- package/src/primitives/feedback/Toast/Toast.a11y.ts +75 -0
- package/src/primitives/inputs/Checkbox/Checkbox.a11y.ts +47 -0
- package/src/primitives/inputs/RadioButton/RadioButton.a11y.ts +48 -0
- package/src/primitives/inputs/SegmentedControl/SegmentedControl.a11y.ts +59 -0
- package/src/primitives/inputs/SelectSheet/SelectSheet.a11y.ts +117 -0
- package/src/primitives/inputs/Switch/Switch.a11y.ts +29 -0
- package/src/primitives/inputs/TextInput/TextInput.a11y.ts +77 -0
- package/src/primitives/layout/Divider/Divider.a11y.ts +55 -0
- package/src/primitives/overlays/Modal/Modal.a11y.ts +64 -0
- package/src/providers/ThemeProvider/index.ts +0 -12
- package/src/providers/index.ts +0 -8
- package/src/providers/ThemeProvider/createTheme.ts +0 -304
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextInput Accessibility Helpers
|
|
3
|
+
*
|
|
4
|
+
* Generates accessibility props for the TextInput component.
|
|
5
|
+
*
|
|
6
|
+
* WCAG References:
|
|
7
|
+
* - 4.1.2 Name, Role, Value: Inputs need proper labels
|
|
8
|
+
* - 3.3.1 Error Identification: Errors announced via hint
|
|
9
|
+
* - 3.3.2 Labels or Instructions: Required fields indicated
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/labels-or-instructions
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { TextInputA11yParams, TextInputA11yProps } from "./TextInput.types";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate accessibility props for TextInput.
|
|
18
|
+
*
|
|
19
|
+
* Implements WCAG requirements:
|
|
20
|
+
* - accessibilityLabel: Uses label prop as fallback, adds "required" suffix
|
|
21
|
+
* - accessibilityHint: Error message takes precedence over custom hint
|
|
22
|
+
* - accessibilityState: Communicates disabled state
|
|
23
|
+
*
|
|
24
|
+
* @param params - Accessibility parameters
|
|
25
|
+
* @returns Accessibility props for the text input
|
|
26
|
+
*
|
|
27
|
+
* @warning Logs console warning in dev if both label and accessibilityLabel missing
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const a11yProps = getTextInputA11y({
|
|
31
|
+
* label: "Email",
|
|
32
|
+
* required: true,
|
|
33
|
+
* disabled: false,
|
|
34
|
+
* error: "Invalid email",
|
|
35
|
+
* });
|
|
36
|
+
* // { accessibilityLabel: "Email, required", accessibilityHint: "Error: Invalid email", accessibilityState: { disabled: false } }
|
|
37
|
+
*/
|
|
38
|
+
export function getTextInputA11y(
|
|
39
|
+
params: TextInputA11yParams
|
|
40
|
+
): TextInputA11yProps {
|
|
41
|
+
const {
|
|
42
|
+
label,
|
|
43
|
+
accessibilityLabel,
|
|
44
|
+
accessibilityHint,
|
|
45
|
+
disabled,
|
|
46
|
+
error,
|
|
47
|
+
required,
|
|
48
|
+
fallbackLabel,
|
|
49
|
+
requiredLabel,
|
|
50
|
+
errorPrefixLabel,
|
|
51
|
+
} = params;
|
|
52
|
+
|
|
53
|
+
if (!accessibilityLabel && !label && process.env.NODE_ENV !== "production") {
|
|
54
|
+
console.warn(
|
|
55
|
+
"[TextInput] Missing label or accessibilityLabel (WCAG 4.1.2)"
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const baseLabel = accessibilityLabel || label || fallbackLabel;
|
|
60
|
+
const fullLabel = required ? `${baseLabel}, ${requiredLabel}` : baseLabel;
|
|
61
|
+
|
|
62
|
+
// Error takes precedence, then custom hint
|
|
63
|
+
let finalHint: string | undefined;
|
|
64
|
+
if (error) {
|
|
65
|
+
finalHint = `${errorPrefixLabel}: ${error}`;
|
|
66
|
+
} else if (accessibilityHint) {
|
|
67
|
+
finalHint = accessibilityHint;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
accessibilityLabel: fullLabel,
|
|
72
|
+
accessibilityHint: finalHint,
|
|
73
|
+
accessibilityState: {
|
|
74
|
+
disabled,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Divider Accessibility Helpers
|
|
3
|
+
*
|
|
4
|
+
* Generates accessibility props for the Divider component.
|
|
5
|
+
*
|
|
6
|
+
* WCAG References:
|
|
7
|
+
* - Decorative elements should be hidden from assistive technologies
|
|
8
|
+
* - When a divider has semantic meaning (with label), it should be announced
|
|
9
|
+
*
|
|
10
|
+
* The divider uses "none" role by default as it's purely decorative.
|
|
11
|
+
* When a label is present, it's announced via accessibilityLabel.
|
|
12
|
+
*
|
|
13
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/name-role-value
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { DividerA11yParams, DividerA11yProps } from "./Divider.types";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate accessibility props for Divider.
|
|
20
|
+
*
|
|
21
|
+
* Dividers are typically decorative, so they use role="none" and
|
|
22
|
+
* are not accessible by default. When a label is present, the
|
|
23
|
+
* divider becomes accessible with the label as its description.
|
|
24
|
+
*
|
|
25
|
+
* @param params - Accessibility parameters
|
|
26
|
+
* @returns Object to spread onto the Divider component
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Decorative divider (hidden from AT)
|
|
30
|
+
* const a11yProps = getDividerA11y({ orientation: "horizontal" });
|
|
31
|
+
* // { accessibilityRole: "none", accessible: false }
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Divider with label (announced by AT)
|
|
35
|
+
* const a11yProps = getDividerA11y({
|
|
36
|
+
* orientation: "horizontal",
|
|
37
|
+
* label: "OR",
|
|
38
|
+
* accessibilityLabel: "Or"
|
|
39
|
+
* });
|
|
40
|
+
* // { accessibilityRole: "none", accessible: true, accessibilityLabel: "Or" }
|
|
41
|
+
*/
|
|
42
|
+
export function getDividerA11y(params: DividerA11yParams): DividerA11yProps {
|
|
43
|
+
const { label, accessibilityLabel } = params;
|
|
44
|
+
|
|
45
|
+
// If there's a label or explicit a11y label, make it accessible
|
|
46
|
+
const hasSemanticMeaning = Boolean(label || accessibilityLabel);
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
accessibilityRole: "none",
|
|
50
|
+
accessible: hasSemanticMeaning,
|
|
51
|
+
...(hasSemanticMeaning && {
|
|
52
|
+
accessibilityLabel: accessibilityLabel || label,
|
|
53
|
+
}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modal Accessibility Helpers
|
|
3
|
+
*
|
|
4
|
+
* Generates accessibility props for the Modal component.
|
|
5
|
+
*
|
|
6
|
+
* WCAG References:
|
|
7
|
+
* - 4.1.2 Name, Role, Value: Modal needs proper label and modal indication
|
|
8
|
+
* - 1.3.1 Info and Relationships: State must be programmatically determinable
|
|
9
|
+
* - 2.4.3 Focus Order: Modal must trap focus when visible
|
|
10
|
+
*
|
|
11
|
+
* The modal uses accessibilityViewIsModal to indicate to assistive
|
|
12
|
+
* technologies that content behind the modal is not accessible.
|
|
13
|
+
*
|
|
14
|
+
* @see https://www.w3.org/WAI/WCAG21/Understanding/name-role-value
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ModalA11yParams, ModalA11yProps, ModalCloseButtonA11yParams } from "./Modal.types";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate accessibility props for Modal container.
|
|
21
|
+
*
|
|
22
|
+
* @param params - Accessibility parameters
|
|
23
|
+
* @returns Object to spread onto the Modal container
|
|
24
|
+
*
|
|
25
|
+
* @warning Logs console warning in dev if title and accessibilityLabel are both missing
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const a11yProps = getModalA11y({
|
|
29
|
+
* title: "Confirm Delete",
|
|
30
|
+
* position: "center",
|
|
31
|
+
* });
|
|
32
|
+
* // { accessible: true, accessibilityRole: "none", accessibilityLabel: "Confirm Delete dialog", accessibilityViewIsModal: true }
|
|
33
|
+
*/
|
|
34
|
+
export function getModalA11y(params: ModalA11yParams): ModalA11yProps {
|
|
35
|
+
const { title, position, accessibilityLabel, fallbackTitle, positionLabels } = params;
|
|
36
|
+
|
|
37
|
+
if (!accessibilityLabel && !title && process.env.NODE_ENV !== "production") {
|
|
38
|
+
console.warn(
|
|
39
|
+
"[Modal] Missing title or accessibilityLabel (WCAG 4.1.2)"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const positionLabel = positionLabels[position];
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
accessible: true,
|
|
47
|
+
accessibilityRole: "none",
|
|
48
|
+
accessibilityLabel:
|
|
49
|
+
accessibilityLabel || `${title || fallbackTitle} ${positionLabel}`,
|
|
50
|
+
accessibilityViewIsModal: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get accessibility props for the modal close button.
|
|
56
|
+
*/
|
|
57
|
+
export function getModalCloseButtonA11yProps(params: ModalCloseButtonA11yParams) {
|
|
58
|
+
return {
|
|
59
|
+
accessible: true as const,
|
|
60
|
+
accessibilityRole: "button" as const,
|
|
61
|
+
accessibilityLabel: params.closeLabel,
|
|
62
|
+
accessibilityHint: params.closeHint,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -20,15 +20,3 @@ export type {
|
|
|
20
20
|
|
|
21
21
|
// Default themes
|
|
22
22
|
export { lightTheme, darkTheme, defaultTheme } from './defaultTheme';
|
|
23
|
-
|
|
24
|
-
// Theme factory
|
|
25
|
-
export {
|
|
26
|
-
createTheme,
|
|
27
|
-
createThemePair,
|
|
28
|
-
horizonTheme,
|
|
29
|
-
sageTheme,
|
|
30
|
-
sunsetTheme,
|
|
31
|
-
oceanTheme,
|
|
32
|
-
lavenderTheme,
|
|
33
|
-
roseTheme,
|
|
34
|
-
} from './createTheme';
|
package/src/providers/index.ts
CHANGED
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* El Sendero Design System - Theme Factory
|
|
3
|
-
*
|
|
4
|
-
* Create custom themes by extending the base theme with overrides.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* const myTheme = createTheme(defaultTheme, {
|
|
8
|
-
* colors: {
|
|
9
|
-
* accent: {
|
|
10
|
-
* primary: '#8B5CF6', // Purple accent
|
|
11
|
-
* }
|
|
12
|
-
* }
|
|
13
|
-
* });
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { Theme, ThemeOverrides, DeepPartial } from './types';
|
|
17
|
-
import { lightTheme, darkTheme } from './defaultTheme';
|
|
18
|
-
|
|
19
|
-
// =============================================================================
|
|
20
|
-
// DEEP MERGE UTILITY
|
|
21
|
-
// =============================================================================
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Deep merge two objects, with source values overriding target
|
|
25
|
-
*/
|
|
26
|
-
function deepMerge<T extends object>(
|
|
27
|
-
target: T,
|
|
28
|
-
source: DeepPartial<T>
|
|
29
|
-
): T {
|
|
30
|
-
const result = { ...target };
|
|
31
|
-
|
|
32
|
-
for (const key in source) {
|
|
33
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
34
|
-
const sourceValue = source[key as keyof typeof source];
|
|
35
|
-
const targetValue = (target as Record<string, unknown>)[key];
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
sourceValue !== null &&
|
|
39
|
-
typeof sourceValue === 'object' &&
|
|
40
|
-
!Array.isArray(sourceValue) &&
|
|
41
|
-
targetValue !== null &&
|
|
42
|
-
typeof targetValue === 'object' &&
|
|
43
|
-
!Array.isArray(targetValue)
|
|
44
|
-
) {
|
|
45
|
-
result[key as keyof T] = deepMerge(
|
|
46
|
-
targetValue as Record<string, unknown>,
|
|
47
|
-
sourceValue as DeepPartial<Record<string, unknown>>
|
|
48
|
-
) as T[keyof T];
|
|
49
|
-
} else if (sourceValue !== undefined) {
|
|
50
|
-
result[key as keyof T] = sourceValue as T[keyof T];
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return result;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// CREATE THEME
|
|
60
|
-
// =============================================================================
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Create a custom theme by extending a base theme with overrides.
|
|
64
|
-
*
|
|
65
|
-
* @param baseTheme - The theme to extend (usually defaultTheme)
|
|
66
|
-
* @param overrides - Partial theme object with your customizations
|
|
67
|
-
* @returns A complete Theme object with your overrides applied
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* // Create a sage-accented theme
|
|
71
|
-
* const sageTheme = createTheme(defaultTheme, {
|
|
72
|
-
* name: 'Sage',
|
|
73
|
-
* colors: {
|
|
74
|
-
* accent: {
|
|
75
|
-
* primary: '#6B8F6B',
|
|
76
|
-
* primaryHover: '#557255',
|
|
77
|
-
* primaryPressed: '#445944',
|
|
78
|
-
* }
|
|
79
|
-
* }
|
|
80
|
-
* });
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* // Create a more rounded theme
|
|
84
|
-
* const softTheme = createTheme(defaultTheme, {
|
|
85
|
-
* radii: {
|
|
86
|
-
* md: 16,
|
|
87
|
-
* lg: 24,
|
|
88
|
-
* xl: 32,
|
|
89
|
-
* }
|
|
90
|
-
* });
|
|
91
|
-
*/
|
|
92
|
-
export function createTheme(
|
|
93
|
-
baseTheme: Theme,
|
|
94
|
-
overrides: ThemeOverrides
|
|
95
|
-
): Theme {
|
|
96
|
-
return deepMerge(baseTheme, overrides);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// =============================================================================
|
|
100
|
-
// CREATE THEME PAIR
|
|
101
|
-
// =============================================================================
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Create both light and dark versions of a custom theme.
|
|
105
|
-
*
|
|
106
|
-
* @param overrides - Overrides to apply to both light and dark themes
|
|
107
|
-
* @param lightOverrides - Additional overrides for light theme only
|
|
108
|
-
* @param darkOverrides - Additional overrides for dark theme only
|
|
109
|
-
* @returns Object with light and dark theme variants
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* const { light, dark } = createThemePair(
|
|
113
|
-
* { name: 'MyBrand' },
|
|
114
|
-
* { colors: { accent: { primary: '#A68B6A' } } }, // Light-specific
|
|
115
|
-
* { colors: { accent: { primary: '#C4A285' } } } // Dark-specific
|
|
116
|
-
* );
|
|
117
|
-
*/
|
|
118
|
-
export function createThemePair(
|
|
119
|
-
overrides: ThemeOverrides = {},
|
|
120
|
-
lightOverrides: ThemeOverrides = {},
|
|
121
|
-
darkOverrides: ThemeOverrides = {}
|
|
122
|
-
): { light: Theme; dark: Theme } {
|
|
123
|
-
return {
|
|
124
|
-
light: createTheme(
|
|
125
|
-
createTheme(lightTheme, overrides),
|
|
126
|
-
lightOverrides
|
|
127
|
-
),
|
|
128
|
-
dark: createTheme(
|
|
129
|
-
createTheme(darkTheme, overrides),
|
|
130
|
-
darkOverrides
|
|
131
|
-
),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// =============================================================================
|
|
136
|
-
// PRESET THEMES
|
|
137
|
-
// =============================================================================
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Horizon Default - Blue with a calming feel
|
|
141
|
-
*/
|
|
142
|
-
export const horizonTheme = createThemePair({
|
|
143
|
-
name: 'Horizon',
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Sage Theme - Green-focused for hope and growth
|
|
148
|
-
*/
|
|
149
|
-
export const sageTheme = createThemePair(
|
|
150
|
-
{ name: 'Sage' },
|
|
151
|
-
{
|
|
152
|
-
colors: {
|
|
153
|
-
accent: {
|
|
154
|
-
primary: '#6B8F6B',
|
|
155
|
-
primaryHover: '#557255',
|
|
156
|
-
primaryPressed: '#445944',
|
|
157
|
-
},
|
|
158
|
-
text: {
|
|
159
|
-
link: '#6B8F6B',
|
|
160
|
-
},
|
|
161
|
-
border: {
|
|
162
|
-
focus: '#6B8F6B',
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
colors: {
|
|
168
|
-
accent: {
|
|
169
|
-
primary: '#8FAF8F',
|
|
170
|
-
primaryHover: '#B3C7B3',
|
|
171
|
-
primaryPressed: '#6B8F6B',
|
|
172
|
-
},
|
|
173
|
-
text: {
|
|
174
|
-
link: '#8FAF8F',
|
|
175
|
-
},
|
|
176
|
-
border: {
|
|
177
|
-
focus: '#8FAF8F',
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
}
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Sunset Theme - Warm coral/peach for energy and comfort
|
|
185
|
-
*/
|
|
186
|
-
export const sunsetTheme = createThemePair(
|
|
187
|
-
{ name: 'Sunset' },
|
|
188
|
-
{
|
|
189
|
-
colors: {
|
|
190
|
-
accent: {
|
|
191
|
-
primary: '#E8836B',
|
|
192
|
-
primaryHover: '#CC6B55',
|
|
193
|
-
primaryPressed: '#A85545',
|
|
194
|
-
},
|
|
195
|
-
text: {
|
|
196
|
-
link: '#E8836B',
|
|
197
|
-
},
|
|
198
|
-
border: {
|
|
199
|
-
focus: '#E8836B',
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
{
|
|
204
|
-
colors: {
|
|
205
|
-
accent: {
|
|
206
|
-
primary: '#FF9B85',
|
|
207
|
-
primaryHover: '#FFBAA8',
|
|
208
|
-
primaryPressed: '#E8836B',
|
|
209
|
-
},
|
|
210
|
-
text: {
|
|
211
|
-
link: '#FF9B85',
|
|
212
|
-
},
|
|
213
|
-
border: {
|
|
214
|
-
focus: '#FF9B85',
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Ocean Theme - Teal/cyan accents, calming water vibes
|
|
222
|
-
*/
|
|
223
|
-
export const oceanTheme = createThemePair(
|
|
224
|
-
{
|
|
225
|
-
colors: {
|
|
226
|
-
accent: {
|
|
227
|
-
primary: '#0E9AA5',
|
|
228
|
-
primaryHover: '#0B7E87',
|
|
229
|
-
primaryPressed: '#086269',
|
|
230
|
-
},
|
|
231
|
-
text: { link: '#0E9AA5' },
|
|
232
|
-
border: { focus: '#0E9AA5' },
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
colors: {
|
|
237
|
-
accent: {
|
|
238
|
-
primary: '#2DD4BF',
|
|
239
|
-
primaryHover: '#5EEAD4',
|
|
240
|
-
primaryPressed: '#0E9AA5',
|
|
241
|
-
},
|
|
242
|
-
text: { link: '#2DD4BF' },
|
|
243
|
-
border: { focus: '#2DD4BF' },
|
|
244
|
-
},
|
|
245
|
-
}
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Lavender Theme - Soft purple accents, relaxing and spiritual
|
|
250
|
-
*/
|
|
251
|
-
export const lavenderTheme = createThemePair(
|
|
252
|
-
{ name: 'Lavender' },
|
|
253
|
-
{
|
|
254
|
-
colors: {
|
|
255
|
-
accent: {
|
|
256
|
-
primary: '#8B5CF6',
|
|
257
|
-
primaryHover: '#7C3AED',
|
|
258
|
-
primaryPressed: '#6D28D9',
|
|
259
|
-
},
|
|
260
|
-
text: { link: '#8B5CF6' },
|
|
261
|
-
border: { focus: '#8B5CF6' },
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
{
|
|
265
|
-
colors: {
|
|
266
|
-
accent: {
|
|
267
|
-
primary: '#A78BFA',
|
|
268
|
-
primaryHover: '#C4B5FD',
|
|
269
|
-
primaryPressed: '#8B5CF6',
|
|
270
|
-
},
|
|
271
|
-
text: { link: '#A78BFA' },
|
|
272
|
-
border: { focus: '#A78BFA' },
|
|
273
|
-
},
|
|
274
|
-
}
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Rose Theme - Warm pink/rose accents, gentle and nurturing
|
|
279
|
-
*/
|
|
280
|
-
export const roseTheme = createThemePair(
|
|
281
|
-
{ name: 'Rose' },
|
|
282
|
-
{
|
|
283
|
-
colors: {
|
|
284
|
-
accent: {
|
|
285
|
-
primary: '#E11D6C',
|
|
286
|
-
primaryHover: '#BE185D',
|
|
287
|
-
primaryPressed: '#9D174D',
|
|
288
|
-
},
|
|
289
|
-
text: { link: '#E11D6C' },
|
|
290
|
-
border: { focus: '#E11D6C' },
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
colors: {
|
|
295
|
-
accent: {
|
|
296
|
-
primary: '#F472B6',
|
|
297
|
-
primaryHover: '#F9A8D4',
|
|
298
|
-
primaryPressed: '#E11D6C',
|
|
299
|
-
},
|
|
300
|
-
text: { link: '#F472B6' },
|
|
301
|
-
border: { focus: '#F472B6' },
|
|
302
|
-
},
|
|
303
|
-
}
|
|
304
|
-
);
|