@eagami/ui 4.5.0 → 4.5.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/package.json CHANGED
@@ -1,15 +1,25 @@
1
1
  {
2
2
  "name": "@eagami/ui",
3
- "version": "4.5.0",
4
- "description": "Lightweight, accessible Angular UI component library built on CSS custom properties",
3
+ "version": "4.5.1",
4
+ "description": "Lightweight, accessible, themeable Angular UI component library and icon set built on CSS custom properties",
5
5
  "author": "Michal Wiraszka <michal@eagami.com>",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "angular",
9
+ "angular-components",
9
10
  "ui",
11
+ "components",
10
12
  "component-library",
11
13
  "design-system",
12
- "accessible"
14
+ "accessible",
15
+ "a11y",
16
+ "dark-mode",
17
+ "theming",
18
+ "icons",
19
+ "signals",
20
+ "standalone",
21
+ "typescript",
22
+ "css-variables"
13
23
  ],
14
24
  "homepage": "https://eagami.com/ui",
15
25
  "repository": {
@@ -41,5 +51,10 @@
41
51
  "default": "./fesm2022/eagami-ui.mjs"
42
52
  }
43
53
  },
44
- "type": "module"
54
+ "type": "module",
55
+ "files": [
56
+ "fesm2022",
57
+ "types",
58
+ "README.md"
59
+ ]
45
60
  }
