@guildofgleks/ui 21.7.2 → 21.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/AGENTS.md +155 -11
- package/CHANGELOG.md +407 -0
- package/README.md +24 -3
- package/TOKENS.md +49 -47
- package/fesm2022/guildofgleks-ui.mjs +345 -48
- package/fesm2022/guildofgleks-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/button.css +165 -0
- package/styles/menu.css +120 -114
- package/styles/presets/bevel.css +87 -82
- package/styles/presets/material.css +122 -111
- package/styles/presets/one-dark.css +14 -2
- package/styles/presets/one-light.css +17 -4
- package/styles/presets/primeng.css +139 -121
- package/styles/presets/slate.css +17 -4
- package/styles/theme.css +447 -94
- package/types/guildofgleks-ui.d.ts +248 -20
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,413 @@ All notable changes to `@guildofgleks/ui` are documented here. Format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/); this project has not yet
|
|
5
5
|
reached 1.0, so breaking changes may land in minor versions.
|
|
6
6
|
|
|
7
|
+
## [21.9.0] - 04.09.2026
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`gog-button` and `[gogButton]` gain `severity`.** `severity` says what the action means;
|
|
12
|
+
`variant` says how loudly it is drawn. The two are orthogonal, which is the whole design: this
|
|
13
|
+
is not a fifth variant but a re-pointing of the colours all four are built from, so
|
|
14
|
+
`variant="ghost" severity="danger"` is a quiet delete and `variant="primary" severity="danger"`
|
|
15
|
+
a loud one. `'accent'` is the default and the absence of a claim — an existing button emits no
|
|
16
|
+
new class and renders byte-for-byte as before. The `GogSeverity` union is shared with
|
|
17
|
+
`gog-progressbar`, whose `GogProgressbarVariant` is now an alias of it.
|
|
18
|
+
|
|
19
|
+
Two colour rules came out of measuring rather than choosing. A **filled** severity button's
|
|
20
|
+
label is `--gog-<status>-text-color`, and hover and press deepen the fill *away* from it via
|
|
21
|
+
`--gog-<status>-shade`, so every state makes the label easier to read rather than harder — the
|
|
22
|
+
first attempt deepened toward the page's ink unconditionally and cost `primeng`'s info button
|
|
23
|
+
6.44:1 down to 4.23:1 on press, because there the label *is* the ink. A **transparent** one's
|
|
24
|
+
label is `--gog-button-<status>-ink`, the status hue mixed halfway toward the ink, because the
|
|
25
|
+
raw hue is legible body text in only five of the eleven shipped themes; the 50% is the binding
|
|
26
|
+
case (`material`'s amber) rather than a round number. All four severities, four variants and
|
|
27
|
+
every state are gated by `check:contrast` — 1155 pairs across 11 themes, all passing.
|
|
28
|
+
|
|
29
|
+
- **A status colour is three tokens now, not one.** `--gog-<status>-color` is the fill;
|
|
30
|
+
`--gog-<status>-text-color` is the label that reads on it, the way `--gog-accent-text-color`
|
|
31
|
+
already did for the accent; and `--gog-<status>-shade` is the direction hover and press deepen
|
|
32
|
+
in. Both new ones default to the accent's answer, so a theme states them only where its own hue
|
|
33
|
+
disagrees — and the defaults are what nine of the eleven shipped presets still use. If you write
|
|
34
|
+
a theme, this is the contract to know: setting a status colour alone is how a bright amber ends
|
|
35
|
+
up under white text, which is exactly the defect in the Fixed section below.
|
|
36
|
+
|
|
37
|
+
- **`gog-scroll` gains `horizontalWheel`, so a vertical wheel can scroll a horizontal row.**
|
|
38
|
+
Hover a horizontal-only region, turn the wheel, and the page moves instead — the browser's own
|
|
39
|
+
behaviour, and the thing consumers report about this component most. The component draws an
|
|
40
|
+
overlay thumb over native scrolling and had deliberately never touched wheel handling; this is
|
|
41
|
+
the narrow exception, opt-in.
|
|
42
|
+
|
|
43
|
+
It acts only when all of this holds: the viewport cannot scroll vertically (checked against
|
|
44
|
+
live geometry, not the `axis` input, so `axis="both"` still scrolls down while there is down to
|
|
45
|
+
go), the event carries no horizontal delta of its own (a trackpad swipe and `Shift`+wheel
|
|
46
|
+
already work and translating on top would double them), `ctrlKey` is clear (pinch-zoom), and
|
|
47
|
+
there is room left in the direction of the turn. **The last one is most of the feature:** at the
|
|
48
|
+
content's end the event is left alone, so the page picks it up exactly as before. A region that
|
|
49
|
+
swallowed the wheel at its own end would leave the page feeling stuck, which is a worse bug than
|
|
50
|
+
the one being fixed. `overscrollBehavior: 'contain'` still contains — that boundary is the
|
|
51
|
+
browser's and this never reaches past it.
|
|
52
|
+
|
|
53
|
+
Off by default, because it changes what an existing instance does with a gesture it currently
|
|
54
|
+
passes on; `GOG_CONFIG.scroll.horizontalWheel` turns it on app-wide. A line-mode delta (what
|
|
55
|
+
Firefox sends) is scaled rather than applied raw, which would have moved the content three
|
|
56
|
+
pixels per notch.
|
|
57
|
+
|
|
58
|
+
- **`gog-chip` gains `selected` — the filter chip.** A row of chips you toggle on and off could
|
|
59
|
+
not be built from this component: it had `clickable` and `removable`, so a chip could be pressed
|
|
60
|
+
or dismissed, but nothing said "this one is on". `[(selected)]` is that, and it is tri-state
|
|
61
|
+
because the alternative would have changed every chip that already ships. `null`, the default,
|
|
62
|
+
is not a toggle at all — no `aria-pressed`, no selected look, activation emits `gogClick` and
|
|
63
|
+
nothing else. `false` is a toggle that is off, and states it: a chip with no `aria-pressed` is
|
|
64
|
+
not a toggle to a screen reader, so "off" has to be said rather than left absent. `true` draws
|
|
65
|
+
an inset ring, `--gog-chip-selected-shadow`.
|
|
66
|
+
|
|
67
|
+
The look and the semantics ship together on purpose, which is the whole reason this waited:
|
|
68
|
+
forwarding `aria-pressed` alone would have let a chip announce itself as on while looking
|
|
69
|
+
identical to an off one — WCAG 1.4.1 from the other side, and the exact trap `gog-button` was
|
|
70
|
+
in between 21.8.0 and 21.9.0. A ring rather than a fill for the same reason as the button's:
|
|
71
|
+
`:hover` and `:active` already own this surface's background, so a selected chip painted with a
|
|
72
|
+
fill would lose the one thing saying it is on the moment the pointer arrived.
|
|
73
|
+
|
|
74
|
+
It is a `model`, so the chip flips it on click, Enter and Space and a filter row needs no click
|
|
75
|
+
handler. `gogClick` still fires, after the flip, so a handler reading `selected()` sees the new
|
|
76
|
+
value. A `disabled` chip keeps the ring and drops `aria-pressed`, which needs the `role="button"`
|
|
77
|
+
a disabled chip does not carry — "on, and currently unavailable" is a real state, and hiding it
|
|
78
|
+
would leave it announced and invisible. `check:contrast` gained the ring against both the hover
|
|
79
|
+
and the press background, at 3:1 (WCAG 1.4.11, a boundary rather than text); all 11 themes pass.
|
|
80
|
+
|
|
81
|
+
- **`GOG_CONFIG.spinner.component` — one line replaces every loading indicator in the library.**
|
|
82
|
+
Passing a component, not a value: it is rendered through `NgComponentOutlet` in place of the
|
|
83
|
+
built-in look, wherever the library draws a spinner. That includes the two places a consumer
|
|
84
|
+
could not reach at all — `gog-button` and `gog-autocomplete` render `<gog-spinner>` from their
|
|
85
|
+
own templates and expose no input for it, so a house loader had no way in. It sits inside the
|
|
86
|
+
same size wrapper as the built-ins, keeping the sizing, the overlay behaviour, `role="status"`
|
|
87
|
+
and the accessible name; only the visual changes.
|
|
88
|
+
|
|
89
|
+
Precedence is the library's usual instance-then-config-then-default, and the wrinkle is stated
|
|
90
|
+
because it is the one people will ask about: an instance's own `variant` outranks both config
|
|
91
|
+
keys, so `<gog-spinner variant="ring">` stays a ring in an app that has set a component.
|
|
92
|
+
`spinner.variant` is there for an app that only wants to switch between the two built-ins.
|
|
93
|
+
|
|
94
|
+
`variant` is therefore `GogSpinnerVariant | undefined` now, resolving through the same
|
|
95
|
+
`resolveConfigured` chain as every other configurable input. `variant="custom"` with projected
|
|
96
|
+
content is unaffected.
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- **Leading is a character axis too: `--gog-line-height-none|tight|snug|normal|relaxed|loose`.**
|
|
101
|
+
Twenty component tokens held a bare number — seven of them the same `1.4` — so roomier text
|
|
102
|
+
meant finding and re-listing every one. Same values, nothing moves. `gog-panel`'s heading keeps
|
|
103
|
+
its own `1.25`, off the scale on purpose the way an 11px chip is off the type scale, and rule G
|
|
104
|
+
covers the family so the next bare number fails the build.
|
|
105
|
+
|
|
106
|
+
- **`--gog-control-clear-icon-ratio`: one number, not five.** The clear (×) button's glyph is the
|
|
107
|
+
same part in `gog-autocomplete`, `gog-datepicker`, `gog-inputfield`, `gog-multiselect` and
|
|
108
|
+
`gog-select`, and each carried its own `0.7`. `gog-textarea` keeps its own `1`: its clear
|
|
109
|
+
button sits in a corner rather than in the field's icon row, which is a different problem and
|
|
110
|
+
a different number.
|
|
111
|
+
|
|
112
|
+
- **Weight is a character axis now: `--gog-font-weight-medium|semibold|bold|heavy`.** Fifteen
|
|
113
|
+
component tokens held a bare `500`/`600`/`700`/`900`, so a house style that wanted lighter
|
|
114
|
+
chrome had to find and re-list every one — 21.7.0's character layer unified casing and tracking
|
|
115
|
+
and stopped short of this. Same values, nothing moves; what changes is that four tokens now
|
|
116
|
+
reach all fifteen. Four steps because four are used: no `normal`, since nothing in the library
|
|
117
|
+
paints 400 and an unused token is API nobody asked for. `check-tokens` rule G covers the family,
|
|
118
|
+
so the next bare number fails the build.
|
|
119
|
+
|
|
120
|
+
- **`--gog-z-base`: the whole stacking order moves as one.** `badge`, `toast`, `dropdown`
|
|
121
|
+
(which dialogs and menus read), `tooltip` and the blocking `spinner-overlay` were five
|
|
122
|
+
unrelated literals — 1, 100, 300, 400, 8000 — so an app that had to lift the library above its
|
|
123
|
+
own chrome edited five tokens and hoped it had found them all. Each is `calc(var(--gog-z-base) +
|
|
124
|
+
N)` now: the numbers are unchanged at `--gog-z-base: 0`, and setting it to 10000 gives
|
|
125
|
+
10001/10100/10300/10400/18000 — the same order, one number. The gaps are deliberate, so an app
|
|
126
|
+
can still slot its own element between two library layers.
|
|
127
|
+
|
|
128
|
+
- **One disabled level, not four.** `--gog-disabled-opacity` (0.4) is read by nine components,
|
|
129
|
+
while `gog-accordion`, the `gog-select` and `gog-multiselect` option rows (0.5) and `gog-chip`
|
|
130
|
+
(0.55) each carried their own. One state should not have four opinions, and the three
|
|
131
|
+
stragglers were invisible to rule G by construction — it flags a literal only when the value
|
|
132
|
+
*matches* the token's. **This is a visual change**: those four fade slightly further now.
|
|
133
|
+
|
|
134
|
+
- **The type scale gained the step it was missing: `--gog-text-slg` (1.25rem).** `gog-button` and
|
|
135
|
+
the field controls both needed a size for their `slg` variant, the scale went straight from
|
|
136
|
+
1.125rem to 1.5rem, and both wrote `1.25rem` as a literal — the same value chosen twice,
|
|
137
|
+
independently, which is a missing rung rather than two opinions. Both read the token now, and
|
|
138
|
+
rule G lists it, so the next component that wants 20px type cannot re-invent it. Named for the
|
|
139
|
+
control size it serves rather than continuing the t-shirt run, because that is what asked for
|
|
140
|
+
it.
|
|
141
|
+
|
|
142
|
+
- **Sixteen component font sizes now read the type scale, and rule G covers it.** A theme that
|
|
143
|
+
retuned `--gog-text-*` moved most of the library and left `gog-button`, `gog-chip`, `gog-tag`,
|
|
144
|
+
the dialog's close button, the toast's action and close, and the toggle's `lg` state label
|
|
145
|
+
behind — each held a literal that was byte-for-byte a scale step (`--gog-button-md-font-size:
|
|
146
|
+
1rem` sitting beside `--gog-text-md: 1rem`). Same values, so nothing moves in any theme; the
|
|
147
|
+
difference is that retuning the scale now reaches them.
|
|
148
|
+
|
|
149
|
+
`check-tokens` rule G covered radii, strokes, casing and tracking but **not** font size, which
|
|
150
|
+
is how sixteen of them accumulated. It does now, and the thirteen remaining literals are right
|
|
151
|
+
to be literals: five are the accordion chevron's px ramp, and eight are off the scale on
|
|
152
|
+
purpose — `slg` is 1.25rem in two components because the scale has no step between 1.125 and
|
|
153
|
+
1.5, an 11px chip sits deliberately below `xs`, and the toggle's state label has its own
|
|
154
|
+
four-step micro-ramp. Rule G flags only an exact match, which is precisely what keeps those
|
|
155
|
+
out of it.
|
|
156
|
+
|
|
157
|
+
- **Three clear buttons ignored the theme's corner radius.** `--gog-input-clear-radius`,
|
|
158
|
+
`--gog-select-clear-radius` and `--gog-multiselect-clear-radius` were a flat `2px`, so a theme
|
|
159
|
+
that set `--gog-radius` moved every corner in the library except these. They are
|
|
160
|
+
`calc(var(--gog-radius) / 4)` now: identical at the default 8px, so nothing moves in `light` or
|
|
161
|
+
`dark` — but `bevel`, whose whole identity is square corners (`--gog-radius: 0`), had three
|
|
162
|
+
quietly rounded controls and now does not.
|
|
163
|
+
|
|
164
|
+
Found by counting rather than by looking: of 47 radius tokens, 30 already derived from
|
|
165
|
+
`--gog-radius`, 8 are pills or circles (a shape, not a corner size), 5 are deliberately flat,
|
|
166
|
+
and these 3 were the remainder. `check-tokens` rule G could not have caught them — it flags a
|
|
167
|
+
literal only when its value *equals* a character token's, which is what keeps a pill's `999px`
|
|
168
|
+
from being called drift, and is exactly why a small arbitrary number is the shape of drift it
|
|
169
|
+
cannot see. `gog-toast` and `gog-accordion` keep their flat corners, on the user's call: those
|
|
170
|
+
are a chosen shape.
|
|
171
|
+
|
|
172
|
+
- **Error text was below WCAG AA in four themes.** `--gog-danger-color` is what every
|
|
173
|
+
`--gog-<block>-error-color` resolves to, so it is the colour a validation message is printed in
|
|
174
|
+
— text, needing 4.5:1, not the 3:1 a status accent gets away with. It cleared neither ground in
|
|
175
|
+
`one-light` (3.51:1 / 3.67:1), `primeng` (3.60 / 3.76), `one-dark` (4.38) or `slate` (4.46).
|
|
176
|
+
Each preset's red moves the smallest distance that clears 4.6:1 on both the page and a card:
|
|
177
|
+
`#e45649`→`#c2493e`, `#ef4444`→`#ce3a3a`, `#e06c75`→`#e2737c`, `#dc2626`→`#d82525`.
|
|
178
|
+
`check:contrast` gained the pair in the same change — it had none for `danger` at all, which is
|
|
179
|
+
why a field error nobody could read was invisible to it. Found by pointing the new
|
|
180
|
+
`check:app-contrast` at `ui-showcase`, which renders the library from source.
|
|
181
|
+
|
|
182
|
+
- **A toggle button now looks toggled.** 21.8.0 taught `gog-button` to forward `aria-pressed`,
|
|
183
|
+
and nothing in the library styled it — so a toggle could announce itself as on to a screen
|
|
184
|
+
reader while looking identical to an off one, which is WCAG 1.4.1 from the other side and
|
|
185
|
+
exactly the reason `docs/backlog.md` gives for *not* forwarding `aria-pressed` to `gog-chip`.
|
|
186
|
+
`aria-pressed="true"` (and `"mixed"`) now draws an inset ring: new
|
|
187
|
+
`--gog-button-<variant>-toggled-shadow`, with `--gog-button-toggled-shadow` as the per-instance
|
|
188
|
+
override. A ring rather than a fill because `:hover` and `:active` already own the background —
|
|
189
|
+
a toggled button that lost its state the moment the pointer arrived would be the same bug one
|
|
190
|
+
layer down. It keys off the attribute, not an input, so `[gogButton]` on your own element gets
|
|
191
|
+
it from the `aria-pressed` you already wrote there.
|
|
192
|
+
|
|
193
|
+
- **A button pressed with animations off now shows that it was pressed.** `:active` was a
|
|
194
|
+
`transform: scale()` and nothing else, and the `prefers-reduced-motion: reduce` block switched
|
|
195
|
+
that transform off — so the reader most likely to need the feedback got none at all. The ripple
|
|
196
|
+
did not cover it either: it is off by default, and it is deliberately suppressed under reduced
|
|
197
|
+
motion because it genuinely is decoration. `:active` now also deepens the button's background,
|
|
198
|
+
one step past its own hover so a press is distinguishable while hovering, and reduced motion
|
|
199
|
+
drops only the movement. New per-variant `--gog-button-<variant>-press-bg`/`-press-color`
|
|
200
|
+
tokens and the usual `--gog-button-press-bg`/`-press-color` instance overrides. **Ghost presses
|
|
201
|
+
to a filled `--gog-accent-dim`, like outline, rather than to a wash** — checked across all 11
|
|
202
|
+
themes, and a wash cannot work there: ghost's own *label* is the accent, so tinting its ground
|
|
203
|
+
with the accent walks the two together, and a 24% wash put the label under 4.5:1 in seven
|
|
204
|
+
themes. A filled press moves the label to `--gog-accent-text-color`, the pair `check:contrast`
|
|
205
|
+
already gates, so no future theme can quietly break it. Reduced motion must remove the animation, not the
|
|
206
|
+
information — the same rule the toast countdown was fixed under in 21.7.1.
|
|
207
|
+
|
|
208
|
+
The family is spelled `press`, not `active`, because `active` already means two different
|
|
209
|
+
things in this library — `--gog-tabs-active-color` is the *selected* tab, while
|
|
210
|
+
`--gog-scroll-thumb-active-bg` is the thumb being dragged. One name, one meaning. The shipped
|
|
211
|
+
`--gog-button-active-scale` keeps its spelling: renaming a token consumers already override
|
|
212
|
+
needs a deprecation cycle, and this is a patch.
|
|
213
|
+
|
|
214
|
+
- **`check:contrast` now measures composited washes, and found 24 more failures.** The script
|
|
215
|
+
compared palette hexes, so any pair where one side was a `color-mix()` wash was invisible to it
|
|
216
|
+
— which is both of the button failures above, found by hand instead. New `scripts/token-color.mjs`
|
|
217
|
+
resolves a component token the way a browser does (the theme's own block, then the `@supports`
|
|
218
|
+
mixed layer, then the derived layer, then the literals), composites it over the ground that
|
|
219
|
+
component actually sits on, and the check measures the label against that. 385 pairs across the
|
|
220
|
+
11 themes, up from 143.
|
|
221
|
+
|
|
222
|
+
It then grew a second half that needs no table at all: `collectStatePairs` reads the compiled
|
|
223
|
+
stylesheets and checks every label/ground pair the rules themselves state, so a component added
|
|
224
|
+
later is covered without anyone remembering to list it. **627 pairs** in total now. That sweep
|
|
225
|
+
found one further real failure across the whole library — `gog-autocomplete`'s **selected
|
|
226
|
+
option** label, `--gog-accent-color` on its own tint, 4.12:1 in light (and `--gog-accent-dim` is
|
|
227
|
+
worse again, 3.77:1 in one-dark). It is `--gog-text-color` now; the tint and `aria-selected`
|
|
228
|
+
still mark the row, and `gog-select` keeps its accent label because its selected option has no
|
|
229
|
+
tint behind it. Icons are held to 3:1 rather than 4.5:1, which is what keeps a spin-button glyph
|
|
230
|
+
and a panel chevron — 4.35:1 and 4.40:1, both correct — from being "fixed" into near-black.
|
|
231
|
+
|
|
232
|
+
Its first run failed 24 of them, all real, and all fixed here:
|
|
233
|
+
|
|
234
|
+
- **A pressed tab's label leaves the muted tone.** A resting tab is deliberately
|
|
235
|
+
`--gog-muted-text-color`, which has no headroom to spend on a tinted ground: 3.24:1 in
|
|
236
|
+
one-dark and under 4.5 in six more. New `--gog-tabs-press-color`, the full text colour — which
|
|
237
|
+
is what pressing a tab is about to make it anyway.
|
|
238
|
+
- **An accordion header's label stops turning accent while hovered or held.** It took
|
|
239
|
+
`--gog-accordion-accent-color` on an accent-tinted strip: 3.61:1 in light, 3.79:1 in one-light,
|
|
240
|
+
4.09:1 in ledger, and worse once the press deepened the tint. New `--gog-accordion-hover-color`,
|
|
241
|
+
defaulting to the header's own text colour; the lift is carried by the background alone. The
|
|
242
|
+
same trade as the ghost button's hover, for the same reason.
|
|
243
|
+
- **The press wash is 20%, not 22%.** Measured rather than chosen: at 21% one-dark's mid-grey
|
|
244
|
+
text falls under 4.5:1 on three of the surfaces. 20% is the strongest wash that clears AA in
|
|
245
|
+
every theme, and it is still a clear step past the 10-12% hover.
|
|
246
|
+
|
|
247
|
+
- **A ghost button's label was under WCAG AA on its own hover, in three themes.** `light`
|
|
248
|
+
3.94:1, `primeng` 4.18:1, `one-light` 4.22:1. The variant's resting label *is*
|
|
249
|
+
`--gog-accent-color` and its hover tints the ground with the same accent, so the two walked
|
|
250
|
+
toward each other. **No background fixes it**, which is why this took a sweep rather than a
|
|
251
|
+
nudge: a half-strength wash (4.28), a neutral `--gog-hover-color` (4.15), a text scrim (3.91)
|
|
252
|
+
and an accent-dim wash (3.96) were all measured across the 11 themes, and `light` fails every
|
|
253
|
+
one — `--gog-accent-color` as *text* on that theme's background is 4.60:1 to begin with, so
|
|
254
|
+
there is no headroom to spend on any ground at all. The label now becomes `--gog-text-color`
|
|
255
|
+
while hovered, which clears 5.29:1 at worst (one-dark) and leaves the wash untouched, so the
|
|
256
|
+
hover stays the subtle one this variant is documented to have. Ghost's three states now read
|
|
257
|
+
transparent → tinted → filled, with a label chosen for each ground rather than one label
|
|
258
|
+
hoping to survive three.
|
|
259
|
+
|
|
260
|
+
- **`bevel` had no accent ramp, so its buttons could not show a press.** That preset declared
|
|
261
|
+
`--gog-accent-dim: #000080`, byte-identical to its `--gog-accent-color`. Harmless while `dim`
|
|
262
|
+
was only a field border; once it became the pressed fill, a pressed button in `bevel` painted
|
|
263
|
+
itself the colour it already was. Nothing failed — the token existed, resolved and passed every
|
|
264
|
+
contrast pair. It is now `#00005c`, and **`check-tokens` rule I was widened from the surface
|
|
265
|
+
tiers to any ramp**, so a theme whose rest/hover/press tones collapse into each other fails the
|
|
266
|
+
build instead of shipping a state nobody can see. Found by sweeping all 11 themes rather than by
|
|
267
|
+
the check that now catches it.
|
|
268
|
+
|
|
269
|
+
- **The other nine pressable surfaces had no press feedback either — now eight of them do.**
|
|
270
|
+
`.gog-btn:active` turned out to be the *only* `:active` rule in the library. `gogMenuItem`,
|
|
271
|
+
`gog-chip`, `gog-tabs` headers, `gog-accordion` headers, `gog-button-toggle-group` options and
|
|
272
|
+
the `gog-select` / `gog-multiselect` / `gog-autocomplete` option rows all acknowledged a press
|
|
273
|
+
through the ripple alone — which is off by default and suppressed under reduced motion — so a
|
|
274
|
+
default-configured app confirmed a press nowhere at all. Each now paints
|
|
275
|
+
`--gog-<block>-press-bg`: a wash roughly double the 10-12% one its own hover uses, in the same
|
|
276
|
+
ingredient, with a flat `--gog-border-color` for browsers without `color-mix()`. Two of them
|
|
277
|
+
are not that shape and say so in place: a `gog-tabs` header paints no background in any other
|
|
278
|
+
state (its hover moves the label colour only), and a *selected* button-toggle option is already
|
|
279
|
+
filled, so it deepens to `--gog-accent-dim` the way the filled button variants do.
|
|
280
|
+
|
|
281
|
+
**`gogCollapsibleTrigger` is deliberately not in that list.** It is the consumer's own element
|
|
282
|
+
and the library paints nothing on it — no background at rest, none on hover, only a cursor and
|
|
283
|
+
a disabled state. A press colour there would be the library inventing a look for markup it does
|
|
284
|
+
not own, and inventing it for one state out of three. The same reasoning `docs/ripple.md`
|
|
285
|
+
records for `gogCardLink` and `gog-table` rows.
|
|
286
|
+
|
|
287
|
+
The three option rows' press rules are guarded against the disabled modifier; their **hover**
|
|
288
|
+
rules are not, and were left alone — a disabled option lighting up under the pointer is a
|
|
289
|
+
separate decision from this one, and it is filed rather than folded in.
|
|
290
|
+
|
|
291
|
+
- **A disabled option no longer lights up under the pointer, and no longer ripples.** Two
|
|
292
|
+
separate holes in the same place. `.gog-select__option:hover` and `.gog-ms__option:hover`
|
|
293
|
+
carried no disabled guard, so a row that cannot be chosen took the same hover background as one
|
|
294
|
+
that can — only its opacity and its cursor disagreed, and neither is what a hover is read for.
|
|
295
|
+
`gog-autocomplete` already had this right (`:not([aria-disabled='true'])`), which is where the
|
|
296
|
+
fix was copied from. And all **three** wired `gogRipple` with `[rippleDisabled]="!rippleEnabled()"`,
|
|
297
|
+
taking no account of the option's own state: with the ripple switched on app-wide, a disabled
|
|
298
|
+
row answered a press with a wave. The options are rendered `aria-disabled`, not `disabled`, so
|
|
299
|
+
nothing else was stopping it. Same argument the library already applied to a non-interactive
|
|
300
|
+
`gog-chip`: a wave is a promise, and these rows cannot keep it.
|
|
301
|
+
|
|
302
|
+
- **The outline button's label was unreadable while hovered, in every shipped theme.**
|
|
303
|
+
`--gog-button-outline-hover-color` resolved to `--gog-primary-color`, the colour of text on the
|
|
304
|
+
*page*, while the hover fill is the accent — pale parchment on bright amber in `dark` (1.41:1),
|
|
305
|
+
light grey on blue in `one-dark` (1.11:1), and failing WCAG AA in all 11 themes, the best of
|
|
306
|
+
them `light` at 3.65:1. It now resolves to `--gog-accent-text-color`, the token that means "text
|
|
307
|
+
on an accent fill" and the one both filled variants already used. Found while adding the state
|
|
308
|
+
above, which would have copied the same mistake into `:active`.
|
|
309
|
+
|
|
310
|
+
- **`check:contrast` gained the pair that hid both.** The script had no pair for a label on the
|
|
311
|
+
accent *fill* other than `accentText/accent`, so neither the outline label nor the new held
|
|
312
|
+
state was covered. `accentText/accentDim(active)` is now checked at 4.5:1, and it immediately
|
|
313
|
+
failed one theme: `one-dark`'s `--gog-accent-dim` moved from `#4b8fca` to `#5399d6` (4.05:1 →
|
|
314
|
+
4.59:1). That token had only ever been a field border, which is gated at 3:1; making it a fill
|
|
315
|
+
under a label is what raised the bar. The nudge moves it toward this palette's own `#61afef`,
|
|
316
|
+
so unlike 21.7.0's two comment-colour corrections it costs no fidelity.
|
|
317
|
+
|
|
318
|
+
- **Ten pieces of geometry ignored `--gog-density`, and nine of the eleven themes set it.**
|
|
319
|
+
`terminal` runs at 0.85, `one-dark`/`one-light`/`bevel`/`ledger` at 0.9, `primeng` at 0.95,
|
|
320
|
+
`slate` at 1.05, `material`/`parchment` at 1.1 — so in every one of them these ten stayed at
|
|
321
|
+
the pixel they were typed as while everything around them moved. The clearest case is the gap
|
|
322
|
+
between a dropdown and its panel: `gog-autocomplete` and `gog-datepicker` read `--gog-space-2`,
|
|
323
|
+
while `gog-select` and `gog-multiselect` restated `2px`, so in `terminal` two of the four
|
|
324
|
+
panels drew closer to their field and two did not. Also converted: `--gog-menu-offset` (which
|
|
325
|
+
sat between `--gog-menu-padding` and `--gog-menu-gap`, both already reading the scale),
|
|
326
|
+
`--gog-input-clear-inset` (the textarea's clear button — the other four clearable fields place
|
|
327
|
+
their chrome from `--gog-control-icon-offset`), the two error-line offsets, the toggle's
|
|
328
|
+
in-track wording clearance, the badge's overhang, and the calendar's header and time-row
|
|
329
|
+
margins. Each now reads its scale step, so all ten render exactly as before at the default
|
|
330
|
+
density and follow the theme everywhere else.
|
|
331
|
+
|
|
332
|
+
- **Four focus rings did not follow `--gog-focus-ring-offset`.** `gog-button-toggle` restated
|
|
333
|
+
its `2px` on the line directly after reading `--gog-focus-ring-width` from the foundation;
|
|
334
|
+
`gog-button` used `3px`; `gog-calendar` and `gog-tabs` used `-2px` to sit the ring inside a
|
|
335
|
+
cell, because both pack their cells edge to edge and an outward ring lands on the neighbour.
|
|
336
|
+
All four now derive from the foundation token — `var(…)`, `calc(… + 1px)` and `calc(… * -1)` —
|
|
337
|
+
so a theme that moves the ring moves them with it, and the two negative values now say in the
|
|
338
|
+
file why they are negative. No rendered value changes.
|
|
339
|
+
|
|
340
|
+
- **`check-tokens` rule H only covered two of the six families that hold a spacing number.**
|
|
341
|
+
The density check was written for `-padding` and `-gap`, the two the density work had just
|
|
342
|
+
converted, and `-offset`, `-inset` and `-margin` went unwatched for three releases — which is
|
|
343
|
+
where all ten literals above were hiding. The name filter now covers all six, and exempts the
|
|
344
|
+
lengths that match a scale step by coincidence rather than by meaning: every
|
|
345
|
+
`*-focus-ring-offset` (an accessibility affordance, which a compact theme must not shrink, and
|
|
346
|
+
which a component should answer by reading the foundation ring rather than a spacing step),
|
|
347
|
+
plus the scrollbar and toggle thumb insets, both fitted to a track whose own width is a fixed
|
|
348
|
+
pixel value. The script's header now also lists rules H and I, which had been in it unlisted
|
|
349
|
+
since they were added.
|
|
350
|
+
|
|
351
|
+
- **`gogBadge`'s status variants failed WCAG AA in four themes, and had since they shipped.** A
|
|
352
|
+
status badge paints `--gog-<status>-color` and labelled it `--gog-accent-text-color`, which on
|
|
353
|
+
a light theme is white: `material`'s amber measured **1.97:1**, `primeng`'s green 2.28:1, and
|
|
354
|
+
`slate` and `one-light` failed on all three of success/warning/info — 11 pairs in total.
|
|
355
|
+
`danger` passed everywhere, which is the tell: a danger pair was added to `check:contrast` on
|
|
356
|
+
2026-09-03 and the palettes were tuned to it, while the other three statuses had never been
|
|
357
|
+
measured against anything.
|
|
358
|
+
|
|
359
|
+
Half the fix costs no fidelity: `material` puts near-black on its amber (8.69:1) and `primeng`
|
|
360
|
+
does the same on all three of Aura's bright hues (6.44–8.31:1), which is what both design
|
|
361
|
+
systems do themselves. The other half had no label to pick — neither white nor the theme's own
|
|
362
|
+
ink reached AA — so the hue moved instead, one step down each theme's own ramp: `slate`'s three
|
|
363
|
+
to Tailwind's 700s, `material`'s blue to Light Blue 800, and `one-light`'s three darkened, the
|
|
364
|
+
same trade that theme already made on its accent and muted tokens in 21.7.0.
|
|
365
|
+
|
|
366
|
+
**The reason no check caught it generalises past the badge.** `check:contrast`'s automatic
|
|
367
|
+
sweep pairs a rule that sets `color` with the `background-color` beside it; a variant class
|
|
368
|
+
sets neither, only `--gog-badge-variant-bg`/`-color` for the base rule to read. Every variant
|
|
369
|
+
of every component is written that way, so the sweep had been reporting ~180 passing states
|
|
370
|
+
without looking at one of them. Four explicit badge pairs close it for this component; the
|
|
371
|
+
general fix is filed in `docs/backlog.md`.
|
|
372
|
+
|
|
373
|
+
- **Two fields put their error line 2px lower than the other six.** Every control that renders an
|
|
374
|
+
error — `gog-inputfield`, `gog-textarea`, `gog-select`, `gog-multiselect`, `gog-autocomplete`,
|
|
375
|
+
`gog-datepicker`, `gog-radio-group`, `gog-slider` — is a flex column whose own gap already
|
|
376
|
+
separates the error from the field, the same gap that separates the label from it. Two of them
|
|
377
|
+
then added `margin-top: 2px` on top: measured in a browser, `gog-inputfield` and
|
|
378
|
+
`gog-multiselect` sat at 6px while `gog-select`, `gog-autocomplete` and `gog-datepicker` sat at
|
|
379
|
+
4px from the identical gap. In one form, side by side, the six did not line up.
|
|
380
|
+
`--gog-input-error-offset` and `--gog-multiselect-error-offset` now default to `0`, so one
|
|
381
|
+
mechanism spaces the error line everywhere; both tokens stay, and setting one still pushes that
|
|
382
|
+
field's error further than the rest.
|
|
383
|
+
|
|
384
|
+
## [21.8.0] - 03.09.2026
|
|
385
|
+
|
|
386
|
+
### Added
|
|
387
|
+
|
|
388
|
+
- **`gog-button` forwards ARIA state and relationships: `ariaPressed`, `ariaExpanded`,
|
|
389
|
+
`ariaControls`, `ariaHasPopup`.** The component hides the real `<button>`, so
|
|
390
|
+
`<gog-button [attr.aria-pressed]="on()">` puts the attribute on the custom element host —
|
|
391
|
+
which has no role — and assistive tech never sees it. It compiles, throws nothing, looks
|
|
392
|
+
right, and silently ships a toggle button that is not a toggle button; `ariaLabel` already
|
|
393
|
+
existed for exactly this reason and was the only one. `null` (the default) omits the
|
|
394
|
+
attribute, while `false` is forwarded as `aria-pressed="false"`/`aria-expanded="false"`,
|
|
395
|
+
which is what an off toggle or a closed disclosure must say. New exported type
|
|
396
|
+
`GogAriaHasPopup`. The `[gogButton]` directive needs none of this — it styles an element you
|
|
397
|
+
own, so write the attributes there directly.
|
|
398
|
+
|
|
399
|
+
### Fixed
|
|
400
|
+
|
|
401
|
+
- **`GOG_CONFIG`'s own documentation now names every component that reads each key.** The
|
|
402
|
+
`GogGlobalConfig` JSDoc — the closest thing the library has to a source of truth for which
|
|
403
|
+
component honours which setting, and what your editor shows you on hover — under-reported four
|
|
404
|
+
keys. `control.size` did not mention `gog-button-toggle-group`, `gog-toggle`, `gog-autocomplete`
|
|
405
|
+
or `gog-datepicker`; `control.errorDisplay`, `control.clearable` and `floatLabel` did not
|
|
406
|
+
mention `gog-autocomplete` or `gog-datepicker`; and `dropdown` claimed to apply to
|
|
407
|
+
`gog-select`/`gog-multiselect` as a block, when `appendToBody`/`direction` also reach
|
|
408
|
+
`gog-autocomplete` and `gog-datepicker` while `filter`/`filterPosition` genuinely do not.
|
|
409
|
+
`AGENTS.md`'s config table was closer but stated outright that `gog-toggle` does **not** take
|
|
410
|
+
`control.size`, which it does. No behaviour change — every one of these components already
|
|
411
|
+
honoured the setting; only the documentation was wrong, in the direction of telling you a
|
|
412
|
+
setting would not work when it does.
|
|
413
|
+
|
|
7
414
|
## [21.7.2] - 30.08.2026
|
|
8
415
|
|
|
9
416
|
### Fixed
|
package/README.md
CHANGED
|
@@ -168,6 +168,16 @@ variant and size classes:
|
|
|
168
168
|
> "what a raised surface looks like here". Change one and every raised surface follows, which is
|
|
169
169
|
> the intent; the rest of `--gog-panel-*` belongs to the component alone.
|
|
170
170
|
|
|
171
|
+
**A status colour is three tokens, not one.** `--gog-danger-color` and its three siblings are
|
|
172
|
+
fills, and a fill needs a label that reads on it and a direction to deepen in — so each also has
|
|
173
|
+
`--gog-<status>-text-color` (the label; defaults to the accent's, state it only when your hue
|
|
174
|
+
disagrees) and `--gog-<status>-shade` (which way hover and press move; defaults to the page's ink,
|
|
175
|
+
and should be the opposite when your label *is* the ink). Setting a status colour alone and
|
|
176
|
+
leaving those at their defaults is how a bright amber ends up under white text: it measured 1.97:1
|
|
177
|
+
in one of this package's own presets before 21.9.0. `gogBadge` and `gog-button`'s `severity` read
|
|
178
|
+
the label; the button also reads the shade. `gog-tag` derives its own pair by mixing and
|
|
179
|
+
`gog-progressbar` paints no label on its bar, so neither needs them.
|
|
180
|
+
|
|
171
181
|
Every group and token name is in **[`TOKENS.md`](./TOKENS.md)**, generated from `theme.css` so it
|
|
172
182
|
cannot drift, and available at runtime as `GOG_TOKEN_GROUPS`.
|
|
173
183
|
|
|
@@ -263,9 +273,20 @@ provideGogConfig({
|
|
|
263
273
|
```
|
|
264
274
|
|
|
265
275
|
Keys: `control`, `dropdown`, `floatLabel`, `datepicker`, `autocomplete`, `inputfield`, `textarea`,
|
|
266
|
-
`tooltip`, `scroll`, `button`, `ripple`, `paginator`, `toast`, `theme`, `labels`. An
|
|
267
|
-
input always wins, and providing the config again lower in the injector tree layers
|
|
268
|
-
parent rather than replacing it.
|
|
276
|
+
`tooltip`, `scroll`, `button`, `ripple`, `spinner`, `paginator`, `toast`, `theme`, `labels`. An
|
|
277
|
+
instance's own input always wins, and providing the config again lower in the injector tree layers
|
|
278
|
+
onto the parent rather than replacing it.
|
|
279
|
+
|
|
280
|
+
`spinner` is the one key that takes a **component** rather than a value:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
provideGogConfig({ spinner: { component: HouseLoader } });
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
That renders your loader wherever the library draws a spinner — including the two places no input
|
|
287
|
+
could reach, since `gog-button` and `gog-autocomplete` render their own and expose nothing for it.
|
|
288
|
+
It keeps the library's sizing, overlay behaviour, `role="status"` and accessible name; only the
|
|
289
|
+
visual is yours.
|
|
269
290
|
|
|
270
291
|
`ripple` is the one visual default that is not a token, and the exception is deliberate:
|
|
271
292
|
`--gog-ripple-opacity: 0` would hide the wash but still pay for the DOM node, the listeners and
|