@guildofgleks/ui 21.8.0 → 21.9.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/AGENTS.md +120 -5
- package/CHANGELOG.md +383 -0
- package/README.md +24 -3
- package/TOKENS.md +49 -47
- package/fesm2022/guildofgleks-ui.mjs +316 -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 +176 -10
package/AGENTS.md
CHANGED
|
@@ -5,8 +5,8 @@ an app that **consumes** the published `@guildofgleks/ui` npm package. It is not
|
|
|
5
5
|
authoring the library — if you are working inside the `gleks_web_ui` monorepo itself, read
|
|
6
6
|
`.github/instructions/*.md` instead.
|
|
7
7
|
|
|
8
|
-
Everything below reflects the library's actual source as of **`21.
|
|
9
|
-
released version is 21.
|
|
8
|
+
Everything below reflects the library's actual source as of **`21.9.0`** (in progress — the
|
|
9
|
+
released version is 21.8.0; see `CHANGELOG.md` for what 21.9.0 adds). 21.7.0 removed the three
|
|
10
10
|
abbreviated token prefixes and 21.5.0 removed a batch of deprecated API — see **Removed in 21.7.0**
|
|
11
11
|
and **Removed in 21.5.0** near the end of this file, which exist so code written against an older
|
|
12
12
|
version can be migrated — and `CHANGELOG.md` has the rest. `README.md` covers the same ground at a
|
|
@@ -181,13 +181,30 @@ Full model is in `README.md`'s Theming section; short version:
|
|
|
181
181
|
`--gog-text-transform`/`--gog-letter-spacing` (emphasis casing/tracking). Component tokens in
|
|
182
182
|
the categories these cover derive from them by default; setting one in a `[data-theme]` block
|
|
183
183
|
restyles every component that reads it, with nothing to re-list per component.
|
|
184
|
+
- **The type scale is `--gog-text-xs | sm | md | lg | slg | xl | 2xl | 3xl`.** `slg` (1.25rem)
|
|
185
|
+
fills the gap between `lg` and `xl` and is named for the control size that needed it. Every
|
|
186
|
+
component font size that is one of these reads the token, so retuning the scale retunes the
|
|
187
|
+
library; the handful that do not are off-scale on purpose (an 11px chip, the accordion
|
|
188
|
+
chevron's px ramp, the toggle's own micro-ramp).
|
|
189
|
+
|
|
190
|
+
- **Weight is `--gog-font-weight-medium | semibold | bold | heavy`** (500/600/700/900). Every
|
|
191
|
+
component weight reads one of them, so a lighter or heavier house style is four declarations.
|
|
192
|
+
|
|
193
|
+
- **`--gog-z-base` moves the whole stacking order.** Badge `+1`, toast `+100`, dropdowns, dialogs
|
|
194
|
+
and menus `+300`, tooltip `+400`, the blocking spinner overlay `+8000`. Set the base to lift
|
|
195
|
+
the library above your own chrome without disturbing its internal order.
|
|
196
|
+
|
|
184
197
|
- **`--gog-density` is the character layer for spacing** (since 21.7.0, `docs/themes.md`
|
|
185
198
|
iteration 6). It multiplies the fourteen-step scale `--gog-space-2` … `--gog-space-48`, named
|
|
186
199
|
for their pixel value at density 1, and every padding and gap in the library derives from a
|
|
187
200
|
step. `--gog-density: 0.9` in a `[data-theme]` block makes the whole library tighter; nothing
|
|
188
201
|
else needs to be named. `--gog-space-xs|sm|md|lg|2xl` are aliases for steps 4/8/16/24/48 and
|
|
189
|
-
still work. Icon offsets
|
|
190
|
-
|
|
202
|
+
still work. Icon offsets, dropdown panel gaps, error-line offsets and the badge's overhang
|
|
203
|
+
follow density; the glyph box, the focus-ring offset, the float-label reserve and the
|
|
204
|
+
scrollbar/toggle thumb insets deliberately do not — those are legibility or geometry fitted to
|
|
205
|
+
a fixed-width track, not spacing. Since 21.9.0 the split is enforced rather than trusted:
|
|
206
|
+
`check-tokens` rule H fails the build on a length token that restates a scale step's value as
|
|
207
|
+
a bare literal, with the three exceptions named in the script.
|
|
191
208
|
- **Component prefixes are spelled out** since 21.5.0: `--gog-button-*`, `--gog-multiselect-*`,
|
|
192
209
|
`--gog-confirmation-dialog-*`. The abbreviated `--gog-btn-*`, `--gog-ms-*` and `--gog-confirm-*`
|
|
193
210
|
were removed in 21.7.0 — if you're reading a codebase or an example that still uses one, rename
|
|
@@ -271,7 +288,8 @@ parent's config**, one level deep per key — it does not replace it.
|
|
|
271
288
|
| `datepicker` | `locale`, `firstDayOfWeek`, `format` | `gog-datepicker`, `gog-calendar`. |
|
|
272
289
|
| `autocomplete` | `searchDebounce`, `minLength`, `openOnFocus` | `gog-autocomplete`. |
|
|
273
290
|
| `tooltip` | `position`, `showDelay`, `hideDelay` | the `gogTooltip` directive. |
|
|
274
|
-
| `
|
|
291
|
+
| `spinner` | `component`, `variant` | every spinner the library draws — `gog-spinner`, `gog-spinner-overlay`, and the ones inside `gog-button` and `gog-autocomplete`, which have no input of their own. `component` takes **your** component and renders it in place of the built-in look. |
|
|
292
|
+
| `scroll` | `autoHide`, `hideDelay`, `size`, `overscrollBehavior`, `showTrack`, `horizontalWheel` | `gog-scroll` (and every component that uses one internally). |
|
|
275
293
|
| `button` | `debounce` | `gog-button`. |
|
|
276
294
|
| `ripple` | `enabled` | the press ripple on `gog-button`, `[gogButton]`, `gog-button-toggle-group`, `gog-chip`, `gog-tabs`, `gog-accordion`, `gogCollapsibleTrigger`, `gogMenuItem` and the `gog-select`/`gog-multiselect`/`gog-autocomplete` options. **Off by default.** Each of those takes a `ripple` input that wins over it. Not the `gogRipple` directive — writing that attribute is already the per-element decision. |
|
|
277
295
|
| `inputfield` | `showSpinButtons` | `gog-inputfield`. |
|
|
@@ -468,6 +486,7 @@ Every component below is exported from `@guildofgleks/ui`'s root — `import { X
|
|
|
468
486
|
| Input | Type | Default | Notes |
|
|
469
487
|
| ----------- | --------------------------------- | ----------- | ----------------------------------------------------- |
|
|
470
488
|
| `variant` | `GogVariant` | `'primary'` | |
|
|
489
|
+
| `severity` | `GogSeverity` | `'accent'` | what the action means; orthogonal to `variant` — see below |
|
|
471
490
|
| `size` | `GogSize \| undefined` | `'md'` | via `GOG_CONFIG.control.size` |
|
|
472
491
|
| `disabled` | `boolean` | `false` | |
|
|
473
492
|
| `fullWidth` | `boolean` | `false` | |
|
|
@@ -483,6 +502,29 @@ Every component below is exported from `@guildofgleks/ui`'s root — `import { X
|
|
|
483
502
|
|
|
484
503
|
Outputs: `gogClick: MouseEvent`.
|
|
485
504
|
|
|
505
|
+
**`severity` says what the action means; `variant` says how loudly it is drawn** (21.9.0). The
|
|
506
|
+
two are orthogonal, so this is not a fifth variant — it re-points the colours all four are built
|
|
507
|
+
from, and every combination is real: `variant="ghost" severity="danger"` is a quiet delete,
|
|
508
|
+
`variant="primary" severity="danger"` a loud one. `'accent'` is the default and the absence of a
|
|
509
|
+
claim, so nothing has to opt out of a severity it does not have. `GogSeverity` is shared with
|
|
510
|
+
`gog-progressbar`, whose `GogProgressbarVariant` is now an alias of it.
|
|
511
|
+
|
|
512
|
+
```html
|
|
513
|
+
<gog-button severity="danger" (gogClick)="deleteAccount()">Delete account</gog-button>
|
|
514
|
+
<gog-button variant="outline" severity="warning">Discard draft</gog-button>
|
|
515
|
+
<a gogButton severity="success" routerLink="/done">Finish</a>
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
Two colour rules are worth knowing before you override anything. A **filled** severity button's
|
|
519
|
+
label is `--gog-<status>-text-color`, which each theme states for its own hue — `material` and
|
|
520
|
+
`primeng` put near-black on their bright ones, the rest white — and hover and press deepen the
|
|
521
|
+
fill *away* from that label (`--gog-<status>-shade`), so a state always makes the label easier to
|
|
522
|
+
read rather than harder. A **transparent** one's label is `--gog-button-<status>-ink`: the status
|
|
523
|
+
hue mixed halfway toward the page's ink, because the raw hue is legible body text in only five of
|
|
524
|
+
the eleven shipped themes. Override `--gog-button-<status>-ink` if your own theme wants more
|
|
525
|
+
colour there, and check it: all four severities across all four variants and all their states are
|
|
526
|
+
gated by `npm run check:contrast`.
|
|
527
|
+
|
|
486
528
|
**Every ARIA attribute this button needs has an input, and a raw attribute is not a
|
|
487
529
|
substitute.** `<gog-button [attr.aria-pressed]="on()">` compiles, throws nothing, and does
|
|
488
530
|
nothing: the attribute lands on the `<gog-button>` custom element, which has no role, while the
|
|
@@ -494,6 +536,13 @@ simply not a toggle to a screen reader. Use `[ariaPressed]`, `[ariaExpanded]`, `
|
|
|
494
536
|
`aria-pressed="false"` / `aria-expanded="false"`, which is what an off toggle or a closed
|
|
495
537
|
disclosure has to say — a button with no `aria-pressed` at all is not a toggle button.
|
|
496
538
|
|
|
539
|
+
**A toggle button now looks toggled** (21.9.0). `aria-pressed="true"` (or `"mixed"`) draws an
|
|
540
|
+
inset ring — `--gog-button-<variant>-toggled-shadow`, overridable per instance with
|
|
541
|
+
`--gog-button-toggled-shadow`. A ring rather than a fill because hover and press already own the
|
|
542
|
+
background: the state has to survive both, and until 21.9.0 it did not exist at all, so a button
|
|
543
|
+
could announce itself as on to a screen reader and look identical to an off one. `[gogButton]`
|
|
544
|
+
gets the same look from the attribute you write on your own element.
|
|
545
|
+
|
|
497
546
|
**`[gogButton]` needs none of these inputs.** It styles an element you own, so write the ARIA
|
|
498
547
|
attributes on your own `<button>`/`<a>` directly. Same for `[gogMenuTrigger]`, which sets
|
|
499
548
|
`aria-haspopup`/`aria-expanded`/`aria-controls` on its host — put it on your own `<button
|
|
@@ -506,6 +555,19 @@ gogButton>`, as its own example shows, not on a `<gog-button>`.
|
|
|
506
555
|
(gogClick)="open.set(!open())">Filters</gog-button>
|
|
507
556
|
```
|
|
508
557
|
|
|
558
|
+
**The press is a colour, not only a movement.** `:active` deepens the button's background (and
|
|
559
|
+
the label where the fill demands it) as well as scaling it by `--gog-button-active-scale`. Under
|
|
560
|
+
`prefers-reduced-motion: reduce` the scale is dropped and the colour stays, so the press is still
|
|
561
|
+
visible to a reader who has switched animations off — before 21.9.0 that reader got no feedback at
|
|
562
|
+
all, since the ripple is off by default and is itself suppressed under reduced motion. Override
|
|
563
|
+
per instance with `--gog-button-press-bg` / `--gog-button-press-color`, or per theme with
|
|
564
|
+
`--gog-button-<variant>-active-bg`.
|
|
565
|
+
|
|
566
|
+
Every other pressable surface in the library does the same thing since 21.9.0 — menu items,
|
|
567
|
+
chips, tab and accordion headers, button-toggle options and the three dropdowns' option rows —
|
|
568
|
+
each through its own `--gog-<block>-press-bg`. `gogCollapsibleTrigger` is the exception: the
|
|
569
|
+
library paints nothing on that element in any state, because it is yours.
|
|
570
|
+
|
|
509
571
|
**`debounce` is a spam guard, not a delay before the first click.** The first click in a window
|
|
510
572
|
fires immediately (leading edge); further clicks within `debounce` ms are silently dropped.
|
|
511
573
|
|
|
@@ -956,6 +1018,7 @@ the element stays yours and the directive only gives it the look.
|
|
|
956
1018
|
| Input | Type | Default |
|
|
957
1019
|
| ----------- | ------------------------ | ---------------------------------------- |
|
|
958
1020
|
| `variant` | `GogVariant` | `'primary'` |
|
|
1021
|
+
| `severity` | `GogSeverity` | `'accent'`; same as `gog-button` |
|
|
959
1022
|
| `size` | `GogSize \| undefined` | `'md'`; via `GOG_CONFIG.control.size` |
|
|
960
1023
|
| `fullWidth` | `boolean` (bare attr ok) | `false` |
|
|
961
1024
|
| `ripple` | `boolean \| undefined` | `false`; via `GOG_CONFIG.ripple.enabled` |
|
|
@@ -1004,6 +1067,7 @@ are impossible by design.
|
|
|
1004
1067
|
| `size` | `GogSize` | `'md'` |
|
|
1005
1068
|
| `shape` | `GogTagShape` (`'rounded'\|'pill'`) | `'rounded'` |
|
|
1006
1069
|
| `disabled`, `clickable` | `boolean` | `false`, `true` |
|
|
1070
|
+
| `selected` | `boolean \| null` (two-way) | `null` — see below |
|
|
1007
1071
|
| `removable` | `boolean` | `false` |
|
|
1008
1072
|
| `fullWidth` | `boolean` | `false` |
|
|
1009
1073
|
| `ariaLabel`, `removeAriaLabel` | `string` | `''`, `'Remove chip'` |
|
|
@@ -1019,6 +1083,29 @@ Outputs: `gogClick: MouseEvent | KeyboardEvent`, `gogRemove: void`.
|
|
|
1019
1083
|
>
|
|
1020
1084
|
```
|
|
1021
1085
|
|
|
1086
|
+
**`selected` makes it a filter chip** (21.9.0) — a chip you toggle on and off rather than press.
|
|
1087
|
+
It is tri-state, and `null` is the default so nothing about an existing chip changes: no
|
|
1088
|
+
`aria-pressed`, no selected look, activation only emits `gogClick`. Set it to `false` and the chip
|
|
1089
|
+
is a toggle that is off (`aria-pressed="false"` — a chip with no `aria-pressed` at all is not a
|
|
1090
|
+
toggle to a screen reader, so "off" has to be stated); `true` and it is on, which draws an inset
|
|
1091
|
+
ring from `--gog-chip-selected-shadow`. A ring rather than a fill because `:hover` and `:active`
|
|
1092
|
+
already own the chip's background and the selection has to survive both.
|
|
1093
|
+
|
|
1094
|
+
It is a two-way `model`, so the chip flips it on click, Enter and Space — a row of filters needs
|
|
1095
|
+
no click handler:
|
|
1096
|
+
|
|
1097
|
+
```html
|
|
1098
|
+
@for (f of filters; track f.label) {
|
|
1099
|
+
<gog-chip [(selected)]="f.on">{{ f.label }}</gog-chip>
|
|
1100
|
+
}
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
`gogClick` still fires, **after** the flip, so a handler reading `selected()` sees the new value.
|
|
1104
|
+
Drive the state from that handler instead and you want a one-way `[selected]`, or the two writes
|
|
1105
|
+
cancel out. A `disabled` chip keeps the ring but drops `aria-pressed`, which needs the
|
|
1106
|
+
`role="button"` a disabled chip does not carry — "selected, and currently unavailable" is a real
|
|
1107
|
+
state and hiding it would leave it announced and invisible.
|
|
1108
|
+
|
|
1022
1109
|
#### `gog-tag`
|
|
1023
1110
|
|
|
1024
1111
|
| Input | Type | Default |
|
|
@@ -1048,6 +1135,19 @@ Slot: `<ng-template gogTagIcon>` for custom icon markup.
|
|
|
1048
1135
|
`variant="custom"` renders your own projected markup, still inheriting the size wrapper and
|
|
1049
1136
|
`--gog-spinner-color` theming.
|
|
1050
1137
|
|
|
1138
|
+
**To replace the spinner everywhere at once, pass a component to `GOG_CONFIG`** — including the
|
|
1139
|
+
two places you cannot reach with an input, `gog-button`'s and `gog-autocomplete`'s loading
|
|
1140
|
+
states:
|
|
1141
|
+
|
|
1142
|
+
```ts
|
|
1143
|
+
provideGogConfig({ spinner: { component: HouseLoaderComponent } });
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
It renders inside the same size wrapper as the built-ins, so it keeps the sizing, the overlay
|
|
1147
|
+
behaviour, `role="status"` and the accessible name — only the visual is yours. An instance's own
|
|
1148
|
+
`variant` still wins over it, so `<gog-spinner variant="ring">` is a ring in an app that has set
|
|
1149
|
+
a component: a default does not overrule something asked for explicitly.
|
|
1150
|
+
|
|
1051
1151
|
```html
|
|
1052
1152
|
<gog-spinner-overlay [loading]="isLoading()">
|
|
1053
1153
|
<app-content-that-loads />
|
|
@@ -1588,6 +1688,21 @@ region — the library's official recommendation over a raw `overflow-x`/`overfl
|
|
|
1588
1688
|
| `ariaLabel` | `string` | `''` |
|
|
1589
1689
|
| `overscrollBehavior` | `GogScrollOverscrollBehavior \| undefined` (`'auto'\|'contain'\|'none'`) | `'auto'`; via `GOG_CONFIG.scroll.overscrollBehavior` |
|
|
1590
1690
|
| `showTrack` | `boolean \| undefined` | `true`; via `GOG_CONFIG.scroll.showTrack` |
|
|
1691
|
+
| `horizontalWheel` | `boolean \| undefined` | `false`; via `GOG_CONFIG.scroll.horizontalWheel` |
|
|
1692
|
+
|
|
1693
|
+
**`horizontalWheel` turns a vertical wheel into horizontal scrolling** (21.9.0), for the case a
|
|
1694
|
+
consumer hits first: hover a horizontal-only row, turn the wheel, and the *page* moves. That is
|
|
1695
|
+
the browser's own behaviour and the component deliberately did nothing about it until now.
|
|
1696
|
+
|
|
1697
|
+
It is off by default because it changes what an existing instance does with a gesture it
|
|
1698
|
+
currently passes on; `provideGogConfig({ scroll: { horizontalWheel: true } })` turns it on
|
|
1699
|
+
app-wide. It only acts when the viewport cannot scroll vertically (checked against live
|
|
1700
|
+
geometry, so `axis="both"` scrolls down while there is down to go), the event carries no
|
|
1701
|
+
horizontal delta of its own (a trackpad swipe and `Shift`+wheel already work), `ctrlKey` is
|
|
1702
|
+
clear (pinch-zoom), and there is room left in the direction of the turn. **That last condition is
|
|
1703
|
+
the point:** at the content's end the event is left alone and the page picks it up, so the wheel
|
|
1704
|
+
never goes dead over a scrolled-to-the-end region. `overscrollBehavior: 'contain'` still
|
|
1705
|
+
contains — that boundary is the browser's and this never reaches past it.
|
|
1591
1706
|
|
|
1592
1707
|
Outputs: `gogScroll: GogScrollMetrics`, `gogReachStart`/`gogReachEnd: 'vertical'|'horizontal'`.
|
|
1593
1708
|
Methods (via template ref): `scrollTo(options)`, `scrollToTop()`, `scrollToBottom()`,
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,389 @@ 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.1] - 04.09.2026
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- version and commit history
|
|
12
|
+
|
|
13
|
+
## [21.9.0] - 04.09.2026
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`gog-button` and `[gogButton]` gain `severity`.** `severity` says what the action means;
|
|
18
|
+
`variant` says how loudly it is drawn. The two are orthogonal, which is the whole design: this
|
|
19
|
+
is not a fifth variant but a re-pointing of the colours all four are built from, so
|
|
20
|
+
`variant="ghost" severity="danger"` is a quiet delete and `variant="primary" severity="danger"`
|
|
21
|
+
a loud one. `'accent'` is the default and the absence of a claim — an existing button emits no
|
|
22
|
+
new class and renders byte-for-byte as before. The `GogSeverity` union is shared with
|
|
23
|
+
`gog-progressbar`, whose `GogProgressbarVariant` is now an alias of it.
|
|
24
|
+
|
|
25
|
+
Two colour rules came out of measuring rather than choosing. A **filled** severity button's
|
|
26
|
+
label is `--gog-<status>-text-color`, and hover and press deepen the fill *away* from it via
|
|
27
|
+
`--gog-<status>-shade`, so every state makes the label easier to read rather than harder — the
|
|
28
|
+
first attempt deepened toward the page's ink unconditionally and cost `primeng`'s info button
|
|
29
|
+
6.44:1 down to 4.23:1 on press, because there the label *is* the ink. A **transparent** one's
|
|
30
|
+
label is `--gog-button-<status>-ink`, the status hue mixed halfway toward the ink, because the
|
|
31
|
+
raw hue is legible body text in only five of the eleven shipped themes; the 50% is the binding
|
|
32
|
+
case (`material`'s amber) rather than a round number. All four severities, four variants and
|
|
33
|
+
every state are gated by `check:contrast` — 1155 pairs across 11 themes, all passing.
|
|
34
|
+
|
|
35
|
+
- **A status colour is three tokens now, not one.** `--gog-<status>-color` is the fill;
|
|
36
|
+
`--gog-<status>-text-color` is the label that reads on it, the way `--gog-accent-text-color`
|
|
37
|
+
already did for the accent; and `--gog-<status>-shade` is the direction hover and press deepen
|
|
38
|
+
in. Both new ones default to the accent's answer, so a theme states them only where its own hue
|
|
39
|
+
disagrees — and the defaults are what nine of the eleven shipped presets still use. If you write
|
|
40
|
+
a theme, this is the contract to know: setting a status colour alone is how a bright amber ends
|
|
41
|
+
up under white text, which is exactly the defect in the Fixed section below.
|
|
42
|
+
|
|
43
|
+
- **`gog-scroll` gains `horizontalWheel`, so a vertical wheel can scroll a horizontal row.**
|
|
44
|
+
Hover a horizontal-only region, turn the wheel, and the page moves instead — the browser's own
|
|
45
|
+
behaviour, and the thing consumers report about this component most. The component draws an
|
|
46
|
+
overlay thumb over native scrolling and had deliberately never touched wheel handling; this is
|
|
47
|
+
the narrow exception, opt-in.
|
|
48
|
+
|
|
49
|
+
It acts only when all of this holds: the viewport cannot scroll vertically (checked against
|
|
50
|
+
live geometry, not the `axis` input, so `axis="both"` still scrolls down while there is down to
|
|
51
|
+
go), the event carries no horizontal delta of its own (a trackpad swipe and `Shift`+wheel
|
|
52
|
+
already work and translating on top would double them), `ctrlKey` is clear (pinch-zoom), and
|
|
53
|
+
there is room left in the direction of the turn. **The last one is most of the feature:** at the
|
|
54
|
+
content's end the event is left alone, so the page picks it up exactly as before. A region that
|
|
55
|
+
swallowed the wheel at its own end would leave the page feeling stuck, which is a worse bug than
|
|
56
|
+
the one being fixed. `overscrollBehavior: 'contain'` still contains — that boundary is the
|
|
57
|
+
browser's and this never reaches past it.
|
|
58
|
+
|
|
59
|
+
Off by default, because it changes what an existing instance does with a gesture it currently
|
|
60
|
+
passes on; `GOG_CONFIG.scroll.horizontalWheel` turns it on app-wide. A line-mode delta (what
|
|
61
|
+
Firefox sends) is scaled rather than applied raw, which would have moved the content three
|
|
62
|
+
pixels per notch.
|
|
63
|
+
|
|
64
|
+
- **`gog-chip` gains `selected` — the filter chip.** A row of chips you toggle on and off could
|
|
65
|
+
not be built from this component: it had `clickable` and `removable`, so a chip could be pressed
|
|
66
|
+
or dismissed, but nothing said "this one is on". `[(selected)]` is that, and it is tri-state
|
|
67
|
+
because the alternative would have changed every chip that already ships. `null`, the default,
|
|
68
|
+
is not a toggle at all — no `aria-pressed`, no selected look, activation emits `gogClick` and
|
|
69
|
+
nothing else. `false` is a toggle that is off, and states it: a chip with no `aria-pressed` is
|
|
70
|
+
not a toggle to a screen reader, so "off" has to be said rather than left absent. `true` draws
|
|
71
|
+
an inset ring, `--gog-chip-selected-shadow`.
|
|
72
|
+
|
|
73
|
+
The look and the semantics ship together on purpose, which is the whole reason this waited:
|
|
74
|
+
forwarding `aria-pressed` alone would have let a chip announce itself as on while looking
|
|
75
|
+
identical to an off one — WCAG 1.4.1 from the other side, and the exact trap `gog-button` was
|
|
76
|
+
in between 21.8.0 and 21.9.0. A ring rather than a fill for the same reason as the button's:
|
|
77
|
+
`:hover` and `:active` already own this surface's background, so a selected chip painted with a
|
|
78
|
+
fill would lose the one thing saying it is on the moment the pointer arrived.
|
|
79
|
+
|
|
80
|
+
It is a `model`, so the chip flips it on click, Enter and Space and a filter row needs no click
|
|
81
|
+
handler. `gogClick` still fires, after the flip, so a handler reading `selected()` sees the new
|
|
82
|
+
value. A `disabled` chip keeps the ring and drops `aria-pressed`, which needs the `role="button"`
|
|
83
|
+
a disabled chip does not carry — "on, and currently unavailable" is a real state, and hiding it
|
|
84
|
+
would leave it announced and invisible. `check:contrast` gained the ring against both the hover
|
|
85
|
+
and the press background, at 3:1 (WCAG 1.4.11, a boundary rather than text); all 11 themes pass.
|
|
86
|
+
|
|
87
|
+
- **`GOG_CONFIG.spinner.component` — one line replaces every loading indicator in the library.**
|
|
88
|
+
Passing a component, not a value: it is rendered through `NgComponentOutlet` in place of the
|
|
89
|
+
built-in look, wherever the library draws a spinner. That includes the two places a consumer
|
|
90
|
+
could not reach at all — `gog-button` and `gog-autocomplete` render `<gog-spinner>` from their
|
|
91
|
+
own templates and expose no input for it, so a house loader had no way in. It sits inside the
|
|
92
|
+
same size wrapper as the built-ins, keeping the sizing, the overlay behaviour, `role="status"`
|
|
93
|
+
and the accessible name; only the visual changes.
|
|
94
|
+
|
|
95
|
+
Precedence is the library's usual instance-then-config-then-default, and the wrinkle is stated
|
|
96
|
+
because it is the one people will ask about: an instance's own `variant` outranks both config
|
|
97
|
+
keys, so `<gog-spinner variant="ring">` stays a ring in an app that has set a component.
|
|
98
|
+
`spinner.variant` is there for an app that only wants to switch between the two built-ins.
|
|
99
|
+
|
|
100
|
+
`variant` is therefore `GogSpinnerVariant | undefined` now, resolving through the same
|
|
101
|
+
`resolveConfigured` chain as every other configurable input. `variant="custom"` with projected
|
|
102
|
+
content is unaffected.
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
|
|
106
|
+
- **Leading is a character axis too: `--gog-line-height-none|tight|snug|normal|relaxed|loose`.**
|
|
107
|
+
Twenty component tokens held a bare number — seven of them the same `1.4` — so roomier text
|
|
108
|
+
meant finding and re-listing every one. Same values, nothing moves. `gog-panel`'s heading keeps
|
|
109
|
+
its own `1.25`, off the scale on purpose the way an 11px chip is off the type scale, and rule G
|
|
110
|
+
covers the family so the next bare number fails the build.
|
|
111
|
+
|
|
112
|
+
- **`--gog-control-clear-icon-ratio`: one number, not five.** The clear (×) button's glyph is the
|
|
113
|
+
same part in `gog-autocomplete`, `gog-datepicker`, `gog-inputfield`, `gog-multiselect` and
|
|
114
|
+
`gog-select`, and each carried its own `0.7`. `gog-textarea` keeps its own `1`: its clear
|
|
115
|
+
button sits in a corner rather than in the field's icon row, which is a different problem and
|
|
116
|
+
a different number.
|
|
117
|
+
|
|
118
|
+
- **Weight is a character axis now: `--gog-font-weight-medium|semibold|bold|heavy`.** Fifteen
|
|
119
|
+
component tokens held a bare `500`/`600`/`700`/`900`, so a house style that wanted lighter
|
|
120
|
+
chrome had to find and re-list every one — 21.7.0's character layer unified casing and tracking
|
|
121
|
+
and stopped short of this. Same values, nothing moves; what changes is that four tokens now
|
|
122
|
+
reach all fifteen. Four steps because four are used: no `normal`, since nothing in the library
|
|
123
|
+
paints 400 and an unused token is API nobody asked for. `check-tokens` rule G covers the family,
|
|
124
|
+
so the next bare number fails the build.
|
|
125
|
+
|
|
126
|
+
- **`--gog-z-base`: the whole stacking order moves as one.** `badge`, `toast`, `dropdown`
|
|
127
|
+
(which dialogs and menus read), `tooltip` and the blocking `spinner-overlay` were five
|
|
128
|
+
unrelated literals — 1, 100, 300, 400, 8000 — so an app that had to lift the library above its
|
|
129
|
+
own chrome edited five tokens and hoped it had found them all. Each is `calc(var(--gog-z-base) +
|
|
130
|
+
N)` now: the numbers are unchanged at `--gog-z-base: 0`, and setting it to 10000 gives
|
|
131
|
+
10001/10100/10300/10400/18000 — the same order, one number. The gaps are deliberate, so an app
|
|
132
|
+
can still slot its own element between two library layers.
|
|
133
|
+
|
|
134
|
+
- **One disabled level, not four.** `--gog-disabled-opacity` (0.4) is read by nine components,
|
|
135
|
+
while `gog-accordion`, the `gog-select` and `gog-multiselect` option rows (0.5) and `gog-chip`
|
|
136
|
+
(0.55) each carried their own. One state should not have four opinions, and the three
|
|
137
|
+
stragglers were invisible to rule G by construction — it flags a literal only when the value
|
|
138
|
+
*matches* the token's. **This is a visual change**: those four fade slightly further now.
|
|
139
|
+
|
|
140
|
+
- **The type scale gained the step it was missing: `--gog-text-slg` (1.25rem).** `gog-button` and
|
|
141
|
+
the field controls both needed a size for their `slg` variant, the scale went straight from
|
|
142
|
+
1.125rem to 1.5rem, and both wrote `1.25rem` as a literal — the same value chosen twice,
|
|
143
|
+
independently, which is a missing rung rather than two opinions. Both read the token now, and
|
|
144
|
+
rule G lists it, so the next component that wants 20px type cannot re-invent it. Named for the
|
|
145
|
+
control size it serves rather than continuing the t-shirt run, because that is what asked for
|
|
146
|
+
it.
|
|
147
|
+
|
|
148
|
+
- **Sixteen component font sizes now read the type scale, and rule G covers it.** A theme that
|
|
149
|
+
retuned `--gog-text-*` moved most of the library and left `gog-button`, `gog-chip`, `gog-tag`,
|
|
150
|
+
the dialog's close button, the toast's action and close, and the toggle's `lg` state label
|
|
151
|
+
behind — each held a literal that was byte-for-byte a scale step (`--gog-button-md-font-size:
|
|
152
|
+
1rem` sitting beside `--gog-text-md: 1rem`). Same values, so nothing moves in any theme; the
|
|
153
|
+
difference is that retuning the scale now reaches them.
|
|
154
|
+
|
|
155
|
+
`check-tokens` rule G covered radii, strokes, casing and tracking but **not** font size, which
|
|
156
|
+
is how sixteen of them accumulated. It does now, and the thirteen remaining literals are right
|
|
157
|
+
to be literals: five are the accordion chevron's px ramp, and eight are off the scale on
|
|
158
|
+
purpose — `slg` is 1.25rem in two components because the scale has no step between 1.125 and
|
|
159
|
+
1.5, an 11px chip sits deliberately below `xs`, and the toggle's state label has its own
|
|
160
|
+
four-step micro-ramp. Rule G flags only an exact match, which is precisely what keeps those
|
|
161
|
+
out of it.
|
|
162
|
+
|
|
163
|
+
- **Three clear buttons ignored the theme's corner radius.** `--gog-input-clear-radius`,
|
|
164
|
+
`--gog-select-clear-radius` and `--gog-multiselect-clear-radius` were a flat `2px`, so a theme
|
|
165
|
+
that set `--gog-radius` moved every corner in the library except these. They are
|
|
166
|
+
`calc(var(--gog-radius) / 4)` now: identical at the default 8px, so nothing moves in `light` or
|
|
167
|
+
`dark` — but `bevel`, whose whole identity is square corners (`--gog-radius: 0`), had three
|
|
168
|
+
quietly rounded controls and now does not.
|
|
169
|
+
|
|
170
|
+
Found by counting rather than by looking: of 47 radius tokens, 30 already derived from
|
|
171
|
+
`--gog-radius`, 8 are pills or circles (a shape, not a corner size), 5 are deliberately flat,
|
|
172
|
+
and these 3 were the remainder. `check-tokens` rule G could not have caught them — it flags a
|
|
173
|
+
literal only when its value *equals* a character token's, which is what keeps a pill's `999px`
|
|
174
|
+
from being called drift, and is exactly why a small arbitrary number is the shape of drift it
|
|
175
|
+
cannot see. `gog-toast` and `gog-accordion` keep their flat corners, on the user's call: those
|
|
176
|
+
are a chosen shape.
|
|
177
|
+
|
|
178
|
+
- **Error text was below WCAG AA in four themes.** `--gog-danger-color` is what every
|
|
179
|
+
`--gog-<block>-error-color` resolves to, so it is the colour a validation message is printed in
|
|
180
|
+
— text, needing 4.5:1, not the 3:1 a status accent gets away with. It cleared neither ground in
|
|
181
|
+
`one-light` (3.51:1 / 3.67:1), `primeng` (3.60 / 3.76), `one-dark` (4.38) or `slate` (4.46).
|
|
182
|
+
Each preset's red moves the smallest distance that clears 4.6:1 on both the page and a card:
|
|
183
|
+
`#e45649`→`#c2493e`, `#ef4444`→`#ce3a3a`, `#e06c75`→`#e2737c`, `#dc2626`→`#d82525`.
|
|
184
|
+
`check:contrast` gained the pair in the same change — it had none for `danger` at all, which is
|
|
185
|
+
why a field error nobody could read was invisible to it. Found by pointing the new
|
|
186
|
+
`check:app-contrast` at `ui-showcase`, which renders the library from source.
|
|
187
|
+
|
|
188
|
+
- **A toggle button now looks toggled.** 21.8.0 taught `gog-button` to forward `aria-pressed`,
|
|
189
|
+
and nothing in the library styled it — so a toggle could announce itself as on to a screen
|
|
190
|
+
reader while looking identical to an off one, which is WCAG 1.4.1 from the other side and
|
|
191
|
+
exactly the reason `docs/backlog.md` gives for *not* forwarding `aria-pressed` to `gog-chip`.
|
|
192
|
+
`aria-pressed="true"` (and `"mixed"`) now draws an inset ring: new
|
|
193
|
+
`--gog-button-<variant>-toggled-shadow`, with `--gog-button-toggled-shadow` as the per-instance
|
|
194
|
+
override. A ring rather than a fill because `:hover` and `:active` already own the background —
|
|
195
|
+
a toggled button that lost its state the moment the pointer arrived would be the same bug one
|
|
196
|
+
layer down. It keys off the attribute, not an input, so `[gogButton]` on your own element gets
|
|
197
|
+
it from the `aria-pressed` you already wrote there.
|
|
198
|
+
|
|
199
|
+
- **A button pressed with animations off now shows that it was pressed.** `:active` was a
|
|
200
|
+
`transform: scale()` and nothing else, and the `prefers-reduced-motion: reduce` block switched
|
|
201
|
+
that transform off — so the reader most likely to need the feedback got none at all. The ripple
|
|
202
|
+
did not cover it either: it is off by default, and it is deliberately suppressed under reduced
|
|
203
|
+
motion because it genuinely is decoration. `:active` now also deepens the button's background,
|
|
204
|
+
one step past its own hover so a press is distinguishable while hovering, and reduced motion
|
|
205
|
+
drops only the movement. New per-variant `--gog-button-<variant>-press-bg`/`-press-color`
|
|
206
|
+
tokens and the usual `--gog-button-press-bg`/`-press-color` instance overrides. **Ghost presses
|
|
207
|
+
to a filled `--gog-accent-dim`, like outline, rather than to a wash** — checked across all 11
|
|
208
|
+
themes, and a wash cannot work there: ghost's own *label* is the accent, so tinting its ground
|
|
209
|
+
with the accent walks the two together, and a 24% wash put the label under 4.5:1 in seven
|
|
210
|
+
themes. A filled press moves the label to `--gog-accent-text-color`, the pair `check:contrast`
|
|
211
|
+
already gates, so no future theme can quietly break it. Reduced motion must remove the animation, not the
|
|
212
|
+
information — the same rule the toast countdown was fixed under in 21.7.1.
|
|
213
|
+
|
|
214
|
+
The family is spelled `press`, not `active`, because `active` already means two different
|
|
215
|
+
things in this library — `--gog-tabs-active-color` is the *selected* tab, while
|
|
216
|
+
`--gog-scroll-thumb-active-bg` is the thumb being dragged. One name, one meaning. The shipped
|
|
217
|
+
`--gog-button-active-scale` keeps its spelling: renaming a token consumers already override
|
|
218
|
+
needs a deprecation cycle, and this is a patch.
|
|
219
|
+
|
|
220
|
+
- **`check:contrast` now measures composited washes, and found 24 more failures.** The script
|
|
221
|
+
compared palette hexes, so any pair where one side was a `color-mix()` wash was invisible to it
|
|
222
|
+
— which is both of the button failures above, found by hand instead. New `scripts/token-color.mjs`
|
|
223
|
+
resolves a component token the way a browser does (the theme's own block, then the `@supports`
|
|
224
|
+
mixed layer, then the derived layer, then the literals), composites it over the ground that
|
|
225
|
+
component actually sits on, and the check measures the label against that. 385 pairs across the
|
|
226
|
+
11 themes, up from 143.
|
|
227
|
+
|
|
228
|
+
It then grew a second half that needs no table at all: `collectStatePairs` reads the compiled
|
|
229
|
+
stylesheets and checks every label/ground pair the rules themselves state, so a component added
|
|
230
|
+
later is covered without anyone remembering to list it. **627 pairs** in total now. That sweep
|
|
231
|
+
found one further real failure across the whole library — `gog-autocomplete`'s **selected
|
|
232
|
+
option** label, `--gog-accent-color` on its own tint, 4.12:1 in light (and `--gog-accent-dim` is
|
|
233
|
+
worse again, 3.77:1 in one-dark). It is `--gog-text-color` now; the tint and `aria-selected`
|
|
234
|
+
still mark the row, and `gog-select` keeps its accent label because its selected option has no
|
|
235
|
+
tint behind it. Icons are held to 3:1 rather than 4.5:1, which is what keeps a spin-button glyph
|
|
236
|
+
and a panel chevron — 4.35:1 and 4.40:1, both correct — from being "fixed" into near-black.
|
|
237
|
+
|
|
238
|
+
Its first run failed 24 of them, all real, and all fixed here:
|
|
239
|
+
|
|
240
|
+
- **A pressed tab's label leaves the muted tone.** A resting tab is deliberately
|
|
241
|
+
`--gog-muted-text-color`, which has no headroom to spend on a tinted ground: 3.24:1 in
|
|
242
|
+
one-dark and under 4.5 in six more. New `--gog-tabs-press-color`, the full text colour — which
|
|
243
|
+
is what pressing a tab is about to make it anyway.
|
|
244
|
+
- **An accordion header's label stops turning accent while hovered or held.** It took
|
|
245
|
+
`--gog-accordion-accent-color` on an accent-tinted strip: 3.61:1 in light, 3.79:1 in one-light,
|
|
246
|
+
4.09:1 in ledger, and worse once the press deepened the tint. New `--gog-accordion-hover-color`,
|
|
247
|
+
defaulting to the header's own text colour; the lift is carried by the background alone. The
|
|
248
|
+
same trade as the ghost button's hover, for the same reason.
|
|
249
|
+
- **The press wash is 20%, not 22%.** Measured rather than chosen: at 21% one-dark's mid-grey
|
|
250
|
+
text falls under 4.5:1 on three of the surfaces. 20% is the strongest wash that clears AA in
|
|
251
|
+
every theme, and it is still a clear step past the 10-12% hover.
|
|
252
|
+
|
|
253
|
+
- **A ghost button's label was under WCAG AA on its own hover, in three themes.** `light`
|
|
254
|
+
3.94:1, `primeng` 4.18:1, `one-light` 4.22:1. The variant's resting label *is*
|
|
255
|
+
`--gog-accent-color` and its hover tints the ground with the same accent, so the two walked
|
|
256
|
+
toward each other. **No background fixes it**, which is why this took a sweep rather than a
|
|
257
|
+
nudge: a half-strength wash (4.28), a neutral `--gog-hover-color` (4.15), a text scrim (3.91)
|
|
258
|
+
and an accent-dim wash (3.96) were all measured across the 11 themes, and `light` fails every
|
|
259
|
+
one — `--gog-accent-color` as *text* on that theme's background is 4.60:1 to begin with, so
|
|
260
|
+
there is no headroom to spend on any ground at all. The label now becomes `--gog-text-color`
|
|
261
|
+
while hovered, which clears 5.29:1 at worst (one-dark) and leaves the wash untouched, so the
|
|
262
|
+
hover stays the subtle one this variant is documented to have. Ghost's three states now read
|
|
263
|
+
transparent → tinted → filled, with a label chosen for each ground rather than one label
|
|
264
|
+
hoping to survive three.
|
|
265
|
+
|
|
266
|
+
- **`bevel` had no accent ramp, so its buttons could not show a press.** That preset declared
|
|
267
|
+
`--gog-accent-dim: #000080`, byte-identical to its `--gog-accent-color`. Harmless while `dim`
|
|
268
|
+
was only a field border; once it became the pressed fill, a pressed button in `bevel` painted
|
|
269
|
+
itself the colour it already was. Nothing failed — the token existed, resolved and passed every
|
|
270
|
+
contrast pair. It is now `#00005c`, and **`check-tokens` rule I was widened from the surface
|
|
271
|
+
tiers to any ramp**, so a theme whose rest/hover/press tones collapse into each other fails the
|
|
272
|
+
build instead of shipping a state nobody can see. Found by sweeping all 11 themes rather than by
|
|
273
|
+
the check that now catches it.
|
|
274
|
+
|
|
275
|
+
- **The other nine pressable surfaces had no press feedback either — now eight of them do.**
|
|
276
|
+
`.gog-btn:active` turned out to be the *only* `:active` rule in the library. `gogMenuItem`,
|
|
277
|
+
`gog-chip`, `gog-tabs` headers, `gog-accordion` headers, `gog-button-toggle-group` options and
|
|
278
|
+
the `gog-select` / `gog-multiselect` / `gog-autocomplete` option rows all acknowledged a press
|
|
279
|
+
through the ripple alone — which is off by default and suppressed under reduced motion — so a
|
|
280
|
+
default-configured app confirmed a press nowhere at all. Each now paints
|
|
281
|
+
`--gog-<block>-press-bg`: a wash roughly double the 10-12% one its own hover uses, in the same
|
|
282
|
+
ingredient, with a flat `--gog-border-color` for browsers without `color-mix()`. Two of them
|
|
283
|
+
are not that shape and say so in place: a `gog-tabs` header paints no background in any other
|
|
284
|
+
state (its hover moves the label colour only), and a *selected* button-toggle option is already
|
|
285
|
+
filled, so it deepens to `--gog-accent-dim` the way the filled button variants do.
|
|
286
|
+
|
|
287
|
+
**`gogCollapsibleTrigger` is deliberately not in that list.** It is the consumer's own element
|
|
288
|
+
and the library paints nothing on it — no background at rest, none on hover, only a cursor and
|
|
289
|
+
a disabled state. A press colour there would be the library inventing a look for markup it does
|
|
290
|
+
not own, and inventing it for one state out of three. The same reasoning `docs/ripple.md`
|
|
291
|
+
records for `gogCardLink` and `gog-table` rows.
|
|
292
|
+
|
|
293
|
+
The three option rows' press rules are guarded against the disabled modifier; their **hover**
|
|
294
|
+
rules are not, and were left alone — a disabled option lighting up under the pointer is a
|
|
295
|
+
separate decision from this one, and it is filed rather than folded in.
|
|
296
|
+
|
|
297
|
+
- **A disabled option no longer lights up under the pointer, and no longer ripples.** Two
|
|
298
|
+
separate holes in the same place. `.gog-select__option:hover` and `.gog-ms__option:hover`
|
|
299
|
+
carried no disabled guard, so a row that cannot be chosen took the same hover background as one
|
|
300
|
+
that can — only its opacity and its cursor disagreed, and neither is what a hover is read for.
|
|
301
|
+
`gog-autocomplete` already had this right (`:not([aria-disabled='true'])`), which is where the
|
|
302
|
+
fix was copied from. And all **three** wired `gogRipple` with `[rippleDisabled]="!rippleEnabled()"`,
|
|
303
|
+
taking no account of the option's own state: with the ripple switched on app-wide, a disabled
|
|
304
|
+
row answered a press with a wave. The options are rendered `aria-disabled`, not `disabled`, so
|
|
305
|
+
nothing else was stopping it. Same argument the library already applied to a non-interactive
|
|
306
|
+
`gog-chip`: a wave is a promise, and these rows cannot keep it.
|
|
307
|
+
|
|
308
|
+
- **The outline button's label was unreadable while hovered, in every shipped theme.**
|
|
309
|
+
`--gog-button-outline-hover-color` resolved to `--gog-primary-color`, the colour of text on the
|
|
310
|
+
*page*, while the hover fill is the accent — pale parchment on bright amber in `dark` (1.41:1),
|
|
311
|
+
light grey on blue in `one-dark` (1.11:1), and failing WCAG AA in all 11 themes, the best of
|
|
312
|
+
them `light` at 3.65:1. It now resolves to `--gog-accent-text-color`, the token that means "text
|
|
313
|
+
on an accent fill" and the one both filled variants already used. Found while adding the state
|
|
314
|
+
above, which would have copied the same mistake into `:active`.
|
|
315
|
+
|
|
316
|
+
- **`check:contrast` gained the pair that hid both.** The script had no pair for a label on the
|
|
317
|
+
accent *fill* other than `accentText/accent`, so neither the outline label nor the new held
|
|
318
|
+
state was covered. `accentText/accentDim(active)` is now checked at 4.5:1, and it immediately
|
|
319
|
+
failed one theme: `one-dark`'s `--gog-accent-dim` moved from `#4b8fca` to `#5399d6` (4.05:1 →
|
|
320
|
+
4.59:1). That token had only ever been a field border, which is gated at 3:1; making it a fill
|
|
321
|
+
under a label is what raised the bar. The nudge moves it toward this palette's own `#61afef`,
|
|
322
|
+
so unlike 21.7.0's two comment-colour corrections it costs no fidelity.
|
|
323
|
+
|
|
324
|
+
- **Ten pieces of geometry ignored `--gog-density`, and nine of the eleven themes set it.**
|
|
325
|
+
`terminal` runs at 0.85, `one-dark`/`one-light`/`bevel`/`ledger` at 0.9, `primeng` at 0.95,
|
|
326
|
+
`slate` at 1.05, `material`/`parchment` at 1.1 — so in every one of them these ten stayed at
|
|
327
|
+
the pixel they were typed as while everything around them moved. The clearest case is the gap
|
|
328
|
+
between a dropdown and its panel: `gog-autocomplete` and `gog-datepicker` read `--gog-space-2`,
|
|
329
|
+
while `gog-select` and `gog-multiselect` restated `2px`, so in `terminal` two of the four
|
|
330
|
+
panels drew closer to their field and two did not. Also converted: `--gog-menu-offset` (which
|
|
331
|
+
sat between `--gog-menu-padding` and `--gog-menu-gap`, both already reading the scale),
|
|
332
|
+
`--gog-input-clear-inset` (the textarea's clear button — the other four clearable fields place
|
|
333
|
+
their chrome from `--gog-control-icon-offset`), the two error-line offsets, the toggle's
|
|
334
|
+
in-track wording clearance, the badge's overhang, and the calendar's header and time-row
|
|
335
|
+
margins. Each now reads its scale step, so all ten render exactly as before at the default
|
|
336
|
+
density and follow the theme everywhere else.
|
|
337
|
+
|
|
338
|
+
- **Four focus rings did not follow `--gog-focus-ring-offset`.** `gog-button-toggle` restated
|
|
339
|
+
its `2px` on the line directly after reading `--gog-focus-ring-width` from the foundation;
|
|
340
|
+
`gog-button` used `3px`; `gog-calendar` and `gog-tabs` used `-2px` to sit the ring inside a
|
|
341
|
+
cell, because both pack their cells edge to edge and an outward ring lands on the neighbour.
|
|
342
|
+
All four now derive from the foundation token — `var(…)`, `calc(… + 1px)` and `calc(… * -1)` —
|
|
343
|
+
so a theme that moves the ring moves them with it, and the two negative values now say in the
|
|
344
|
+
file why they are negative. No rendered value changes.
|
|
345
|
+
|
|
346
|
+
- **`check-tokens` rule H only covered two of the six families that hold a spacing number.**
|
|
347
|
+
The density check was written for `-padding` and `-gap`, the two the density work had just
|
|
348
|
+
converted, and `-offset`, `-inset` and `-margin` went unwatched for three releases — which is
|
|
349
|
+
where all ten literals above were hiding. The name filter now covers all six, and exempts the
|
|
350
|
+
lengths that match a scale step by coincidence rather than by meaning: every
|
|
351
|
+
`*-focus-ring-offset` (an accessibility affordance, which a compact theme must not shrink, and
|
|
352
|
+
which a component should answer by reading the foundation ring rather than a spacing step),
|
|
353
|
+
plus the scrollbar and toggle thumb insets, both fitted to a track whose own width is a fixed
|
|
354
|
+
pixel value. The script's header now also lists rules H and I, which had been in it unlisted
|
|
355
|
+
since they were added.
|
|
356
|
+
|
|
357
|
+
- **`gogBadge`'s status variants failed WCAG AA in four themes, and had since they shipped.** A
|
|
358
|
+
status badge paints `--gog-<status>-color` and labelled it `--gog-accent-text-color`, which on
|
|
359
|
+
a light theme is white: `material`'s amber measured **1.97:1**, `primeng`'s green 2.28:1, and
|
|
360
|
+
`slate` and `one-light` failed on all three of success/warning/info — 11 pairs in total.
|
|
361
|
+
`danger` passed everywhere, which is the tell: a danger pair was added to `check:contrast` on
|
|
362
|
+
2026-09-03 and the palettes were tuned to it, while the other three statuses had never been
|
|
363
|
+
measured against anything.
|
|
364
|
+
|
|
365
|
+
Half the fix costs no fidelity: `material` puts near-black on its amber (8.69:1) and `primeng`
|
|
366
|
+
does the same on all three of Aura's bright hues (6.44–8.31:1), which is what both design
|
|
367
|
+
systems do themselves. The other half had no label to pick — neither white nor the theme's own
|
|
368
|
+
ink reached AA — so the hue moved instead, one step down each theme's own ramp: `slate`'s three
|
|
369
|
+
to Tailwind's 700s, `material`'s blue to Light Blue 800, and `one-light`'s three darkened, the
|
|
370
|
+
same trade that theme already made on its accent and muted tokens in 21.7.0.
|
|
371
|
+
|
|
372
|
+
**The reason no check caught it generalises past the badge.** `check:contrast`'s automatic
|
|
373
|
+
sweep pairs a rule that sets `color` with the `background-color` beside it; a variant class
|
|
374
|
+
sets neither, only `--gog-badge-variant-bg`/`-color` for the base rule to read. Every variant
|
|
375
|
+
of every component is written that way, so the sweep had been reporting ~180 passing states
|
|
376
|
+
without looking at one of them. Four explicit badge pairs close it for this component; the
|
|
377
|
+
general fix is filed in `docs/backlog.md`.
|
|
378
|
+
|
|
379
|
+
- **Two fields put their error line 2px lower than the other six.** Every control that renders an
|
|
380
|
+
error — `gog-inputfield`, `gog-textarea`, `gog-select`, `gog-multiselect`, `gog-autocomplete`,
|
|
381
|
+
`gog-datepicker`, `gog-radio-group`, `gog-slider` — is a flex column whose own gap already
|
|
382
|
+
separates the error from the field, the same gap that separates the label from it. Two of them
|
|
383
|
+
then added `margin-top: 2px` on top: measured in a browser, `gog-inputfield` and
|
|
384
|
+
`gog-multiselect` sat at 6px while `gog-select`, `gog-autocomplete` and `gog-datepicker` sat at
|
|
385
|
+
4px from the identical gap. In one form, side by side, the six did not line up.
|
|
386
|
+
`--gog-input-error-offset` and `--gog-multiselect-error-offset` now default to `0`, so one
|
|
387
|
+
mechanism spaces the error line everywhere; both tokens stay, and setting one still pushes that
|
|
388
|
+
field's error further than the rest.
|
|
389
|
+
|
|
7
390
|
## [21.8.0] - 03.09.2026
|
|
8
391
|
|
|
9
392
|
### Added
|