@@ -1,68 +0,0 @@
1
- // Shared SCSS mixins for the library. Consume from a component stylesheet with:
2
- // @use '../../styles/mixins' as ea;
3
- // .ea-foo__close { @include ea.icon-button; }
4
-
5
- // Standard focus indicator. The ring is a soft box-shadow halo, but box-shadow
6
- // is dropped in forced-colors (Windows High Contrast) mode, which would leave
7
- // keyboard users with no visible focus. Pair the halo with a real outline that
8
- // only renders in forced-colors so the ring survives there. Pass the full
9
- // box-shadow value to compose the ring with an existing shadow.
10
- @mixin focus-ring($ring: var(--shadow-focus-ring)) {
11
- box-shadow: $ring;
12
-
13
- @media (forced-colors: active) {
14
- outline: 2px solid Highlight;
15
- outline-offset: 2px;
16
- }
17
- }
18
-
19
- // Floating surfaces (menus, dialogs, popovers, toasts) lean on elevation shadow
20
- // for their boundary, but shadows are dropped in forced-colors mode. Add a
21
- // hairline border there so the surface stays separated from the content behind.
22
- @mixin elevated-surface-border {
23
- @media (forced-colors: active) {
24
- border: 1px solid CanvasText;
25
- }
26
- }
27
-
28
- // Standard icon button: clear, close/dismiss, password-toggle, nav, etc. The box
29
- // is `--ea-icon-button-size` (em) so it scales with the host component's size and
30
- // is consistent across components at a given size tier. The glyph is enlarged so
31
- // it reads clearly inside the box regardless of how much padding the icon's own
32
- // viewBox carries (the feather `x`, for instance, only fills its middle half).
33
- @mixin icon-button {
34
- display: inline-flex;
35
- align-items: center;
36
- justify-content: center;
37
- flex-shrink: 0;
38
- width: var(--ea-icon-button-size, 1.75em);
39
- height: var(--ea-icon-button-size, 1.75em);
40
- padding: 0;
41
- border: none;
42
- border-radius: var(--radius-sm);
43
- background: none;
44
- color: var(--color-text-secondary);
45
- cursor: pointer;
46
- transition: var(--transition-colors);
47
-
48
- // Glyph sized via font-size (not width) so it overrides the icon's inline 1em
49
- // host size and still scales with the box.
50
- > * {
51
- font-size: 1.25em;
52
- }
53
-
54
- &:hover {
55
- background-color: var(--color-state-hover);
56
- color: var(--color-text-primary);
57
- }
58
-
59
- &:focus-visible {
60
- outline: none;
61
- @include focus-ring;
62
- }
63
-
64
- &:disabled {
65
- cursor: not-allowed;
66
- opacity: 0.5;
67
- }
68
- }
@@ -1,62 +0,0 @@
1
- *,
2
- *::before,
3
- *::after {
4
- box-sizing: border-box;
5
- margin: 0;
6
- padding: 0;
7
- }
8
-
9
- html {
10
- font-size: 16px;
11
- -webkit-text-size-adjust: 100%;
12
- tab-size: 4;
13
- }
14
-
15
- body {
16
- font-family: var(--font-family-sans);
17
- font-size: var(--font-size-md);
18
- line-height: var(--line-height-normal);
19
- color: var(--color-text-primary);
20
- background-color: var(--color-bg-canvas);
21
- -webkit-font-smoothing: antialiased;
22
- -moz-osx-font-smoothing: grayscale;
23
- }
24
-
25
- img,
26
- svg,
27
- video {
28
- display: block;
29
- max-width: 100%;
30
- }
31
-
32
- button,
33
- input,
34
- optgroup,
35
- select,
36
- textarea {
37
- font-family: inherit;
38
- font-size: 100%;
39
- font-weight: inherit;
40
- line-height: inherit;
41
- color: inherit;
42
- }
43
-
44
- button {
45
- cursor: pointer;
46
- background: transparent;
47
- border: none;
48
- }
49
-
50
- a {
51
- color: var(--color-text-link);
52
- text-decoration: underline;
53
-
54
- &:hover {
55
- color: var(--color-text-link-hover);
56
- }
57
- }
58
-
59
- :focus-visible {
60
- outline: var(--border-width-medium) solid var(--color-border-focus);
61
- outline-offset: 2px;
62
- }
@@ -1,39 +0,0 @@
1
- @use 'mixins' as ea;
2
-
3
- // Guard against "sticky hover" on touch devices, which fire `mouseenter` on tap
4
- // but never the matching `mouseleave`. The directive gates pointer listeners on
5
- // `(hover: hover)`, but if a tooltip ever slips through keep it invisible on touch.
6
- .ea-tooltip {
7
- z-index: var(--z-index-tooltip);
8
- position: absolute;
9
- padding: var(--space-1-5) var(--space-2-5);
10
- font-family: var(--font-family-sans);
11
- font-size: var(--font-size-xs);
12
- font-weight: var(--font-weight-medium);
13
- line-height: var(--line-height-normal);
14
- white-space: nowrap;
15
- // When a max-width switches the bubble to multi-line, break long unbreakable
16
- // strings (URLs, tokens) instead of letting them overflow the bubble.
17
- overflow-wrap: anywhere;
18
- border: var(--border-width-thin) solid var(--color-tooltip-border);
19
- border-radius: var(--radius-md);
20
- background-color: var(--color-tooltip-surface);
21
- color: var(--color-neutral-0);
22
- pointer-events: none;
23
- animation: ea-tooltip-fade-in var(--duration-fast) var(--ease-out);
24
- @include ea.elevated-surface-border;
25
-
26
- @media (hover: none) {
27
- display: none;
28
- }
29
- }
30
-
31
- @keyframes ea-tooltip-fade-in {
32
- from {
33
- opacity: 0;
34
- }
35
-
36
- to {
37
- opacity: 1;
38
- }
39
- }
@@ -1,6 +0,0 @@
1
- // Global stylesheet: loads all design token custom properties and the base reset.
2
- // Consumers must also load the DM Sans and Syne fonts via <link> tags in the HTML head.
3
-
4
- @use 'tokens/index';
5
- @use 'reset';
6
- @use 'tooltip';
@@ -1,265 +0,0 @@
1
- // Every token-declaring selector is wrapped in :where() so it contributes zero
2
- // specificity. A consumer's own root-level token override (specificity 0,1,0)
3
- // then wins in light mode, OS-dark, and forced dark alike, independent of
4
- // stylesheet load order. The library's own light-to-dark switching still
5
- // resolves correctly by source order, since the dark blocks come after the
6
- // light ones at equal (zero) specificity.
7
- :where(:root) {
8
- --color-primary-50: #ecf3f9;
9
- --color-primary-100: #d1e3f0;
10
- --color-primary-200: #abcbe3;
11
- --color-primary-300: #7dafd4;
12
- --color-primary-400: #4b91c3;
13
- --color-primary-500: #3674a1;
14
- --color-primary-600: #2a5b7e;
15
- --color-primary-700: #204560;
16
- --color-primary-800: #162f41;
17
- --color-primary-900: #0d1c26;
18
-
19
- --color-secondary-50: #f2eff5;
20
- --color-secondary-100: #dfd9e8;
21
- --color-secondary-200: #c4b9d5;
22
- --color-secondary-300: #a493be;
23
- --color-secondary-400: #8169a5;
24
- --color-secondary-500: #665086;
25
- --color-secondary-600: #503f69;
26
- --color-secondary-700: #3d3050;
27
- --color-secondary-800: #292136;
28
- --color-secondary-900: #181320;
29
-
30
- --color-neutral-0: #ffffff;
31
- --color-neutral-50: #f9fafb;
32
- --color-neutral-100: #f3f4f6;
33
- --color-neutral-200: #e5e7eb;
34
- --color-neutral-300: #d1d5db;
35
- --color-neutral-400: #9ca3af;
36
- --color-neutral-500: #6b7280;
37
- --color-neutral-600: #4b5563;
38
- --color-neutral-700: #374151;
39
- --color-neutral-800: #1f2937;
40
- --color-neutral-900: #111827;
41
- --color-neutral-950: #030712;
42
-
43
- --color-success-50: #f0fdf4;
44
- --color-success-100: #dcfce7;
45
- --color-success-200: #bbf7d0;
46
- --color-success-500: #22c55e;
47
- --color-success-600: #16a34a;
48
- --color-success-700: #15803d;
49
-
50
- --color-warning-50: #fffbeb;
51
- --color-warning-100: #fef3c7;
52
- --color-warning-200: #fde68a;
53
- --color-warning-500: #f59e0b;
54
- --color-warning-600: #d97706;
55
- --color-warning-700: #b45309;
56
-
57
- --color-error-50: #fef2f2;
58
- --color-error-100: #fee2e2;
59
- --color-error-200: #fecaca;
60
- --color-error-500: #ef4444;
61
- --color-error-600: #dc2626;
62
- --color-error-700: #b91c1c;
63
-
64
- --color-info-50: #ecfeff;
65
- --color-info-100: #cffafe;
66
- --color-info-200: #a5f3fc;
67
- --color-info-500: #06b6d4;
68
- --color-info-600: #0891b2;
69
- --color-info-700: #0e7490;
70
-
71
- --color-text-primary: var(--color-neutral-900);
72
- --color-text-secondary: var(--color-neutral-600);
73
- --color-text-tertiary: var(--color-neutral-400);
74
- --color-text-disabled: var(--color-neutral-400);
75
- --color-text-inverse: var(--color-neutral-0);
76
- --color-text-link: var(--color-primary-600);
77
- --color-text-link-hover: var(--color-primary-800);
78
-
79
- // Two-tier surfaces: bg-canvas is the page, bg-base is component surfaces on
80
- // it (inputs, cards, accordion, popovers). In dark mode bg-base lifts above
81
- // bg-canvas so surfaces don't vanish into the page.
82
- --color-bg-canvas: var(--color-neutral-0);
83
- --color-bg-base: var(--color-neutral-0);
84
- --color-bg-subtle: var(--color-neutral-50);
85
- --color-bg-stripe: var(--color-neutral-50);
86
- // Zebra-stripe fill for table rows: a mid-tone between the base row and the
87
- // header tint so striped rows read as lighter than the header, not identical to
88
- // it. Dark mode overrides the ratio to stay equally subtle.
89
- --color-bg-stripe-subtle: color-mix(
90
- in srgb,
91
- var(--color-bg-base) 30%,
92
- var(--color-bg-stripe)
93
- );
94
- --color-bg-muted: var(--color-neutral-100);
95
- // Soft neutral fill for placeholder surfaces (e.g. avatar initials) when no
96
- // image is set; light enough to sit gently on a white page
97
- --color-bg-emphasis: var(--color-neutral-100);
98
- --color-bg-elevated: var(--color-neutral-0);
99
- --color-bg-overlay: rgba(0, 0, 0, 0.5);
100
-
101
- // Tooltips float over arbitrary content, so their surface is a unique tone that
102
- // never matches a page or palette colour in either theme; the translucent
103
- // hairline border separates it from same-tone backgrounds.
104
- --color-tooltip-surface: #1a1b21;
105
- --color-tooltip-border: rgba(255, 255, 255, 0.15);
106
-
107
- // Interactive lift layers for hover and active/selected fills. Light surfaces
108
- // are all near-white and never collapse onto these shades, so solid muted
109
- // tones read cleanly. Dark mode swaps them for translucent washes (see the
110
- // dark overrides) because its surfaces all collapse onto the same neutrals,
111
- // where a solid fill would vanish into whatever it sits on.
112
- --color-state-hover: var(--color-neutral-100);
113
- --color-state-active: var(--color-neutral-200);
114
-
115
- --color-border-subtle: var(--color-neutral-200);
116
- --color-border-default: var(--color-neutral-200);
117
- --color-border-strong: var(--color-neutral-400);
118
- --color-divider: var(--color-border-subtle);
119
- --color-border-focus: var(--color-primary-500);
120
-
121
- // brand-default/-hover/-active are the brand colour as a surface (solid bg
122
- // under white text); needs 4.5:1 vs white. brand-text is the brand colour as
123
- // a foreground on a non-brand surface; needs 4.5:1 vs bg-base and flips
124
- // lighter in dark mode.
125
- --color-brand-default: var(--color-primary-600);
126
- --color-brand-hover: var(--color-primary-700);
127
- --color-brand-active: var(--color-primary-800);
128
- --color-brand-text: var(--color-primary-700);
129
- --color-brand-subtle: var(--color-primary-50);
130
- --color-brand-muted: var(--color-primary-100);
131
-
132
- --color-brand-secondary-default: var(--color-secondary-500);
133
- --color-brand-secondary-hover: var(--color-secondary-600);
134
- --color-brand-secondary-active: var(--color-secondary-700);
135
- --color-brand-secondary-subtle: var(--color-secondary-50);
136
- --color-brand-secondary-muted: var(--color-secondary-100);
137
-
138
- // *-text is the status hue as a foreground on its own *-subtle/-muted wash
139
- // (badge, tag, toast). It needs 4.5:1 vs that wash and flips lighter in dark
140
- // mode, mirroring --color-brand-text.
141
- --color-success-default: var(--color-success-600);
142
- --color-success-subtle: var(--color-success-50);
143
- --color-success-muted: var(--color-success-100);
144
- --color-success-text: var(--color-success-700);
145
-
146
- --color-warning-default: var(--color-warning-600);
147
- --color-warning-subtle: var(--color-warning-50);
148
- --color-warning-muted: var(--color-warning-100);
149
- --color-warning-text: var(--color-warning-700);
150
-
151
- --color-error-default: var(--color-error-600);
152
- --color-error-subtle: var(--color-error-50);
153
- --color-error-muted: var(--color-error-100);
154
- --color-error-text: var(--color-error-700);
155
-
156
- --color-info-default: var(--color-info-600);
157
- --color-info-subtle: var(--color-info-50);
158
- --color-info-muted: var(--color-info-100);
159
- --color-info-text: var(--color-info-700);
160
-
161
- // Pure RGB primaries for the picker's hue wheel and saturation/value
162
- // gradient. Intrinsic to the picker, not themeable; kept here so component
163
- // SCSS stays literal-free.
164
- --color-picker-hue-red: #ff0000;
165
- --color-picker-hue-yellow: #ffff00;
166
- --color-picker-hue-green: #00ff00;
167
- --color-picker-hue-cyan: #00ffff;
168
- --color-picker-hue-blue: #0000ff;
169
- --color-picker-hue-magenta: #ff00ff;
170
- --color-picker-sv-white: #ffffff;
171
- --color-picker-sv-black: #000000;
172
- --color-picker-thumb-halo: rgba(0, 0, 0, 0.25);
173
- }
174
-
175
- // Dark mode: applied when the OS prefers dark, unless forced light via
176
- // `<html data-theme="light">`. `<html data-theme="dark">` forces dark.
177
- @mixin dark-color-tokens {
178
- --color-text-primary: var(--color-neutral-50);
179
- --color-text-secondary: var(--color-neutral-300);
180
- --color-text-tertiary: var(--color-neutral-500);
181
- --color-text-disabled: var(--color-neutral-500);
182
- --color-text-inverse: var(--color-neutral-900);
183
- --color-text-link: var(--color-primary-300);
184
- --color-text-link-hover: var(--color-primary-100);
185
-
186
- // Canvas is the deepest page tone; bg-base and up lift component surfaces,
187
- // striped rows, floating surfaces, and hover states above it.
188
- --color-bg-canvas: var(--color-neutral-950);
189
- --color-bg-base: var(--color-neutral-800);
190
- --color-bg-subtle: var(--color-neutral-700);
191
- --color-bg-stripe: var(--color-neutral-900);
192
- // The dark base-to-stripe gap reads stronger than the light one, so weight the
193
- // stripe mix toward the base row to keep zebra striping subtle.
194
- --color-bg-stripe-subtle: color-mix(
195
- in srgb,
196
- var(--color-bg-base) 62.5%,
197
- var(--color-bg-stripe)
198
- );
199
- --color-bg-elevated: var(--color-neutral-700);
200
- // Opaque muted surface for static fills (disabled fields, slider/progress
201
- // tracks, skeletons). Hover/active fills route through the translucent
202
- // --color-state-* tokens instead, so they never collide with this shade.
203
- --color-bg-muted: var(--color-neutral-700);
204
- --color-bg-emphasis: var(--color-neutral-600);
205
-
206
- // White wash so an interactive lift reads on any dark surface, including the
207
- // neutral-700 tier where bg-muted/-subtle/-elevated all coincide. This is the
208
- // fix that lets dropdown/menu/dialog hovers lift off their elevated surfaces.
209
- --color-state-hover: rgba(255, 255, 255, 0.08);
210
- --color-state-active: rgba(255, 255, 255, 0.14);
211
-
212
- // Borders stay clear of every bg-* shade so they stay visible. subtle mixes
213
- // neutral-700/-800 to sit between card and cell backgrounds; default can't go
214
- // darker without colliding with bg-subtle/-elevated (both neutral-700).
215
- --color-border-subtle: color-mix(
216
- in srgb,
217
- var(--color-neutral-700),
218
- var(--color-neutral-800)
219
- );
220
- --color-border-default: var(--color-neutral-400);
221
- --color-border-strong: var(--color-neutral-300);
222
- // Dividers read as barely-there against dark surfaces at border-subtle, so
223
- // they step one neutral lighter for a visible-but-quiet rule.
224
- --color-divider: var(--color-neutral-600);
225
-
226
- // Surface roles step one shade lighter than light mode so the button clears
227
- // WCAG 1.4.11 (3:1) on the near-black canvas while keeping a white label
228
- // above 4.5:1.
229
- --color-brand-default: var(--color-primary-500);
230
- --color-brand-hover: var(--color-primary-600);
231
- --color-brand-active: var(--color-primary-700);
232
- --color-brand-text: var(--color-primary-300);
233
- --color-brand-subtle: rgba(75, 145, 195, 0.1);
234
- --color-brand-muted: rgba(75, 145, 195, 0.2);
235
-
236
- // Light pastels become unreadable behind light text in dark mode. Re-tint as
237
- // a low-alpha wash of the saturated *-500 hue so the surface darkens enough
238
- // for white text.
239
- --color-success-subtle: rgba(34, 197, 94, 0.15);
240
- --color-success-muted: rgba(34, 197, 94, 0.25);
241
- --color-warning-subtle: rgba(245, 158, 11, 0.15);
242
- --color-warning-muted: rgba(245, 158, 11, 0.25);
243
- --color-error-subtle: rgba(239, 68, 68, 0.15);
244
- --color-error-muted: rgba(239, 68, 68, 0.25);
245
- --color-info-subtle: rgba(6, 182, 212, 0.15);
246
- --color-info-muted: rgba(6, 182, 212, 0.25);
247
-
248
- // The *-700 shades are unreadable on the dark translucent washes above; flip
249
- // to the light *-200 pastels so status text keeps 4.5:1.
250
- --color-success-text: var(--color-success-200);
251
- --color-warning-text: var(--color-warning-200);
252
- --color-error-text: var(--color-error-200);
253
- --color-info-text: var(--color-info-200);
254
- }
255
-
256
- @media (prefers-color-scheme: dark) {
257
- :where(:root:not([data-theme='light'])) {
258
- @include dark-color-tokens;
259
- }
260
- }
261
-
262
- :where(:root[data-theme='dark']) {
263
- @include dark-color-tokens;
264
- color-scheme: dark;
265
- }
@@ -1,87 +0,0 @@
1
- // :where() keeps these at zero specificity so consumer overrides win in every
2
- // theme; see the note in _colors.scss.
3
- :where(:root) {
4
- --shadow-none: none;
5
- --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
6
- --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
7
- --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
8
- --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
9
- --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
10
- --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
11
- --shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
12
-
13
- // Composable top-edge highlight appended to every dark-mode shadow so elevated
14
- // surfaces catch light along their top edge; a no-op in light mode.
15
- --shadow-edge-highlight: 0 0 #0000;
16
-
17
- // Bevel: paired inset highlight (top) + shadow (bottom) for a raised look;
18
- // compose with --shadow-* for an ambient drop.
19
- --shadow-bevel:
20
- inset 0 1px 1px rgba(255, 255, 255, 0.85), inset 0 -1px 1.5px rgba(0, 0, 0, 0.25);
21
- --shadow-bevel-strong:
22
- inset 0 1.5px 2px rgba(255, 255, 255, 0.9), inset 0 -2px 3px rgba(0, 0, 0, 0.3);
23
-
24
- // Well: inverse of bevel (inset shadow top, highlight bottom) for a recessed look
25
- --shadow-well:
26
- inset 0 1px 1.5px rgba(0, 0, 0, 0.3), inset 0 -1px 0.5px rgba(255, 255, 255, 0.5);
27
- --shadow-well-strong:
28
- inset 0 2px 3px rgba(0, 0, 0, 0.4), inset 0 -1.5px 1px rgba(255, 255, 255, 0.55);
29
-
30
- --shadow-focus-ring: 0 0 0 3px rgba(59, 130, 246, 0.45);
31
- --shadow-focus-ring-error: 0 0 0 3px var(--color-error-200);
32
- --shadow-focus-ring-success: 0 0 0 3px var(--color-success-200);
33
-
34
- --z-index-base: 0;
35
- --z-index-raised: 10;
36
- --z-index-dropdown: 100;
37
- --z-index-sticky: 200;
38
- --z-index-overlay: 300;
39
- --z-index-modal: 400;
40
- --z-index-popover: 500;
41
- --z-index-toast: 600;
42
- --z-index-tooltip: 700;
43
- }
44
-
45
- // Dark mode: a drop shadow is the absence of light, so it stays black (deeper
46
- // than light mode); a white "shadow" reads as a glow and looks wrong. Elevation
47
- // is carried instead by the lifted surface tone plus a hairline top highlight
48
- // that catches light, appended to every level via --shadow-edge-highlight.
49
- @mixin dark-elevation-tokens {
50
- --shadow-edge-highlight: inset 0 1px 0 0 rgba(255, 255, 255, 0.06);
51
-
52
- --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.4), var(--shadow-edge-highlight);
53
- --shadow-sm:
54
- 0 1px 3px 0 rgba(0, 0, 0, 0.5), 0 1px 2px -1px rgba(0, 0, 0, 0.4),
55
- var(--shadow-edge-highlight);
56
- --shadow-md:
57
- 0 4px 8px -2px rgba(0, 0, 0, 0.55), 0 2px 4px -2px rgba(0, 0, 0, 0.4),
58
- var(--shadow-edge-highlight);
59
- --shadow-lg:
60
- 0 12px 20px -4px rgba(0, 0, 0, 0.6), 0 4px 8px -4px rgba(0, 0, 0, 0.45),
61
- var(--shadow-edge-highlight);
62
- --shadow-xl:
63
- 0 20px 28px -6px rgba(0, 0, 0, 0.65), 0 8px 12px -6px rgba(0, 0, 0, 0.5),
64
- var(--shadow-edge-highlight);
65
- --shadow-2xl: 0 28px 50px -12px rgba(0, 0, 0, 0.75), var(--shadow-edge-highlight);
66
-
67
- // On a dark surface a bright highlight reads as a halo, so drop the highlight
68
- // alpha and raise the shadow alpha to keep the relief without glowing.
69
- --shadow-bevel:
70
- inset 0 1px 1px rgba(255, 255, 255, 0.18), inset 0 -1px 1.5px rgba(0, 0, 0, 0.6);
71
- --shadow-bevel-strong:
72
- inset 0 1.5px 2px rgba(255, 255, 255, 0.22), inset 0 -2px 3px rgba(0, 0, 0, 0.7);
73
- --shadow-well:
74
- inset 0 1px 1.5px rgba(0, 0, 0, 0.55), inset 0 -1px 0.5px rgba(255, 255, 255, 0.08);
75
- --shadow-well-strong:
76
- inset 0 2px 3px rgba(0, 0, 0, 0.7), inset 0 -1.5px 1px rgba(255, 255, 255, 0.12);
77
- }
78
-
79
- @media (prefers-color-scheme: dark) {
80
- :where(:root:not([data-theme='light'])) {
81
- @include dark-elevation-tokens;
82
- }
83
- }
84
-
85
- :where(:root[data-theme='dark']) {
86
- @include dark-elevation-tokens;
87
- }
@@ -1,6 +0,0 @@
1
- @forward 'colors';
2
- @forward 'typography';
3
- @forward 'spacing';
4
- @forward 'shape';
5
- @forward 'elevation';
6
- @forward 'motion';
@@ -1,37 +0,0 @@
1
- // :where() keeps tokens at zero specificity so consumer overrides win; see _colors.scss.
2
- :where(:root) {
3
- --duration-instant: 0ms;
4
- --duration-fast: 100ms;
5
- --duration-normal: 200ms;
6
- --duration-slow: 300ms;
7
- --duration-slower: 500ms;
8
-
9
- --ease-linear: linear;
10
- --ease-in: cubic-bezier(0.4, 0, 1, 1);
11
- --ease-out: cubic-bezier(0, 0, 0.2, 1);
12
- --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
13
- --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
14
-
15
- --transition-colors:
16
- color var(--duration-fast) var(--ease-out),
17
- background-color var(--duration-fast) var(--ease-out),
18
- border-color var(--duration-fast) var(--ease-out),
19
- fill var(--duration-fast) var(--ease-out);
20
-
21
- --transition-shadow: box-shadow var(--duration-fast) var(--ease-out);
22
-
23
- --transition-transform: transform var(--duration-normal) var(--ease-spring);
24
-
25
- --transition-opacity: opacity var(--duration-normal) var(--ease-out);
26
-
27
- --transition-all: all var(--duration-normal) var(--ease-in-out);
28
- }
29
-
30
- @media (prefers-reduced-motion: reduce) {
31
- :where(:root) {
32
- --duration-fast: 0ms;
33
- --duration-normal: 0ms;
34
- --duration-slow: 0ms;
35
- --duration-slower: 0ms;
36
- }
37
- }
@@ -1,23 +0,0 @@
1
- // :where() keeps tokens at zero specificity so consumer overrides win; see _colors.scss.
2
- :where(:root) {
3
- --radius-none: 0;
4
- --radius-xs: 0.125rem; // 2px
5
- --radius-sm: 0.25rem; // 4px
6
- --radius-md: 0.375rem; // 6px
7
- --radius-lg: 0.5rem; // 8px
8
- --radius-xl: 0.75rem; // 12px
9
- --radius-2xl: 1rem; // 16px
10
- --radius-3xl: 1.5rem; // 24px
11
- --radius-full: 9999px; // pill / circle
12
-
13
- --border-width-none: 0;
14
- --border-width-thin: 1px;
15
- --border-width-medium: 2px;
16
- --border-width-thick: 4px;
17
-
18
- // Hit-target box for icon buttons (clear / close / dismiss / toggle). em-based
19
- // so it scales with the host component's size; since all sized components share
20
- // a font-size per tier, this is also consistent across components at a tier
21
- // (md = 1.75 * 16px = 28px).
22
- --ea-icon-button-size: 1.75em;
23
- }
@@ -1,73 +0,0 @@
1
- // :where() keeps tokens at zero specificity so consumer overrides win; see _colors.scss.
2
- :where(:root) {
3
- --space-0: 0;
4
- --space-px: 1px;
5
- --space-0-5: 0.125rem; // 2px
6
- --space-1: 0.25rem; // 4px
7
- --space-1-5: 0.375rem; // 6px
8
- --space-2: 0.5rem; // 8px
9
- --space-2-5: 0.625rem; // 10px
10
- --space-3: 0.75rem; // 12px
11
- --space-3-5: 0.875rem; // 14px
12
- --space-4: 1rem; // 16px
13
- --space-5: 1.25rem; // 20px
14
- --space-6: 1.5rem; // 24px
15
- --space-7: 1.75rem; // 28px
16
- --space-8: 2rem; // 32px
17
- --space-9: 2.25rem; // 36px
18
- --space-10: 2.5rem; // 40px
19
- --space-11: 2.75rem; // 44px
20
- --space-12: 3rem; // 48px
21
- --space-14: 3.5rem; // 56px
22
- --space-16: 4rem; // 64px
23
- --space-20: 5rem; // 80px
24
- --space-24: 6rem; // 96px
25
- --space-32: 8rem; // 128px
26
-
27
- // Negative variants mirror the scale (n- infix) so consumers skip
28
- // `calc(var(--space-2) * -1)` for negative margins.
29
- --space-n-px: -1px;
30
- --space-n-0-5: -0.125rem; // -2px
31
- --space-n-1: -0.25rem; // -4px
32
- --space-n-1-5: -0.375rem; // -6px
33
- --space-n-2: -0.5rem; // -8px
34
- --space-n-2-5: -0.625rem; // -10px
35
- --space-n-3: -0.75rem; // -12px
36
- --space-n-3-5: -0.875rem; // -14px
37
- --space-n-4: -1rem; // -16px
38
- --space-n-5: -1.25rem; // -20px
39
- --space-n-6: -1.5rem; // -24px
40
- --space-n-7: -1.75rem; // -28px
41
- --space-n-8: -2rem; // -32px
42
- --space-n-9: -2.25rem; // -36px
43
- --space-n-10: -2.5rem; // -40px
44
- --space-n-11: -2.75rem; // -44px
45
- --space-n-12: -3rem; // -48px
46
- --space-n-14: -3.5rem; // -56px
47
- --space-n-16: -4rem; // -64px
48
- --space-n-20: -5rem; // -80px
49
- --space-n-24: -6rem; // -96px
50
- --space-n-32: -8rem; // -128px
51
-
52
- --inset-xs: var(--space-1) var(--space-2); // 4px 8px
53
- --inset-sm: var(--space-1-5) var(--space-3); // 6px 12px
54
- --inset-md: var(--space-2) var(--space-4); // 8px 16px
55
- --inset-lg: var(--space-3) var(--space-6); // 12px 24px
56
- --inset-xl: var(--space-4) var(--space-8); // 16px 32px
57
-
58
- // vertical gap
59
- --stack-2xs: var(--space-1); // 4px
60
- --stack-xs: var(--space-2); // 8px
61
- --stack-sm: var(--space-3); // 12px
62
- --stack-md: var(--space-4); // 16px
63
- --stack-lg: var(--space-6); // 24px
64
- --stack-xl: var(--space-8); // 32px
65
- --stack-2xl: var(--space-12); // 48px
66
-
67
- // horizontal gap
68
- --inline-2xs: var(--space-1); // 4px
69
- --inline-xs: var(--space-2); // 8px
70
- --inline-sm: var(--space-3); // 12px
71
- --inline-md: var(--space-4); // 16px
72
- --inline-lg: var(--space-6); // 24px
73
- }
@@ -1,147 +0,0 @@
1
- // :where() keeps tokens at zero specificity so consumer overrides win; see _colors.scss.
2
- :where(:root) {
3
- // The `* Fallback` faces are Arial tuned with metric overrides to match the
4
- // web fonts, so they must sit right after each web font in the stack: that way
5
- // text laid out before the font loads has the same metrics and `font-display:
6
- // swap` causes no layout shift when the real font arrives.
7
- --font-family-sans:
8
- 'DM Sans', 'DM Sans Fallback', 'Segoe UI', system-ui, -apple-system, sans-serif;
9
- --font-family-brand:
10
- 'Syne', 'Syne Fallback', 'DM Sans', 'DM Sans Fallback', system-ui, sans-serif;
11
- --font-family-serif: 'Georgia', 'Times New Roman', serif;
12
- --font-family-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
13
-
14
- --font-size-2xs: 0.625rem; // 10px
15
- --font-size-xs: 0.75rem; // 12px
16
- --font-size-sm: 0.875rem; // 14px
17
- --font-size-md: 1rem; // 16px
18
- --font-size-lg: 1.125rem; // 18px
19
- --font-size-xl: 1.25rem; // 20px
20
- --font-size-2xl: 1.5rem; // 24px
21
- --font-size-3xl: 1.875rem; // 30px
22
- --font-size-4xl: 2.25rem; // 36px
23
- --font-size-5xl: 3rem; // 48px
24
-
25
- --font-weight-regular: 400;
26
- --font-weight-medium: 500;
27
- --font-weight-semibold: 600;
28
- --font-weight-bold: 700;
29
- --font-weight-extrabold: 800;
30
-
31
- --line-height-none: 1;
32
- --line-height-tight: 1.25;
33
- --line-height-snug: 1.375;
34
- --line-height-normal: 1.5;
35
- --line-height-relaxed: 1.625;
36
- --line-height-loose: 2;
37
-
38
- --letter-spacing-tighter: -0.05em;
39
- --letter-spacing-tight: -0.025em;
40
- --letter-spacing-normal: 0em;
41
- --letter-spacing-wide: 0.025em;
42
- --letter-spacing-wider: 0.05em;
43
- --letter-spacing-widest: 0.1em;
44
-
45
- // Leading/status icon sized relative to the text beside it; em keeps it in
46
- // proportion as the surrounding font-size changes
47
- --icon-inline-size: 1.5em;
48
-
49
- --text-display-size: var(--font-size-5xl);
50
- --text-display-weight: var(--font-weight-bold);
51
- --text-display-lh: var(--line-height-tight);
52
-
53
- --text-h1-size: var(--font-size-4xl);
54
- --text-h1-weight: var(--font-weight-bold);
55
- --text-h1-lh: var(--line-height-tight);
56
-
57
- --text-h2-size: var(--font-size-3xl);
58
- --text-h2-weight: var(--font-weight-semibold);
59
- --text-h2-lh: var(--line-height-snug);
60
-
61
- --text-h3-size: var(--font-size-2xl);
62
- --text-h3-weight: var(--font-weight-semibold);
63
- --text-h3-lh: var(--line-height-snug);
64
-
65
- --text-h4-size: var(--font-size-xl);
66
- --text-h4-weight: var(--font-weight-semibold);
67
- --text-h4-lh: var(--line-height-snug);
68
-
69
- // Page-level subsection title (an `<h2>` under the page `<h1>`). Mirrors
70
- // `--text-h4-*` metrics but pins the brand family so it reads as wordmark,
71
- // not body. Only composite that pins a font-family.
72
- --text-section-heading-size: var(--font-size-xl);
73
- --text-section-heading-weight: var(--font-weight-semibold);
74
- --text-section-heading-lh: var(--line-height-snug);
75
- --text-section-heading-family: var(--font-family-brand);
76
-
77
- --text-body-lg-size: var(--font-size-lg);
78
- --text-body-lg-weight: var(--font-weight-regular);
79
- --text-body-lg-lh: var(--line-height-relaxed);
80
-
81
- --text-body-md-size: var(--font-size-md);
82
- --text-body-md-weight: var(--font-weight-regular);
83
- --text-body-md-lh: var(--line-height-normal);
84
-
85
- --text-body-sm-size: var(--font-size-sm);
86
- --text-body-sm-weight: var(--font-weight-regular);
87
- --text-body-sm-lh: var(--line-height-normal);
88
-
89
- --text-label-lg-size: var(--font-size-md);
90
- --text-label-lg-weight: var(--font-weight-medium);
91
- --text-label-lg-lh: var(--line-height-tight);
92
-
93
- --text-label-md-size: var(--font-size-sm);
94
- --text-label-md-weight: var(--font-weight-medium);
95
- --text-label-md-lh: var(--line-height-tight);
96
-
97
- --text-label-sm-size: var(--font-size-xs);
98
- --text-label-sm-weight: var(--font-weight-medium);
99
- --text-label-sm-lh: var(--line-height-tight);
100
-
101
- // Helper / caption: subordinate text below a component's primary content.
102
- // 13px (between --font-size-xs 12px and -sm 14px) so it stays subordinate
103
- // without hitting the barely-readable 12px floor. Used for field hint and
104
- // error messages (see standard below) and short metadata such as a
105
- // file-uploader's constraints or per-file size labels.
106
- //
107
- // Standard: every form-like component (anything exposing `errorMsg` and/or
108
- // `hint`) must render its messages identically. Mirror `<ea-input>`:
109
- // 1. `<p class="ea-{name}-field__message ea-{name}-field__message--error">`
110
- // (or `--hint`) with `role="alert"` on the error variant and an `id`
111
- // matching the field's `aria-describedby`.
112
- // 2. The first child of the error `<p>` is always
113
- // `<ea-icon-alert-circle class="ea-{name}-field__message-icon" />`.
114
- // Hints render text-only (no icon).
115
- // 3. `__message` uses `display: flex; align-items: center; gap: var(--space-1)`
116
- // plus the three `--text-helper-*` tokens above. Never hard-code a
117
- // font-size on `__message`.
118
- // 4. `__message-icon` uses `flex-shrink: 0; width: 0.875em; height: 0.875em`
119
- // so the icon scales with the text.
120
- // 5. Error color is `var(--color-error-default)`. Hint color is component-
121
- // specific (`--color-text-secondary` or `inherit`) but stays consistent
122
- // within a component.
123
- // 6. `AlertCircleIconComponent` must be in the component's `imports: [...]`.
124
- --text-helper-size: 0.8125rem; // 13px
125
- --text-helper-weight: var(--font-weight-regular);
126
- --text-helper-lh: var(--line-height-normal);
127
-
128
- // Inline code chip; em-sized so it tracks the surrounding text
129
- --text-code-size: 0.875em;
130
- --text-code-weight: var(--font-weight-regular);
131
- --text-code-family: var(--font-family-mono);
132
- --text-code-color: var(--color-text-primary);
133
- --text-code-bg: var(--color-bg-muted);
134
- --text-code-padding: var(--space-0-5) var(--space-1-5); // 2px 6px
135
- --text-code-radius: var(--radius-sm);
136
-
137
- // Keyboard-key glyph; raised border + bottom shadow suggest a physical key
138
- --text-kbd-size: 0.8125em;
139
- --text-kbd-weight: var(--font-weight-medium);
140
- --text-kbd-family: var(--font-family-mono);
141
- --text-kbd-color: var(--color-text-primary);
142
- --text-kbd-bg: var(--color-bg-base);
143
- --text-kbd-border: var(--border-width-thin) solid var(--color-border-default);
144
- --text-kbd-padding: var(--space-0-5) var(--space-1-5); // 2px 6px
145
- --text-kbd-radius: var(--radius-sm);
146
- --text-kbd-shadow: 0 1px 0 var(--color-border-default);
147
- }