@apliteni/apliteni-ui 0.8.1 → 0.9.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/package.json +1 -1
- package/src/components/index.js +8 -0
- package/src/components/success.js +10 -0
- package/src/components/topbar.js +28 -7
- package/src/index.js +2 -0
- package/src/inline.js +2 -0
- package/src/styles/badge.css +5 -2
- package/src/styles/base.css +11 -3
- package/src/styles/callout.css +37 -19
- package/src/styles/dropdown.css +1 -1
- package/src/styles/empty.css +8 -3
- package/src/styles/nav.css +11 -7
- package/src/styles/topbar.css +1 -1
- package/src/tokens/tokens.css +76 -10
package/package.json
CHANGED
package/src/components/index.js
CHANGED
|
@@ -235,6 +235,14 @@ export function toast({
|
|
|
235
235
|
+ `<div class="ui-toast__body">${title ? `<div class="ui-toast__title">${esc(title)}</div>` : ''}${bodyHtml}</div>`
|
|
236
236
|
+ `${actBtn}${closeBtn}${timerBar}</div>`;
|
|
237
237
|
}
|
|
238
|
+
// The inline confirmation. A check, a title and one line of sub, dropped into
|
|
239
|
+
// the page the user is already on — under a form that just submitted, or inside
|
|
240
|
+
// a card. Two strings, no options; styles are .ui-success in styles/callout.css.
|
|
241
|
+
//
|
|
242
|
+
// The kit also publishes success() from components/success.js, which is the same
|
|
243
|
+
// idea at page size: layouts, a backdrop, follow-up buttons and an auto-redirect
|
|
244
|
+
// countdown. Pick by how much of the screen the confirmation owns. The two share
|
|
245
|
+
// no CSS, so changing one never moves the other.
|
|
238
246
|
export function successPanel({ title = 'Done', sub = '' } = {}) {
|
|
239
247
|
return `<div class="ui-success"><div class="ui-success__check">${icon('check')}</div><div class="ui-success__title">${esc(title)}</div>${sub ? `<div class="ui-success__sub">${esc(sub)}</div>` : ''}</div>`;
|
|
240
248
|
}
|
|
@@ -61,6 +61,16 @@ function countdownEl({ seconds = 5, label = 'Redirecting' } = {}) {
|
|
|
61
61
|
</div>`;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// The page-sized confirmation — what a flow lands on once it is over. It fills
|
|
65
|
+
// the space it is given, and carries the things a screen needs that a block does
|
|
66
|
+
// not: somewhere to go next, and optionally a countdown that takes the user
|
|
67
|
+
// there.
|
|
68
|
+
//
|
|
69
|
+
// For a confirmation that stays inside the page the user is already on, the kit
|
|
70
|
+
// publishes successPanel() from components/index.js — a check, a title and one
|
|
71
|
+
// line of sub, and nothing to configure. Pick by how much of the screen the
|
|
72
|
+
// confirmation owns. The two share no CSS (.ui-sx here, .ui-success there), so
|
|
73
|
+
// changing one never moves the other.
|
|
64
74
|
export function success({
|
|
65
75
|
layout = 'hero', // 'hero' | 'split' | 'compact'
|
|
66
76
|
backdrop = 'aurora', // 'aurora' | 'glow' | 'flat'
|
package/src/components/topbar.js
CHANGED
|
@@ -7,10 +7,28 @@ import { wireDropdown } from './dropdown.js';
|
|
|
7
7
|
|
|
8
8
|
const THEME_KEY = 'apliteni-strategy-theme';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
// A stateful control in this kit reports the state it is IN, never the state a
|
|
11
|
+
// click would produce — the same reading as segmented()'s aria-pressed, the
|
|
12
|
+
// Deck/Text switch's aria-current, and the accent chips. So: moon while dark,
|
|
13
|
+
// sun while light. Storybook's own toolbar toggle (.storybook/theme-toggle.jsx)
|
|
14
|
+
// reads the same way, and topbar stories render directly beneath it.
|
|
15
|
+
export const themeIcon = (t) => (t === 'light' ? sun : moon);
|
|
16
|
+
|
|
17
|
+
// The name carries both the state and what the click does, which is why there
|
|
18
|
+
// is no aria-pressed and no role="switch": dark and light are peers, not on and
|
|
19
|
+
// off, and an ARIA state on top of this name would announce the theme twice.
|
|
20
|
+
// The button is icon-only, so `title` is the only sighted reading of the same
|
|
21
|
+
// fact and carries the identical string — nothing for WCAG 2.5.3 to disagree
|
|
22
|
+
// with. Both are rewritten by applyTheme on every flip; a name that is right
|
|
23
|
+
// once and never again tells a screen-reader user nothing.
|
|
24
|
+
export const themeName = (t) =>
|
|
25
|
+
(t === 'light' ? 'Theme: Light. Switch to dark.' : 'Theme: Dark. Switch to light.');
|
|
26
|
+
|
|
27
|
+
export function themeToggle(theme = 'dark') {
|
|
28
|
+
// Single icon-only switch. Icon and name are pre-filled for `theme` so the
|
|
29
|
+
// first paint is already truthful; applyTheme() keeps them so afterwards.
|
|
30
|
+
const name = esc(themeName(theme));
|
|
31
|
+
return `<button class="toggle" data-theme-toggle aria-label="${name}" title="${name}"><span class="ic" data-theme-icon>${themeIcon(theme)}</span></button>`;
|
|
14
32
|
}
|
|
15
33
|
|
|
16
34
|
export function deckTextSwitch(active = 'deck') {
|
|
@@ -69,11 +87,14 @@ export function topbar({
|
|
|
69
87
|
// ---- Behaviours (call once after markup mounts) --------------------------
|
|
70
88
|
export function applyTheme(t, root = document.documentElement) {
|
|
71
89
|
root.setAttribute('data-theme', t);
|
|
90
|
+
const name = themeName(t);
|
|
72
91
|
root.querySelectorAll('[data-theme-toggle]').forEach((btn) => {
|
|
73
92
|
const ic = btn.querySelector('[data-theme-icon]');
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
if (ic) ic.innerHTML = themeIcon(t);
|
|
94
|
+
// The announced name is the point of the control, so it moves with the
|
|
95
|
+
// theme like the glyph does.
|
|
96
|
+
btn.setAttribute('aria-label', name);
|
|
97
|
+
btn.setAttribute('title', name);
|
|
77
98
|
});
|
|
78
99
|
try { localStorage.setItem(THEME_KEY, t); } catch (e) { /* no-op */ }
|
|
79
100
|
}
|
package/src/index.js
CHANGED
|
@@ -7,8 +7,10 @@ export * from './components/nav.js';
|
|
|
7
7
|
export * from './components/drawer.js';
|
|
8
8
|
export * from './components/topbar.js';
|
|
9
9
|
export * from './components/shell.js';
|
|
10
|
+
export * from './components/footer.js';
|
|
10
11
|
export * from './components/feedback.js';
|
|
11
12
|
export * from './components/toasts.js';
|
|
13
|
+
export * from './components/success.js';
|
|
12
14
|
export * from './assets/icons.js';
|
|
13
15
|
export * from './assets/brand.js';
|
|
14
16
|
export * from './motion.js';
|
package/src/inline.js
CHANGED
|
@@ -39,6 +39,7 @@ export const styles = {
|
|
|
39
39
|
nav: read('styles/nav.css'),
|
|
40
40
|
drawer: read('styles/drawer.css'),
|
|
41
41
|
table: read('styles/table.css'),
|
|
42
|
+
empty: read('styles/empty.css'),
|
|
42
43
|
callout: read('styles/callout.css'),
|
|
43
44
|
code: read('styles/code.css'),
|
|
44
45
|
topbar: topbarCss,
|
|
@@ -63,6 +64,7 @@ export const cssText = [
|
|
|
63
64
|
styles.nav,
|
|
64
65
|
styles.drawer,
|
|
65
66
|
styles.table,
|
|
67
|
+
styles.empty,
|
|
66
68
|
styles.callout,
|
|
67
69
|
styles.code,
|
|
68
70
|
styles.topbar,
|
package/src/styles/badge.css
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
wash out and the ink has to deepen to clear AA, and that is a token decision. */
|
|
25
25
|
.ui-badge--live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
26
26
|
.ui-badge--soon { color: var(--purple-mid); background: var(--glow-purple); }
|
|
27
|
-
.ui-badge--info { color: var(--
|
|
27
|
+
.ui-badge--info { color: var(--chip-info-ink); background: var(--chip-info-fill); }
|
|
28
28
|
.ui-badge--warn { color: var(--chip-warn-ink); background: var(--chip-warn-fill); }
|
|
29
29
|
.ui-badge--danger { color: var(--chip-danger-ink); background: var(--chip-danger-fill); }
|
|
30
30
|
.ui-badge--archive { color: var(--muted); background: var(--surface); }
|
|
@@ -54,7 +54,10 @@
|
|
|
54
54
|
padding: 4px 11px;
|
|
55
55
|
font-weight: var(--weight-semibold);
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
/* The live pill is the same status paint as the live badge, so it takes the
|
|
58
|
+
same pair. On its own it was --green on --glow-green, which is 3.97:1 over
|
|
59
|
+
white — under AA, while the badge beside it cleared at 4.64:1. See issue #131. */
|
|
60
|
+
.ui-pill--live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
58
61
|
.ui-pill--soon { color: var(--purple-mid); background: var(--glow-purple); }
|
|
59
62
|
|
|
60
63
|
/* Status dot */
|
package/src/styles/base.css
CHANGED
|
@@ -101,9 +101,17 @@ a {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/* Sensible default size for inline icons that a parent rule doesn't size.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
A floor, not a ceiling: :where() holds the whole filter at zero specificity,
|
|
105
|
+
so this weighs (0,0,1) — one element, nothing more — and any component rule
|
|
106
|
+
that sizes an icon outranks it. Written bare, :not([width]):not([height])
|
|
107
|
+
would count both attribute selectors and weigh (0,2,1), which beats every
|
|
108
|
+
`.ui-btn svg`-shaped rule in the kit no matter what order the files load in.
|
|
109
|
+
It did, for every one of them bar three, and for `.ui-fbck` besides — that
|
|
110
|
+
one is a class on the svg itself, so it is easy to miss when you go looking.
|
|
111
|
+
The count is deliberately not written here: it moved once already, and the
|
|
112
|
+
rules outside this package (site/, the Iconography story) are not in it.
|
|
113
|
+
src/styles/icon-size.test.js keeps the ones in src/styles honest. */
|
|
114
|
+
svg:where(:not([width]):not([height])) {
|
|
107
115
|
width: 1.1em;
|
|
108
116
|
height: 1.1em;
|
|
109
117
|
flex: none;
|
package/src/styles/callout.css
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
/* ----------------------------------------------------------------------------
|
|
30
30
|
* Toast — a floating, dismissible notification.
|
|
31
31
|
* A status (colour) × style (surface) matrix, entirely token-driven:
|
|
32
|
-
* status success · danger · warn · info · neutral → sets --toast-accent/-glow/-on
|
|
32
|
+
* status success · danger · warn · info · neutral → sets --toast-accent/-glow/-on/-solid
|
|
33
33
|
* style soft (tinted) · solid (filled) · outline (bordered)
|
|
34
34
|
* -------------------------------------------------------------------------- */
|
|
35
35
|
.ui-toast {
|
|
@@ -47,13 +47,16 @@
|
|
|
47
47
|
animation: ui-toast-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
/* status → the paint tokens every style below consumes
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.ui-toast--
|
|
56
|
-
.ui-toast--
|
|
50
|
+
/* status → the paint tokens every style below consumes.
|
|
51
|
+
--toast-accent is the status as a line or a small mark, --toast-glow its wash,
|
|
52
|
+
--toast-on the glyph ink on the accent circle. --toast-solid is separate on
|
|
53
|
+
purpose: a full fill is a different job from a 22px circle, and it is chosen
|
|
54
|
+
as a PAIR with --signal-solid-ink rather than against a global. See #149. */
|
|
55
|
+
.ui-toast--success { --toast-accent: var(--green); --toast-glow: var(--glow-green); --toast-on: var(--signal-contrast); --toast-solid: var(--signal-solid-success); }
|
|
56
|
+
.ui-toast--danger { --toast-accent: var(--pink); --toast-glow: var(--glow-pink); --toast-on: var(--danger-contrast); --toast-solid: var(--signal-solid-danger); }
|
|
57
|
+
.ui-toast--warn { --toast-accent: var(--amber); --toast-glow: color-mix(in srgb, var(--amber) 14%, transparent); --toast-on: var(--signal-contrast); --toast-solid: var(--signal-solid-warn); }
|
|
58
|
+
.ui-toast--info { --toast-accent: var(--cyan); --toast-glow: var(--glow-cyan); --toast-on: var(--signal-contrast); --toast-solid: var(--signal-solid-info); }
|
|
59
|
+
.ui-toast--neutral { --toast-accent: var(--muted); --toast-glow: var(--surface-2); --toast-on: var(--strong); --toast-solid: var(--signal-solid-neutral); }
|
|
57
60
|
|
|
58
61
|
/* left status marker (soft + outline; solid is already a full fill) */
|
|
59
62
|
.ui-toast--soft::before,
|
|
@@ -83,17 +86,32 @@
|
|
|
83
86
|
/* style: soft — tinted surface */
|
|
84
87
|
.ui-toast--soft { background: var(--toast-glow); box-shadow: var(--shadow-sm); }
|
|
85
88
|
|
|
86
|
-
/* style: solid —
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
.ui-toast--solid
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
/* style: solid — the status at fill strength, inked with the pole opposite it.
|
|
90
|
+
The fill and the ink are one pair, taken together from --signal-solid-*: dark
|
|
91
|
+
fills are the bright signals and take near-black, light fills are the deepened
|
|
92
|
+
ones and take white. What this replaced picked the fill from the status and
|
|
93
|
+
the ink from one of two globals, on independent axes, so nothing made them
|
|
94
|
+
clear each other — and four of the ten status x theme combinations did not.
|
|
95
|
+
Gated for all ten in stories/signal-contrast.test.js. See #149. */
|
|
96
|
+
.ui-toast--solid {
|
|
97
|
+
--toast-ink: var(--signal-solid-ink);
|
|
98
|
+
background: var(--toast-solid);
|
|
99
|
+
color: var(--toast-ink);
|
|
100
|
+
box-shadow: var(--shadow-lg);
|
|
101
|
+
}
|
|
102
|
+
.ui-toast--solid .ui-toast__title { color: var(--toast-ink); }
|
|
103
|
+
/* The body copy is the quieter of the two, but it stays quiet by dilution the
|
|
104
|
+
pair can carry: 90% of the ink measures 4.71 on the worst fill in the matrix
|
|
105
|
+
(--chip-success-ink in light). The opacity: 0.82 this replaced measured 4.19
|
|
106
|
+
there, and 2.25 on the dark danger fill — the pair was correct and the
|
|
107
|
+
dilution then spent it. */
|
|
108
|
+
.ui-toast--solid .ui-toast__text { color: color-mix(in srgb, var(--toast-ink) 90%, transparent); }
|
|
109
|
+
.ui-toast--solid .ui-toast__icon { background: color-mix(in srgb, var(--toast-ink) 22%, transparent); color: var(--toast-ink); }
|
|
110
|
+
.ui-toast--solid .ui-toast__action { color: var(--toast-ink); }
|
|
111
|
+
.ui-toast--solid .ui-toast__action:hover { background: color-mix(in srgb, var(--toast-ink) 18%, transparent); }
|
|
112
|
+
.ui-toast--solid .ui-toast__close { color: color-mix(in srgb, var(--toast-ink) 68%, transparent); }
|
|
113
|
+
.ui-toast--solid .ui-toast__close:hover { color: var(--toast-ink); }
|
|
114
|
+
.ui-toast--solid .ui-toast__timer { background: color-mix(in srgb, var(--toast-ink) 55%, transparent); }
|
|
97
115
|
|
|
98
116
|
/* style: outline — elevated card with a status-tinted border */
|
|
99
117
|
.ui-toast--outline { background: var(--bg-elevated); box-shadow: var(--shadow-md); border: 1px solid color-mix(in srgb, var(--toast-accent) 40%, transparent); }
|
package/src/styles/dropdown.css
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
color: var(--muted);
|
|
103
103
|
background: var(--surface);
|
|
104
104
|
}
|
|
105
|
-
.ui-dropdown__badge.is-live { color: var(--
|
|
105
|
+
.ui-dropdown__badge.is-live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
106
106
|
.ui-dropdown__badge.is-accent { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
|
107
107
|
|
|
108
108
|
/* Disabled + danger rows */
|
package/src/styles/empty.css
CHANGED
|
@@ -67,10 +67,15 @@
|
|
|
67
67
|
margin-top: 12px;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
/* Legacy line-icon slot — kept so existing .ui-empty__icon markup still works.
|
|
70
|
+
/* Legacy line-icon slot — kept so existing .ui-empty__icon markup still works.
|
|
71
|
+
44px until #148. The icon inside is `width: 100%`, and that rule lost to the
|
|
72
|
+
base.css reset for as long as this slot has existed, so the slot's number was
|
|
73
|
+
never the size anyone saw: it rendered at 15.94px. Once the reset stopped
|
|
74
|
+
winning, 44px was a size nobody had chosen with their eyes open. 32px is the
|
|
75
|
+
size that was chosen, against the alternatives, on a rendered comparison. */
|
|
71
76
|
.ui-empty__icon {
|
|
72
|
-
width:
|
|
73
|
-
height:
|
|
77
|
+
width: 32px;
|
|
78
|
+
height: 32px;
|
|
74
79
|
margin: 0 auto 14px;
|
|
75
80
|
color: var(--muted);
|
|
76
81
|
opacity: 0.6;
|
package/src/styles/nav.css
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
8
|
.ui-nav { font-family: var(--font-sans); }
|
|
9
|
-
.ui-nav ul,
|
|
9
|
+
.ui-nav :where(ul, ol) { list-style: none; margin: 0; padding: 0; } /* floor, not ceiling */
|
|
10
10
|
|
|
11
11
|
/* -- Sidebar rail -------------------------------------------------------- */
|
|
12
12
|
.ui-nav--side {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
}
|
|
50
50
|
.ui-nav__item:hover { background: var(--surface-2); color: var(--strong); }
|
|
51
51
|
.ui-nav__item.is-active {
|
|
52
|
-
background: var(--surface);
|
|
52
|
+
background: var(--surface-3);
|
|
53
53
|
color: var(--strong);
|
|
54
54
|
font-weight: 500;
|
|
55
55
|
}
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
color: var(--dim);
|
|
99
99
|
}
|
|
100
100
|
.ui-nav__badge.is-accent { background: var(--glow-purple); color: var(--accent); }
|
|
101
|
-
.ui-nav__badge.is-live { background: var(--
|
|
101
|
+
.ui-nav__badge.is-live { background: var(--chip-success-fill); color: var(--chip-success-ink); }
|
|
102
102
|
.ui-nav__badge.is-danger { background: var(--glow-pink); color: var(--pink); }
|
|
103
103
|
.ui-nav__item.is-active .ui-nav__badge.is-neutral { background: var(--surface-3); color: var(--strong); }
|
|
104
104
|
|
|
@@ -117,14 +117,18 @@
|
|
|
117
117
|
display: flex;
|
|
118
118
|
flex-direction: column;
|
|
119
119
|
gap: 2px;
|
|
120
|
-
margin:
|
|
121
|
-
padding-left:
|
|
120
|
+
margin: var(--space-1) 0 var(--space-1) var(--space-4);
|
|
121
|
+
padding-left: var(--space-3);
|
|
122
122
|
border-left: 1px solid var(--border);
|
|
123
123
|
}
|
|
124
124
|
.ui-nav__sub[hidden] { display: none; }
|
|
125
125
|
.ui-nav__item--sub { font-size: 14px; padding: 7px 12px; }
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
/* No hairline on a nested current row — but only at rest. box-shadow carries
|
|
127
|
+
both the hairline and the focus ring, so a rule about the resting look must
|
|
128
|
+
say so, or it silently cancels the ring (WCAG 2.4.7). */
|
|
129
|
+
.ui-nav--side .ui-nav__item--sub.is-active:not(:focus-visible) { box-shadow: none; }
|
|
130
|
+
/* Hangs back onto the guide hairline the indent above draws. */
|
|
131
|
+
.ui-nav--side .ui-nav__item--sub.is-active::before { left: calc(-1 * var(--space-3)); height: 15px; }
|
|
128
132
|
|
|
129
133
|
/* Footer slot (divider + trailing links, e.g. sign-out) */
|
|
130
134
|
.ui-nav__foot { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
|
package/src/styles/topbar.css
CHANGED
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
flex: none;
|
|
150
150
|
margin-top: 1px;
|
|
151
151
|
}
|
|
152
|
-
.vbadge.live { color: var(--
|
|
152
|
+
.vbadge.live { color: var(--chip-success-ink); background: var(--chip-success-fill); }
|
|
153
153
|
.vbadge.arch { color: var(--muted); background: var(--surface); }
|
|
154
154
|
@media (max-width: 600px) { .vsw__btn .lbl { display: none; } }
|
|
155
155
|
|
package/src/tokens/tokens.css
CHANGED
|
@@ -109,7 +109,12 @@
|
|
|
109
109
|
--purple-mid: #b479ff;
|
|
110
110
|
--cyan: #20dcf5;
|
|
111
111
|
--green: #98ff8f;
|
|
112
|
-
--pink
|
|
112
|
+
/* Lighter than it looks like it should be, and deliberately so: --pink is read
|
|
113
|
+
mostly ON its own 16% glow, and that wash lifts the ground faster than the
|
|
114
|
+
hue lifts the ink. #e35b8f measured 3.82:1 on --glow-pink over a card —
|
|
115
|
+
under AA — so danger moved AWAY from the canvas, not toward it. Light moves
|
|
116
|
+
the opposite way for the same reason. See issue #131. */
|
|
117
|
+
--pink: #e97ca5;
|
|
113
118
|
--amber: #ffcf6a;
|
|
114
119
|
|
|
115
120
|
--bg: #16151f;
|
|
@@ -136,16 +141,25 @@
|
|
|
136
141
|
--ink: #e9e7f0;
|
|
137
142
|
|
|
138
143
|
/* Ink that reads on a SIGNAL colour once that colour becomes a fill — the
|
|
139
|
-
glyph in a success circle, the
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
glyph in a success circle, the glyph on a toast's status circle.
|
|
145
|
+
In dark every signal is a bright hue, so one near-black ink clears all
|
|
146
|
+
five: 15.87 on --green, 7.35 on --pink, 13.40 on --amber, 11.75 on --cyan
|
|
147
|
+
and 6.29 on --muted. Danger keeps a token of its own only because LIGHT
|
|
148
|
+
still needs it: there the signals are deepened to read as ink on white,
|
|
149
|
+
which parks them mid-luminance, and --pink is the one that comes out ahead
|
|
150
|
+
against white (5.78) rather than against near-black (3.39).
|
|
151
|
+
Dark danger was white until now, which was correct while --pink was
|
|
152
|
+
#e35b8f. Issue #131 lightened it to #e97ca5 to clear AA as INK on its own
|
|
153
|
+
glow, and that carried the fill up past the point where white could read on
|
|
154
|
+
it — 2.66 on the toast's status circle, under the 3:1 of WCAG 1.4.11. The
|
|
155
|
+
ten status x theme icon pairs are gated in stories/signal-contrast.test.js. */
|
|
142
156
|
--signal-contrast: #0c0c0c;
|
|
143
|
-
--danger-contrast:
|
|
157
|
+
--danger-contrast: var(--signal-contrast);
|
|
144
158
|
|
|
145
159
|
--glow-green: rgba(152, 255, 143, 0.16);
|
|
146
160
|
--glow-purple: rgba(155, 93, 255, 0.18);
|
|
147
161
|
--glow-cyan: rgba(32, 220, 245, 0.14);
|
|
148
|
-
--glow-pink: rgba(
|
|
162
|
+
--glow-pink: rgba(233, 124, 165, 0.16);
|
|
149
163
|
|
|
150
164
|
/* Status-chip paint — the ink + fill of a badge / pill. Dark tints with the
|
|
151
165
|
signal's own glow; light needs a solid, deepened pair (the glows wash out
|
|
@@ -156,6 +170,23 @@
|
|
|
156
170
|
--chip-warn-fill: color-mix(in srgb, var(--amber) 15%, transparent);
|
|
157
171
|
--chip-danger-ink: var(--pink);
|
|
158
172
|
--chip-danger-fill: var(--glow-pink);
|
|
173
|
+
--chip-info-ink: var(--cyan);
|
|
174
|
+
--chip-info-fill: var(--glow-cyan);
|
|
175
|
+
|
|
176
|
+
/* Solid signal surfaces — a status that has stopped being ink and become the
|
|
177
|
+
FILL (a solid toast). The fill and its ink are ONE pair, never two
|
|
178
|
+
independent picks: the fill is the status at this theme's extreme, and the
|
|
179
|
+
ink is the pole opposite it, so a single ink clears all five. Dark fills are
|
|
180
|
+
the bright signals, so the ink is near-black — it measures 15.87 on --green,
|
|
181
|
+
7.35 on --pink, 13.40 on --amber, 11.75 on --cyan and 6.29 on --muted.
|
|
182
|
+
Neutral needs no chip pair to take part: --muted is already its
|
|
183
|
+
fill-strength form. See issues #131 and #149. */
|
|
184
|
+
--signal-solid-ink: var(--signal-contrast);
|
|
185
|
+
--signal-solid-success: var(--green);
|
|
186
|
+
--signal-solid-danger: var(--pink);
|
|
187
|
+
--signal-solid-warn: var(--amber);
|
|
188
|
+
--signal-solid-info: var(--cyan);
|
|
189
|
+
--signal-solid-neutral: var(--muted);
|
|
159
190
|
|
|
160
191
|
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.28);
|
|
161
192
|
--shadow-md: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
@@ -191,7 +222,11 @@
|
|
|
191
222
|
--purple-mid: #7a3be0;
|
|
192
223
|
--cyan: #0c8fa8;
|
|
193
224
|
--green: #1c8a2c;
|
|
194
|
-
|
|
225
|
+
/* Deeper than the dark pink for the same reason dark's is lighter: the wash
|
|
226
|
+
under it is white, so the ink has to come down to meet it. #d63c72 measured
|
|
227
|
+
3.87:1 on --glow-pink over white and 4.42:1 on plain white — the required
|
|
228
|
+
marker and the form error missed AA on nothing at all. See issue #131. */
|
|
229
|
+
--pink: #b63361;
|
|
195
230
|
--amber: #b5730a;
|
|
196
231
|
|
|
197
232
|
/* A WHITE app: the page and cards are both white; cards are delineated by a
|
|
@@ -219,20 +254,51 @@
|
|
|
219
254
|
--signal-contrast: #0c0c0c;
|
|
220
255
|
--danger-contrast: #ffffff;
|
|
221
256
|
|
|
222
|
-
--
|
|
257
|
+
/* Re-tinted from --green. It was rgba(30, 150, 50, .1) — a colour that exists
|
|
258
|
+
nowhere else in the kit, carried unedited since the initial commit while the
|
|
259
|
+
other three light glows are exact tints of their own token. The wash over
|
|
260
|
+
white moves #e9f5eb -> #e8f3ea, at most two levels on a channel, which is
|
|
261
|
+
0.86 of a deltaE — under the 1.0 that is normally called imperceptible. No
|
|
262
|
+
verdict moves with it: body copy on the success wash goes 9.29 -> 9.15
|
|
263
|
+
against the 4.5 AA bar, and the --green icon on it 3.97 -> 3.91 against the
|
|
264
|
+
3.0 bar WCAG 1.4.11 sets for a graphic. The success chips are untouched —
|
|
265
|
+
light's --chip-success-fill is the solid #dff3e4, not this. Gated for all
|
|
266
|
+
four glows in stories/signal-contrast.test.js. See issue #131. */
|
|
267
|
+
--glow-green: rgba(28, 138, 44, 0.1);
|
|
223
268
|
--glow-purple: rgba(106, 45, 204, 0.09);
|
|
224
269
|
--glow-cyan: rgba(12, 143, 168, 0.1);
|
|
225
|
-
--glow-pink: rgba(
|
|
270
|
+
--glow-pink: rgba(182, 51, 97, 0.1);
|
|
226
271
|
|
|
227
272
|
/* Solid chip pairs for the white app. Each ink is deepened past its signal
|
|
228
273
|
hue so 10px uppercase text clears WCAG AA on its own pale fill —
|
|
229
|
-
e.g. --pink (#
|
|
274
|
+
e.g. --pink (#b63361) on #fbe0ea is 4.66:1, #b7295f is 4.85:1. */
|
|
230
275
|
--chip-success-ink: #1f7a38;
|
|
231
276
|
--chip-success-fill: #dff3e4;
|
|
232
277
|
--chip-warn-ink: #8a5e00;
|
|
233
278
|
--chip-warn-fill: #fbedd2;
|
|
234
279
|
--chip-danger-ink: #b7295f;
|
|
235
280
|
--chip-danger-fill: #fbe0ea;
|
|
281
|
+
/* Info was the one signal family without a pair, so the info badge was still
|
|
282
|
+
painting --cyan (#0c8fa8) on --glow-cyan over white, which is 3.39:1 —
|
|
283
|
+
under AA. #0a7286 on #ddeff3 is 4.71:1, inside the 4.64–4.93 band the other
|
|
284
|
+
three pairs already sit in. See issue #131. */
|
|
285
|
+
--chip-info-ink: #0a7286;
|
|
286
|
+
--chip-info-fill: #ddeff3;
|
|
287
|
+
|
|
288
|
+
/* Light runs the same rule the other way. The signals are mid-tone here — a
|
|
289
|
+
solid --green fill measures 4.40 against near-black and 4.45 against white,
|
|
290
|
+
so NO ink rescues it and the fill is what has to move. It moves to the
|
|
291
|
+
deepened form the chip pair already carries, and the pole above it, white,
|
|
292
|
+
clears every one: #ffffff measures 5.39 on --chip-success-ink, 6.01 on
|
|
293
|
+
--chip-danger-ink, 5.70 on --chip-warn-ink, 5.58 on --chip-info-ink and 6.11
|
|
294
|
+
on --muted. A future status supplies one --signal-solid-* value dark enough
|
|
295
|
+
for white and inherits the ink. See issues #131 and #149. */
|
|
296
|
+
--signal-solid-ink: #ffffff;
|
|
297
|
+
--signal-solid-success: var(--chip-success-ink);
|
|
298
|
+
--signal-solid-danger: var(--chip-danger-ink);
|
|
299
|
+
--signal-solid-warn: var(--chip-warn-ink);
|
|
300
|
+
--signal-solid-info: var(--chip-info-ink);
|
|
301
|
+
--signal-solid-neutral: var(--muted);
|
|
236
302
|
|
|
237
303
|
--shadow-sm: 0 1px 3px rgba(30, 30, 50, 0.08);
|
|
238
304
|
--shadow-md: 0 8px 24px rgba(30, 30, 50, 0.1);
|