@guildofgleks/ui 21.4.0 → 21.4.2
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 +36 -13
- package/CHANGELOG.md +957 -0
- package/README.md +99 -361
- package/fesm2022/guildofgleks-ui.mjs +37 -10
- package/fesm2022/guildofgleks-ui.mjs.map +1 -1
- package/package.json +10 -1
- package/types/guildofgleks-ui.d.ts +2 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@guildofgleks/ui` are documented here. Format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/); this project has not yet
|
|
5
|
+
reached 1.0, so breaking changes may land in minor versions.
|
|
6
|
+
|
|
7
|
+
## [21.5.0] - planned
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`CHANGELOG.md` now ships inside the npm package**, alongside `README.md`, `AGENTS.md` and
|
|
12
|
+
`TOKENS.md`. It was repo-only, which meant the documentation site could not render release
|
|
13
|
+
notes for the exact version a reader has installed — the only source that cannot drift, since
|
|
14
|
+
it travels with the package rather than being copied next to it. Nothing changes for a
|
|
15
|
+
consumer who does not read it; the file adds a few KB to the tarball.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **`AGENTS.md` was missing `gog-slider`'s range mode.** `range`, `rangeValue`
|
|
20
|
+
(`GogSliderRange`), `startDisabled`/`endDisabled` and `startAriaLabel`/`endAriaLabel` shipped
|
|
21
|
+
in 21.3.1 but never reached the agent reference, so an agent reading it would conclude the
|
|
22
|
+
slider cannot express a range and build a two-slider workaround.
|
|
23
|
+
- **`AGENTS.md` did not mention the `GOG_ICONS` token.** `provideGogIcons(...)` was documented,
|
|
24
|
+
but not the token it provides — which is what an app injects to read the registered set back
|
|
25
|
+
(an icon picker enumerating it). Public since 21.4.0, undocumented until now.
|
|
26
|
+
|
|
27
|
+
## [21.4.1] - 14.08.2026
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **Overlays ignored custom properties set on `:root`.** A select panel, tooltip or any other
|
|
32
|
+
overlay rendered into `<body>` copied the `data-theme` of its trigger's nearest themed
|
|
33
|
+
ancestor. When that ancestor is `<html>` — the usual case — the copy made the overlay match
|
|
34
|
+
`theme.css`'s derived layer (`:root, [data-theme]`) *locally*, re-declaring every component
|
|
35
|
+
token against the plain preset palette and discarding anything set on the root that the preset
|
|
36
|
+
does not itself declare.
|
|
37
|
+
|
|
38
|
+
Inline custom properties are what this hit: a page that overrides `--gog-*` on
|
|
39
|
+
`document.documentElement` — a live theme editor, or any runtime accent switch — saw the
|
|
40
|
+
document follow while every overlay kept rendering the un-edited theme.
|
|
41
|
+
|
|
42
|
+
The attribute is now copied only for a genuinely *scoped* theme, where the overlay would
|
|
43
|
+
otherwise pick up the document's; when the theme sits on the document element, inheritance
|
|
44
|
+
already does the work. Several themes rendered side by side in scoped subtrees keep working
|
|
45
|
+
exactly as before.
|
|
46
|
+
|
|
47
|
+
## [21.4.0] - 14.08.2026
|
|
48
|
+
|
|
49
|
+
A minor rather than a patch: this adds public API. Iterations 5 and 6 of the consumer-DX plan
|
|
50
|
+
(`docs/consumer-dx-plan.md`).
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- **`gog-table`: outputs.** The component had none at all, which is what made it a display-only
|
|
55
|
+
grid. `gogSortChange` (`{ field, direction }`, including the third click that clears the sort),
|
|
56
|
+
`gogPageChange` (the new 1-based page), and `gogRowClick`
|
|
57
|
+
(`{ row, index, originalEvent }`).
|
|
58
|
+
|
|
59
|
+
`gogPageChange` deliberately stays quiet in two cases: the initial render, and the reset to
|
|
60
|
+
page 1 that a new sort causes — that reset is part of the sort, and a consumer refetching from
|
|
61
|
+
both events would issue two requests for one user action.
|
|
62
|
+
- **`gog-table`: `lazy` — server-driven sorting and paging.** With `[lazy]="true"` the table
|
|
63
|
+
stops sorting and slicing `value` and renders it exactly as handed over, treating it as the
|
|
64
|
+
current page; `totalRecords` tells the paginator how many pages exist, and the two outputs are
|
|
65
|
+
the refetch signals. Row numbering still counts from the current page, and `showTotal` reports
|
|
66
|
+
`totalRecords` rather than `value.length`. Without `totalRecords` pagination stays hidden and
|
|
67
|
+
the table warns in dev mode. Until now the table sorted and paged purely in memory, so anything
|
|
68
|
+
backed by a real endpoint had to be built on something else.
|
|
69
|
+
- **`gog-table`: row selection.** `selectionMode` (`'none' | 'single' | 'multiple'`) plus a
|
|
70
|
+
two-way `[(selection)]`, always a `T[]` — in `'single'` mode it simply holds zero or one row,
|
|
71
|
+
which is one shape to read rather than a `T | T[] | null` union to narrow. A checkbox column
|
|
72
|
+
renders automatically (`showSelectionColumn` turns it off), and the header select-all appears
|
|
73
|
+
only in `'multiple'` mode.
|
|
74
|
+
|
|
75
|
+
**The select-all covers the current page, not the whole data set** — in `lazy` mode the table
|
|
76
|
+
has never seen the other pages, and a control that meant different things in the two modes
|
|
77
|
+
would be worse than either behaviour on its own.
|
|
78
|
+
- **`gog-table`: `dataKey`.** The field (or dot-path) identifying a row. Selection matches on it
|
|
79
|
+
instead of object identity — without it a refetch producing new objects silently drops the
|
|
80
|
+
selection — and it becomes the `@for` track key, so the rendered DOM survives a refetch of the
|
|
81
|
+
same page instead of being torn down and rebuilt.
|
|
82
|
+
- **`gog-table`: `interactiveRows`.** Makes rows focusable and styles them as clickable, with
|
|
83
|
+
Enter and Space activating the focused row. `gogRowClick` fires on a click either way; this is
|
|
84
|
+
what stops a whole-row target from being mouse-only.
|
|
85
|
+
- **`[gogButton]` — a link that looks like a button.** `gog-button` renders its own `<button>`,
|
|
86
|
+
so it could never *be* a link, and a large share of buttons on a real site are navigation. The
|
|
87
|
+
directive inverts the relationship: the element stays the consumer's, and only the look is
|
|
88
|
+
applied.
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<a gogButton routerLink="/pricing">See pricing</a>
|
|
92
|
+
<a gogButton variant="ghost" href="https://example.com" target="_blank" rel="noreferrer">Docs</a>
|
|
93
|
+
<button gogButton variant="outline" size="sm" type="submit">Save</button>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Chosen over an `as="a"` / `routerLink` input trio on `gog-button` because that would mean
|
|
97
|
+
brokering the router's whole input surface through the component **and taking a dependency on
|
|
98
|
+
`@angular/router`** — a fifth peer, and one that would break every app without a router. With
|
|
99
|
+
the directive, `routerLink`, `href`, `target`, `download`, `type="submit"` and anything else
|
|
100
|
+
keep working because they were never taken away.
|
|
101
|
+
|
|
102
|
+
`variant`, `size` and `fullWidth` behave exactly as on the component, `size` included in its
|
|
103
|
+
`GOG_CONFIG.control.size` fallback. It deliberately has no `disabled` (there is no such thing
|
|
104
|
+
on an `<a>`) and no `loading` (the spinner is a projected child a directive cannot add). The
|
|
105
|
+
selector is `a[gogButton], button[gogButton]`, not a bare attribute, so it cannot be put on a
|
|
106
|
+
`<div>` and produce something that looks clickable and is invisible to the keyboard.
|
|
107
|
+
- **`gog-paginator`: a rows-per-page select.** `showPageSizeSelect` turns it on (**off by
|
|
108
|
+
default** — a paginator that silently grew a control would change every existing layout) and
|
|
109
|
+
`pageSizeOptions` sets the choices, defaulting to `[10, 20, 30, 40, 50]`. Both are also
|
|
110
|
+
settable app-wide through the new `GOG_CONFIG.paginator`, so one page can offer `5, 10, 20`
|
|
111
|
+
while the rest of the app uses the house default.
|
|
112
|
+
- **`gog-paginator`: `pageSize` (a `model`) and `totalRecords`.** Given `totalRecords`, the
|
|
113
|
+
paginator derives the page count from `pageSize` itself — which removes the
|
|
114
|
+
`computed(() => Math.ceil(total / size))` a consumer would otherwise have to write *and* keep
|
|
115
|
+
in sync with the select. `totalPages` still works and is right when a server hands you a page
|
|
116
|
+
count directly; `totalRecords` wins if both are set. Changing the size returns to page 1:
|
|
117
|
+
"page 5" of 10-row pages is not "page 5" of 50-row ones, so clamping alone would leave the user
|
|
118
|
+
somewhere they never asked to be.
|
|
119
|
+
- **`gog-table`: `showPageSizeSelect` / `pageSizeOptions`**, forwarded to its paginator, and
|
|
120
|
+
**`GOG_CONFIG.labels.rowsPerPage`** for the select's accessible name.
|
|
121
|
+
- **`GOG_CONFIG.labels`: `total`, `tablePagination`, `selectRow`, `selectAllRows`.** The table's
|
|
122
|
+
own chrome — the row-count label read `Total:` from a hardcoded string, and its paginator was
|
|
123
|
+
labelled `Table pagination` with no way to change either.
|
|
124
|
+
|
|
125
|
+
- **`provideGogIcons(...)` — register your own icons by name.** `gog-icon` shipped a closed set
|
|
126
|
+
of 20 glyphs, and the only way to render anything else was a `TemplateRef` per instance,
|
|
127
|
+
which costs an `<ng-template>` at every use site and does not work at all for the components
|
|
128
|
+
that take an icon *name* (`gog-tag`, `gog-chip`, `gog-tabs`, `gog-button-toggle-group`,
|
|
129
|
+
`ToastService`, `DialogService`). In practice that meant installing a second icon library —
|
|
130
|
+
precisely the dependency the "no CDK, no Material" footprint exists to avoid.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// app.config.ts
|
|
134
|
+
providers: [provideGogIcons({ cart: '<svg viewBox="0 0 24 24">…</svg>' })];
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<gog-icon name="cart" />
|
|
139
|
+
<gog-tag iconName="cart">In basket</gog-tag>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- A registered name **overrides a built-in of the same name**, so an app can replace the
|
|
143
|
+
library's checkmark or chevrons everywhere without touching a single component.
|
|
144
|
+
- Providing it again lower in the injector tree **layers onto** the parent set rather than
|
|
145
|
+
replacing it, matching `provideGogConfig`.
|
|
146
|
+
- The registry is also exposed as the `GOG_ICONS` injection token.
|
|
147
|
+
- **`GogBuiltinIconName`** — the closed union of the shipped glyphs, for code that wants
|
|
148
|
+
exhaustiveness (an icon gallery, a `Record` keyed by icon).
|
|
149
|
+
- **21 more built-in icons, taking the set from 20 to 41.** The old set covered what the
|
|
150
|
+
library's own components needed and almost nothing an app needs: there was no `search` for a
|
|
151
|
+
field, no `trash` for a destructive action, no `more-vertical` for a table row menu. Added, all
|
|
152
|
+
Lucide, all on the same 24×24 / stroke-2 grid as the existing ones:
|
|
153
|
+
- actions — `search`, `plus`, `minus`, `trash`, `pencil`, `download`, `upload`, `refresh`,
|
|
154
|
+
`filter`, `external-link`;
|
|
155
|
+
- chrome — `menu`, `more-horizontal`, `more-vertical`, `settings`;
|
|
156
|
+
- navigation — `arrow-left`, `arrow-right` (distinct from the chevrons, which read as
|
|
157
|
+
disclosure rather than movement);
|
|
158
|
+
- objects and state — `user`, `lock`, `mail`, `star`, `star-filled`.
|
|
159
|
+
|
|
160
|
+
`star`/`star-filled` is the only outline/filled pair, for a rating or favourite **toggle** —
|
|
161
|
+
the same case `checkbox`/`checkbox-checked` already covers. The set stays outline-only
|
|
162
|
+
otherwise: a solid duplicate of every glyph would double the payload for a distinction almost
|
|
163
|
+
nothing needs, and `provideGogIcons` covers the exceptions.
|
|
164
|
+
|
|
165
|
+
Cost: `ICON_DEFS` is one object, so every consumer pays for all of it — it grew from 8.0 KB to
|
|
166
|
+
16.5 KB raw, **1.6 KB to 2.7 KB gzipped**.
|
|
167
|
+
- **Attribution for the icons.** The glyphs were always Lucide but the package said so nowhere;
|
|
168
|
+
Lucide's ISC licence asks for the notice to travel with them. It is now at the top of
|
|
169
|
+
`icons.ts` and summarised in the README's licence section.
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
|
|
173
|
+
- **The button's `.gog-btn*` block moved from the component stylesheet into
|
|
174
|
+
`styles/button.css`**, which `styles/index.css` imports. Angular's emulated encapsulation
|
|
175
|
+
would never let a component stylesheet reach an `<a>` declared in a consumer's template, so
|
|
176
|
+
`[gogButton]` needs the rules to be global — the same reason `gogBadge` and `gog-collapsible`
|
|
177
|
+
already keep theirs there. One source for both, no duplication. Costs about 1 KB gzipped in the
|
|
178
|
+
always-loaded stylesheet; nothing changes for anyone already importing `index.css`, which the
|
|
179
|
+
Setup section has always required.
|
|
180
|
+
- **`npm run check:tokens` now covers the global stylesheets too.** It scanned `lib/**/*.scss`
|
|
181
|
+
plus a hardcoded `utilities.css`; it now walks `styles/*.css` as a directory, so a new global
|
|
182
|
+
stylesheet is under the token contract the moment it exists rather than whenever someone
|
|
183
|
+
remembers to add it. 34 stylesheets checked before, 38 now.
|
|
184
|
+
- **`gog-table`'s `pageSize` is a `model`, not an `input`.** `[pageSize]="20"` is unchanged;
|
|
185
|
+
`[(pageSize)]="size"` is now possible, and that is what lets the rows-per-page select work with
|
|
186
|
+
no wiring — the table binds its own model straight to the paginator's, so nothing is ferried
|
|
187
|
+
between the two by hand. `pageSizeChange` comes free from the model and is the refetch signal
|
|
188
|
+
in `lazy` mode.
|
|
189
|
+
- **The table footer no longer hides at a single page while the size select is on.** Hiding it
|
|
190
|
+
would strand the user on whatever size produced that one page, with no control left to choose a
|
|
191
|
+
smaller one. With the select off, the old behaviour is unchanged.
|
|
192
|
+
- **`GogIconName` is now open: `GogBuiltinIconName | (string & {})`.** The built-ins still
|
|
193
|
+
autocomplete; a registered name is now accepted wherever an icon name is taken, with no change
|
|
194
|
+
at any of the ten call sites that use the type. The trade is deliberate and comes with the
|
|
195
|
+
registry: a typo is no longer a compile error, so **an unknown name renders nothing and warns
|
|
196
|
+
in dev mode** (once per name) instead of throwing — an icon is decoration, and failing a render
|
|
197
|
+
over a glyph name would be the worse failure. Code that relied on `GogIconName` being closed
|
|
198
|
+
— an exhaustive `switch`, `Record<GogIconName, …>` — should move to `GogBuiltinIconName`.
|
|
199
|
+
|
|
200
|
+
### Fixed
|
|
201
|
+
|
|
202
|
+
- **Buttons no longer inherit the anchor underline.** `.gog-btn` never reset `text-decoration`,
|
|
203
|
+
because a `<button>` has none to reset — the moment the same block landed on an `<a>` via
|
|
204
|
+
`[gogButton]`, every link-button came out underlined.
|
|
205
|
+
- **`--gog-icon-stroke-width` now applies to every shape in an icon.** The rule listed only
|
|
206
|
+
`path`, `circle` and `rect` — which happened to be all the original 20 glyphs used, so the gap
|
|
207
|
+
was invisible. Any icon drawn with `line`, `polyline` or `polygon` (half the new ones, and
|
|
208
|
+
whatever a consumer registers) silently ignored the token and fell back to the `stroke-width`
|
|
209
|
+
attribute baked into its own markup. `ellipse` is covered too.
|
|
210
|
+
|
|
211
|
+
## [21.3.2] - 13.08.2026
|
|
212
|
+
|
|
213
|
+
First batch of the consumer-DX plan (`docs/consumer-dx-plan.md`, iterations 1–4): the seam
|
|
214
|
+
between the package and the developer installing it — setup that failed on the documented
|
|
215
|
+
path, accessibility that depended on optional inputs, and native attributes a wrapper component
|
|
216
|
+
made unreachable.
|
|
217
|
+
|
|
218
|
+
### Added
|
|
219
|
+
|
|
220
|
+
- **The baseline stylesheet now also ships at `@guildofgleks/ui/styles/`.** This is the path the
|
|
221
|
+
README has always documented, and until now it did not exist in the package — the files were
|
|
222
|
+
only under `src/styles/`, so a setup copied from the README failed on a missing file and every
|
|
223
|
+
component rendered unstyled. Both paths ship for one deprecation window, and `package.json`'s
|
|
224
|
+
`exports` map now lists them, so `@import '@guildofgleks/ui/styles/index.css'` resolves from
|
|
225
|
+
SCSS as well as from `angular.json`.
|
|
226
|
+
- **`gog-inputfield` / `gog-textarea`: the native attribute space.** `readonly`, `maxlength`,
|
|
227
|
+
`minlength`, `spellcheck`, plus `pattern` and `inputMode` on the input. `readonly` differs
|
|
228
|
+
from `disabled` in the usual way (still focusable, still submitted) and suppresses the clear
|
|
229
|
+
button and the number field's spin buttons, since both offer an edit the field would refuse.
|
|
230
|
+
`autofocus` is deliberately **not** forwarded — moving focus unasked is a documented a11y
|
|
231
|
+
problem and the repo's own lint rule rejects it.
|
|
232
|
+
- **`gog-inputfield`: `tel`, `url`, `search`, `time` and `datetime-local` types**, via the new
|
|
233
|
+
exported `GogInputType`. The new `GogInputMode` types the `inputMode` input.
|
|
234
|
+
- **`GOG_CONFIG.labels`.** App-wide defaults for every fixed string the library renders —
|
|
235
|
+
`clear`, `clearSelection`, `clearDate`, `selectAll`, `clearAll`, `increment`, `decrement`,
|
|
236
|
+
`showPassword`, `hidePassword`, `closeDialog`, `closeToast`, `pagination`, `previousPage`,
|
|
237
|
+
`nextPage`, `openCalendar`, `today`, `thisMonth`, `previousMonth`, `nextMonth`,
|
|
238
|
+
`previousYear`, `nextYear`, `hours`, `minutes`, `seconds`, plus `page` (a formatter — see
|
|
239
|
+
Fixed). A non-English app relabels the library once instead of on every instance.
|
|
240
|
+
Per-instance inputs still win where they exist.
|
|
241
|
+
- **`gog-multiselect`: `selectAllLabel` / `clearAllLabel`.** The panel's two buttons rendered
|
|
242
|
+
literal `Select all` / `Clear` with no way to change them at all.
|
|
243
|
+
- **`gog-calendar`: `hoursLabel` / `minutesLabel` / `secondsLabel`.** The time section's three
|
|
244
|
+
fields had hardcoded English `aria-label`s.
|
|
245
|
+
- **`GOG_CONFIG.theme`.** `storageKey` persists the chosen theme in `localStorage`;
|
|
246
|
+
`followSystem` opens in the OS `prefers-color-scheme` setting and keeps following it until the
|
|
247
|
+
app calls `setTheme`; `defaultTheme`, `lightTheme` and `darkTheme` name the themes involved.
|
|
248
|
+
All off by default, so an app that configures nothing keeps today's behaviour exactly.
|
|
249
|
+
- **`@angular/platform-browser` is now declared as a peer dependency.** `gog-icon` has always
|
|
250
|
+
imported `DomSanitizer` from it; the omission only worked because npm's flat tree hides it,
|
|
251
|
+
and broke under strict pnpm.
|
|
252
|
+
|
|
253
|
+
### Fixed
|
|
254
|
+
|
|
255
|
+
- **Form controls are labelled without an `inputId`.** `gog-inputfield` and `gog-textarea` now
|
|
256
|
+
generate an id when none is given, so the `<label for>` actually points at the field (clicking
|
|
257
|
+
the label focuses it, assistive tech gets a name) and the error message is reachable through
|
|
258
|
+
`aria-describedby`. Previously both were silently dropped unless the consumer happened to pass
|
|
259
|
+
`inputId` — the default configuration was inaccessible. `gog-select` already worked this way;
|
|
260
|
+
the id generator is now shared (`gog-radio-group` and `gog-slider` use it too, with unchanged
|
|
261
|
+
output).
|
|
262
|
+
- **`aria-describedby` no longer points at an element that isn't rendered.** It was keyed off
|
|
263
|
+
`hasError()`, while the message element renders on `visibleError()` — with `errorDisplay="auto"`
|
|
264
|
+
and an empty `errorMessage` the two disagree.
|
|
265
|
+
- **Toasts are announced reliably.** `aria-live` moved off the individual toast, which enters the
|
|
266
|
+
DOM together with its own text (a live region created at the same moment as its content is
|
|
267
|
+
routinely skipped by screen readers), onto two permanently-mounted regions in
|
|
268
|
+
`gog-toast-container` — polite, and assertive for `error`/`warning`. Individual toasts no longer
|
|
269
|
+
carry `role`/`aria-live`, so nothing is announced twice.
|
|
270
|
+
- **`gog-inputfield`: the clear button on a number field wrote `''` instead of `null`.** A
|
|
271
|
+
`FormControl<number | null>` ended up holding a string, which then failed numeric validators
|
|
272
|
+
and round-tripped the wrong type. It now writes exactly what emptying the field by hand writes.
|
|
273
|
+
- **`ThemeService.theme` is read-only.** It was a writable signal, so `theme.set(...)` moved the
|
|
274
|
+
signal without touching the `data-theme` attribute the styles read, leaving the two out of
|
|
275
|
+
sync. Use `setTheme`/`toggleTheme`.
|
|
276
|
+
- **`gog-inputfield`: a `clearable` number field had no clear button.** The stepper and the
|
|
277
|
+
clear button share the field's end slot, and the stepper won outright — so `clearable` was
|
|
278
|
+
silently a no-op on `type="number"` unless `showSpinButtons` was also off. Both now render:
|
|
279
|
+
the clear button sits one stepper-width further in, and the field's text gutter widens to fit
|
|
280
|
+
the pair (`--gog-input-spin-width`, new). It still disappears when there is nothing to clear,
|
|
281
|
+
taking the extra gutter with it.
|
|
282
|
+
- **`gog-calendar` now reads `GOG_CONFIG.datepicker`.** `locale` and `firstDayOfWeek` were
|
|
283
|
+
documented as applying to `gog-calendar` as well as `gog-datepicker`, but the calendar only
|
|
284
|
+
ever honoured its own inputs — so a standalone `<gog-calendar>` in an app with an app-wide
|
|
285
|
+
locale silently rendered in `en-US`. Rendered through `gog-datepicker` nothing changes: that
|
|
286
|
+
component passes its own already-resolved values, which still win.
|
|
287
|
+
- **`gog-paginator`: the per-page button names are translatable.** "Go to page 4" / "Page 4,
|
|
288
|
+
current page" were built by string concatenation in the template. They now come from
|
|
289
|
+
`GOG_CONFIG.labels.page`, a `(page, isCurrent) => string` formatter — a function rather than a
|
|
290
|
+
placeholder string, since the number's position and the grammar around it are language
|
|
291
|
+
dependent.
|
|
292
|
+
- **The textarea resize grip's offsets are real tokens.** `--gog-textarea-resize-grip-offset`
|
|
293
|
+
and `--gog-textarea-resize-inset-right`/`-bottom` are declared in `theme.css` instead of
|
|
294
|
+
living as literal `var()` fallbacks in the component stylesheet, which the token-contract
|
|
295
|
+
check (`npm run check:tokens`) had been failing on. Geometry is unchanged.
|
|
296
|
+
|
|
297
|
+
### Changed
|
|
298
|
+
|
|
299
|
+
- **The generated token catalogue moved from `README.md` to `TOKENS.md`.** It was ~200 KB of
|
|
300
|
+
reference table in the middle of the README, burying the Setup section that a new consumer has
|
|
301
|
+
to find within seconds on npm. The README keeps the three-layer explanation and links across;
|
|
302
|
+
the README itself is now ~14 KB. `GOG_TOKEN_GROUPS` is unaffected.
|
|
303
|
+
- **README: `<gog-dialog />` and `<gog-toast-container />` are documented.** `DialogService.open()`
|
|
304
|
+
and `ToastService.show()` render nothing until those host elements are in a template, which
|
|
305
|
+
the README never said.
|
|
306
|
+
- **README: a `## Global configuration` section.** `provideGogConfig` was never documented in the
|
|
307
|
+
README at all — only individual keys mentioned in passing — so the app-wide settings, and now
|
|
308
|
+
`labels` and `theme` with them, were undiscoverable to anyone reading the package page. Adds
|
|
309
|
+
the key list, the precedence rule, the injector-tree merge, and a translation example.
|
|
310
|
+
- **README / `AGENTS.md`: the new API is documented.** Both ship inside the package. `AGENTS.md`
|
|
311
|
+
(the consumer-facing agent reference) has the native attributes, `GOG_CONFIG.labels` and
|
|
312
|
+
`.theme`, the read-only `ThemeService.theme`, generated field ids, the toast live regions, and
|
|
313
|
+
`GogInputType`/`GogInputMode` in its type table.
|
|
314
|
+
- **README: the component list is complete again.** It advertised 18 components and listed 21,
|
|
315
|
+
while omitting `gog-autocomplete`, `gogBadge`, `gog-button-toggle-group`, `gog-datepicker`,
|
|
316
|
+
`gog-divider`, `gog-progressbar`, `gog-tabs` and `gog-toggle` entirely.
|
|
317
|
+
- Label inputs that now resolve through `GOG_CONFIG.labels` changed their default from a literal
|
|
318
|
+
string to `undefined` (`clearAriaLabel`, `incrementLabel`, `decrementLabel`, `showPasswordLabel`,
|
|
319
|
+
`hidePasswordLabel`, `todayLabel`, `thisMonthLabel`, `previousMonthLabel`, `nextMonthLabel`,
|
|
320
|
+
`previousYearLabel`, `nextYearLabel`, `openCalendarLabel`, `gog-paginator`'s `ariaLabel`).
|
|
321
|
+
Rendered output is identical unless the app configures `labels`; only reading the input back
|
|
322
|
+
in TypeScript now yields `undefined` rather than the English default. `gog-calendar`'s
|
|
323
|
+
`locale` and `firstDayOfWeek` changed the same way, for the same reason.
|
|
324
|
+
|
|
325
|
+
### Deprecated
|
|
326
|
+
|
|
327
|
+
- `@guildofgleks/ui/src/styles/…` — use `@guildofgleks/ui/styles/…`. Both ship until **21.5.0**,
|
|
328
|
+
when the `src/styles/` copy is removed.
|
|
329
|
+
|
|
330
|
+
## [21.3.1] - 11.08.2026
|
|
331
|
+
|
|
332
|
+
### Added
|
|
333
|
+
|
|
334
|
+
- **`gog-slider`: `range`.** Switches the slider to two independently focusable native
|
|
335
|
+
thumbs for picking a span instead of a single value — bind `[(rangeValue)]` (a
|
|
336
|
+
`GogSliderRange` `{ start, end }` pair) instead of `[(value)]`; the two are mutually
|
|
337
|
+
exclusive, and `writeValue`/the `ControlValueAccessor` follow whichever one `range` selects.
|
|
338
|
+
Neither thumb can be dragged, keyboard-nudged, or written past the other — crossing is
|
|
339
|
+
clamped in JS rather than through the native `min`/`max` attribute, since narrowing that
|
|
340
|
+
per thumb would desync the browser's own (invisible) thumb position from the custom
|
|
341
|
+
`--range-start-pos`/`--range-end-pos`-driven visuals. Works in both orientations and with
|
|
342
|
+
`showThumb`/`fullWidth`/`disabled`/error display exactly as the single-value mode does.
|
|
343
|
+
`startAriaLabel`/`endAriaLabel` (defaulting to `'Minimum'`/`'Maximum'`, prefixed with
|
|
344
|
+
`label()` when set) name the two thumbs for assistive tech, since a single `<label for>`
|
|
345
|
+
can't target both. The value readout (`showValue`) reserves stable width up front, sized
|
|
346
|
+
from `min()`/`max()`/`step()` rather than the live value, so it — and, in a `fit-content`
|
|
347
|
+
vertical slider, the whole control along with it — doesn't visibly resize on every drag.
|
|
348
|
+
- **`gog-slider`: `startDisabled`/`endDisabled`.** Disable just one thumb in `range` mode —
|
|
349
|
+
e.g. pin a range's floor while leaving its ceiling adjustable, or vice versa — instead of
|
|
350
|
+
`disabled`, which still takes out both together. ORed with `disabled` rather than
|
|
351
|
+
overriding it, and ignored outside `range` mode (nothing to disable "one side" of there). A
|
|
352
|
+
one-sided disable only dims and disables that one thumb (its native input's own `disabled`
|
|
353
|
+
attribute takes it out of the tab order); the whole-control `.gog-slider--disabled` styling
|
|
354
|
+
(dimming + `pointer-events: none` over the whole track) only kicks in once *both* sides are
|
|
355
|
+
disabled, since applying it for just one would also block pointer input to the other,
|
|
356
|
+
still-enabled thumb. Reactive forms are unaffected by this addition: a `[formControl]`'s own
|
|
357
|
+
`.disable()`/`.enable()` still speaks for both thumbs at once, same as before — one
|
|
358
|
+
`FormControl` backs one `rangeValue` and has no way to target just one side of it.
|
|
359
|
+
|
|
360
|
+
- **`gog-autocomplete`: `openOnFocus`.** Focusing the field now opens the panel immediately with
|
|
361
|
+
the full option list, ignoring `minLength` — the common "browse everything, then narrow it
|
|
362
|
+
down" pattern a plain type-ahead can't offer. On by default; turn it off (or set
|
|
363
|
+
`GOG_CONFIG.autocomplete.openOnFocus = false`) to keep the previous behaviour of nothing
|
|
364
|
+
showing until enough has been typed. The list stays unfiltered even when the field already
|
|
365
|
+
displays a previously-selected label, and normal filtering resumes on the first keystroke.
|
|
366
|
+
- **`gog-autocomplete`: `gogLoadMore`.** Fires once the panel is scrolled to the end of the
|
|
367
|
+
option list — the signal to fetch and append another page, instead of handing a huge or
|
|
368
|
+
server-backed source over up front (500,000 rows loaded 20 at a time, not all at once).
|
|
369
|
+
Forwarded from the panel's own `gog-scroll`.
|
|
370
|
+
- **`gog-tabs`: `scrollActiveIntoView`.** With an overflowing header row, selecting a tab —
|
|
371
|
+
by click, the arrow keys, or a consumer setting `activeIndex` directly — now scrolls the
|
|
372
|
+
header so the active tab stays in view, centered where there's room so its neighbours on
|
|
373
|
+
both sides stay visible too. The same "show what's around the current position" idea
|
|
374
|
+
`gog-paginator` already uses for pages. On by default; instant on first render, smooth (or
|
|
375
|
+
instant under `prefers-reduced-motion`) after. Turn it off to own the scroll position
|
|
376
|
+
yourself.
|
|
377
|
+
- **`gog-tabs`: `showScrollTrack`; `gog-scroll`: `showTrack`.** With `scrollActiveIntoView`
|
|
378
|
+
driving the header's scroll position, its own draggable thumb/track next to the active-tab
|
|
379
|
+
underline read as two conflicting position indicators for the same thing — confusing rather
|
|
380
|
+
than helpful, per feedback on the first cut of `scrollActiveIntoView`. `gog-tabs` now hides
|
|
381
|
+
the track by default while `scrollActiveIntoView` is on, and shows it by default once that's
|
|
382
|
+
off (the only way left to reach an off-screen tab by mouse); either can be pinned explicitly
|
|
383
|
+
with `showScrollTrack`, regardless of the other. Native scrolling — wheel, touch, keyboard,
|
|
384
|
+
and any programmatic `scrollTo`/`scrollIntoView` — is unaffected either way; only the visual
|
|
385
|
+
affordance is gone. The underlying toggle lives on `gog-scroll` itself as `showTrack`
|
|
386
|
+
(instance input, or app-wide via `GOG_CONFIG.scroll.showTrack`), so any other panel built on
|
|
387
|
+
it gets the same option.
|
|
388
|
+
- **`gog-textarea`: `resize`.** Which direction(s) the field's own drag handle resizes it in —
|
|
389
|
+
`'vertical'` (the default, matching a plain `<textarea>`), `'horizontal'`, `'both'`, or
|
|
390
|
+
`'none'` to remove it entirely. Settable app-wide via `GOG_CONFIG.textarea.resize`. The
|
|
391
|
+
handle itself is also restyled: the browser's native glyph is barely visible at a glance, so
|
|
392
|
+
it's blanked out (`::-webkit-resizer`, where that's even stylable — Firefox never exposed a
|
|
393
|
+
hook for its own) and replaced with two short diagonal strokes in the field's own border
|
|
394
|
+
colour, sized and positioned to sit inside the border rather than past it. A `ResizeObserver`
|
|
395
|
+
on the field keeps the grip glued to its actual corner as it's dragged narrower/shorter than
|
|
396
|
+
its container (`'horizontal'`/`'both'`) — it's anchored to the container, not the field
|
|
397
|
+
itself, since a `<textarea>` can't reliably host `::after`. The drag stays entirely native;
|
|
398
|
+
only the glyph and its tracking are new.
|
|
399
|
+
- **`gog-inputfield`: number spin buttons.** A `type="number"` field now gets the library's own
|
|
400
|
+
increment/decrement buttons instead of the browser's native ones, which render inconsistently
|
|
401
|
+
across Chromium/Firefox/Safari and were never themed. Flush against the field's own border as
|
|
402
|
+
one grouped stepper (a divider on each side), not floating loose in the icon gutter. Steps by
|
|
403
|
+
`step` (default `1`), clamps to `min`/`max`, and disables the button at whichever boundary is
|
|
404
|
+
reached. Arrow-key stepping on the focused field is untouched — that's native
|
|
405
|
+
`<input type="number">` behaviour, unrelated to which glyphs are visible. `showSpinButtons`
|
|
406
|
+
turns them off entirely (native glyphs never come back — off means no stepper UI at all);
|
|
407
|
+
settable app-wide via `GOG_CONFIG.inputfield.showSpinButtons`.
|
|
408
|
+
- **`gog-icon`: `copy`.** A new glyph for the common "copy this field's value" trailing-action
|
|
409
|
+
pattern (see the inputfield showcase page for a full example built on `gogInputAddonEnd`).
|
|
410
|
+
- **`AGENTS.md`.** A consumer-facing reference for AI coding agents building apps against the
|
|
411
|
+
published package — conventions, theming/`GOG_CONFIG` summary, a full per-component API table
|
|
412
|
+
(inputs, outputs, slots, CVA status), and the deprecated-pattern list, all derived from the
|
|
413
|
+
library's actual source rather than the (currently lagging) `README.md`. Shipped alongside
|
|
414
|
+
`README.md`/`LICENSE` in the npm package via `ng-package.json`'s `assets`.
|
|
415
|
+
|
|
416
|
+
### Fixed
|
|
417
|
+
|
|
418
|
+
- **`gog-scroll`: thumb too small to reliably click, especially at `size="thin"`.** The
|
|
419
|
+
thumb's own visible box is exactly as wide as `size` says — that part is unchanged — but its
|
|
420
|
+
clickable/draggable _region_ now extends a few pixels past every edge
|
|
421
|
+
(`--gog-scroll-thumb-hit-padding`, bigger on `thin`, where the visible thumb was hardest to
|
|
422
|
+
land a cursor on), so a near-miss click still grabs the thumb instead of falling through to
|
|
423
|
+
the track, which pages the view rather than dragging. Purely an invisible hit-area change —
|
|
424
|
+
no new input, no behaviour change for the mouse wheel, which already worked fine.
|
|
425
|
+
- **`gog-autocomplete`: option rows spilling out of the panel.** The panel's `.gog-scroll` was
|
|
426
|
+
never actually constrained to `--gog-autocomplete-panel-max-height` — a classic flexbox trap
|
|
427
|
+
where a `max-height`-only container doesn't give its flex-grow children a definite size to
|
|
428
|
+
shrink into, so the option list rendered at full content height and visibly overflowed past
|
|
429
|
+
the panel's own border into whatever sat below it. Most visible with `appendToBody` and a
|
|
430
|
+
longer list (typing narrowed it back under the cap, masking the issue until the panel was
|
|
431
|
+
reopened with more matches, which also made it look like "the panel closes on its own" — it
|
|
432
|
+
hadn't; the list had just spilled out from under it). Fixed by giving the panel the same
|
|
433
|
+
`display: flex` + `flex: 1; min-height: 0` chain `gog-select` and `gog-multiselect` already
|
|
434
|
+
use, plus a defensive `overflow: hidden`.
|
|
435
|
+
|
|
436
|
+
## [21.3.0] - 08.08.2026
|
|
437
|
+
|
|
438
|
+
### Added
|
|
439
|
+
|
|
440
|
+
- **Eight new components**, the Angular Material set this library was missing:
|
|
441
|
+
|
|
442
|
+
- **`gog-datepicker`** — a date field with a calendar panel: single date, `selectionMode="range"`
|
|
443
|
+
(with `numberOfMonths` for a two-month view), and an optional clock via `showTime` /
|
|
444
|
+
`hourFormat` / `minuteStep` / `showSeconds`. `min`, `max` and a `disabledDates` **predicate**
|
|
445
|
+
(an array cannot express "weekends"), `inline` for an always-visible calendar, `allowTextInput`
|
|
446
|
+
with parsing, plus the usual `clearable` / `floatLabel` / `errorMessage` / `appendToBody`.
|
|
447
|
+
|
|
448
|
+
The panel's footer carries **two separate actions**, never one: `showTodayButton` (on by
|
|
449
|
+
default) _selects_ today, and `showThisMonthButton` (off by default) only moves the view back
|
|
450
|
+
to the current month. A single button doing both is ambiguous — after paging away, the same
|
|
451
|
+
label reads as "take me back" to one person and "set it to today" to another. "Today" is
|
|
452
|
+
disabled when `min`/`max` or `disabledDates` rule today out, rather than silently doing
|
|
453
|
+
nothing. Wording via `todayLabel` / `thisMonthLabel`.
|
|
454
|
+
|
|
455
|
+
Native `Date`, **no date library and no adapter abstraction** — the package keeps its zero
|
|
456
|
+
runtime dependencies. `Intl` supplies month and weekday names; the display format is a token
|
|
457
|
+
pattern (`dd.MM.yyyy`, `yyyy-MM-dd`, …) used for _both_ rendering and parsing, so what is
|
|
458
|
+
written can always be read back. `31.02.2026` is rejected rather than silently becoming
|
|
459
|
+
3 March. `locale`, `firstDayOfWeek` and `format` are also settable app-wide through
|
|
460
|
+
`GOG_CONFIG.datepicker`.
|
|
461
|
+
|
|
462
|
+
- **`gog-calendar`** — the month grid behind it, exported and usable on its own. Follows the
|
|
463
|
+
ARIA grid pattern: arrows by day, `PageUp`/`PageDown` by month, `Shift` + those by year,
|
|
464
|
+
`Home`/`End` to the week's ends, and one tab stop across all 42 cells. Always six weeks, so
|
|
465
|
+
the calendar's height never changes as you page through months.
|
|
466
|
+
- **`gog-autocomplete`** — a text field that suggests options as you type, on the same
|
|
467
|
+
`GogDropdownBase` as `gog-select` and taking the same `optionLabel` / `optionValue` /
|
|
468
|
+
`optionDisabled` accessors. The trigger is a real `<input>`, which is what makes it a separate
|
|
469
|
+
control rather than a mode of `gog-select`: focus never leaves the field and the highlighted
|
|
470
|
+
row is pointed at with `aria-activedescendant`. `gogSearch` is debounced (`searchDebounce`,
|
|
471
|
+
300 ms) for a server-backed source, and `[filterLocal]="false"` stops that server's answer
|
|
472
|
+
being filtered a second time. Plus `minLength`, `loading`, `emptyMessage` and
|
|
473
|
+
`forceSelection`.
|
|
474
|
+
- **`gog-tabs` / `gog-tab`** — a tablist over projected children, each tab declaring its own
|
|
475
|
+
`label`, `iconName` and `disabled`. Content written inside a tab renders eagerly and is
|
|
476
|
+
merely hidden while inactive, so scroll position and half-typed input survive a switch; an
|
|
477
|
+
`<ng-template gogTabContent>` is instead built on first activation and kept alive after.
|
|
478
|
+
Which you get is decided by whether that template is present. `gogTabHeader` replaces the
|
|
479
|
+
header button entirely. Overflowing headers scroll inside a `<gog-scroll>`, not a native
|
|
480
|
+
`overflow-x`.
|
|
481
|
+
- **`gog-button-toggle-group`** — a row of buttons where one, or with `multiple` several, can
|
|
482
|
+
be picked. Options-driven with the same accessors as the dropdowns, plus `optionIcon` and a
|
|
483
|
+
`gogButtonToggleOption` slot. Single and multiple are genuinely different widgets to
|
|
484
|
+
assistive tech and are exposed as such: `role="radiogroup"`/`aria-checked` with arrows that
|
|
485
|
+
move _and_ select, versus `role="group"`/`aria-pressed` with arrows that only move.
|
|
486
|
+
`appearance` picks between one segmented control and discrete buttons.
|
|
487
|
+
- **`gog-toggle`** — an on/off switch. A native `<input type="checkbox">` carrying
|
|
488
|
+
`role="switch"`, so it announces as "switch, on" rather than "checkbox, checked" while the
|
|
489
|
+
platform keeps owning the keyboard and forms. `onLabel` / `offLabel` render _inside_ the
|
|
490
|
+
track — the one thing a checkbox cannot do — and both stay in the DOM so the track's width
|
|
491
|
+
cannot jump as it flips. Shares `gog-checkbox`'s size scale.
|
|
492
|
+
- **`gog-progressbar`** — determinate, indeterminate and buffer modes, five sizes and the
|
|
493
|
+
semantic colour set. `value` and `buffer` are clamped to 0–100 rather than trusted.
|
|
494
|
+
Indeterminate reports **no** `aria-valuenow` at all, which is what marks it indeterminate,
|
|
495
|
+
and its animation is replaced by a static stripe under `prefers-reduced-motion`.
|
|
496
|
+
- **`gogBadge`** — a count or dot pinned to another element's corner. A directive, so it
|
|
497
|
+
decorates a button, icon or avatar without wrapping it. `badgePosition`, `badgeVariant`,
|
|
498
|
+
`badgeDot`, `badgeMax` (`99+` beyond it), `badgeHidden` and `badgeAriaLabel`. It renders
|
|
499
|
+
**nothing at all** for `0`, `null` or `''` — a badge reading "0" is the defining bug of this
|
|
500
|
+
component class, so it is not reachable.
|
|
501
|
+
- **`gog-divider`** — a rule between two regions, horizontal or vertical, solid/dashed/dotted,
|
|
502
|
+
with an optional projected label running through it and an `inset` variant for lists. No
|
|
503
|
+
`hasLabel` input: the two forms are told apart by whether anything was actually projected.
|
|
504
|
+
|
|
505
|
+
- `GogOrientation` — one shared `'horizontal' | 'vertical'` type. `GogSliderOrientation` is now
|
|
506
|
+
an alias of it, so nothing changes for existing code.
|
|
507
|
+
- `roving-focus.ts` gained an `orientation` (so a horizontal tablist leaves `ArrowDown` to the
|
|
508
|
+
page) and an optional predicate for skipping disabled items. Both default to the previous
|
|
509
|
+
behaviour, so `gog-select`, `gog-multiselect` and `gog-accordion` are unaffected.
|
|
510
|
+
- Four icons: `calendar`, `clock`, `chevron-left`, `chevron-right`.
|
|
511
|
+
- `.gog-visually-hidden` in `styles/utilities.css`.
|
|
512
|
+
|
|
513
|
+
- `GogFloatLabelState` (exported) — the shared float-label state behind `gog-inputfield`,
|
|
514
|
+
`gog-textarea`, `gog-select` and `gog-multiselect`, previously three near-identical copies of
|
|
515
|
+
the same five `computed()`s. A plain composition class in the mould of `GogErrorState`, so it
|
|
516
|
+
serves the two components that share no base class as well as `GogDropdownBase`, which is one.
|
|
517
|
+
Each control still supplies its own "has content" signal, since that genuinely differs
|
|
518
|
+
(non-empty string / non-null selection / non-empty selection array).
|
|
519
|
+
- `resolveConfigured(instanceValue, configuredValue, fallback)` (exported) — the library's
|
|
520
|
+
input → `GOG_CONFIG` → built-in default precedence rule in one place, instead of the `??`
|
|
521
|
+
chain hand-written at each configurable input.
|
|
522
|
+
- `GOG_CONFIG` now covers the settings an app otherwise repeats on every instance:
|
|
523
|
+
`control.size` and `control.errorDisplay` (the latter is what makes `errorDisplay="auto"` an
|
|
524
|
+
app-wide decision for a Reactive Forms app rather than per-field boilerplate),
|
|
525
|
+
`dropdown.appendToBody`, `dropdown.direction`, and `toast.position` / `toast.duration`.
|
|
526
|
+
`control.size` deliberately covers only the interactive form controls — `gog-table`,
|
|
527
|
+
`gog-accordion` and `gog-paginator` keep their own density defaults, as do `gog-spinner`,
|
|
528
|
+
`gog-skeleton`, `gog-tag` and `gog-chip`. All stay per-instance overridable.
|
|
529
|
+
|
|
530
|
+
- **A built-in clear button** on `gog-inputfield`, `gog-textarea`, `gog-select` and
|
|
531
|
+
`gog-multiselect`, via a `clearable` input (plus `clearAriaLabel`). It appears only once the
|
|
532
|
+
control has something to clear and disappears again when empty, so it adds no permanent
|
|
533
|
+
chrome — and it removes the need for a fake `"— not selected —"` option just to let someone
|
|
534
|
+
undo a choice. Also settable app-wide through `GOG_CONFIG.control.clearable`. Defaults to
|
|
535
|
+
`false`, except `gog-multiselect`, which already had a clear button and keeps it. On a
|
|
536
|
+
password field the built-in reveal toggle keeps the trailing slot.
|
|
537
|
+
- `filterPosition` on `gog-select` / `gog-multiselect` (`'top'` | `'bottom'`, plus
|
|
538
|
+
`GOG_CONFIG.dropdown.filterPosition`) sticks the search box to either end of the panel, and it
|
|
539
|
+
now carries a divider on the side facing the list so it reads as chrome rather than a row. The
|
|
540
|
+
name matches `gog-multiselect`'s existing `controlsPosition` rather than inventing a second
|
|
541
|
+
vocabulary for the same idea.
|
|
542
|
+
- **Filtering in `gog-select` and `gog-multiselect`** — `filter` puts a search box at the top of
|
|
543
|
+
the panel, matching case-insensitively on the resolved `optionLabel`. `filterMatch` swaps that
|
|
544
|
+
for your own predicate, `filterPlaceholder` and `filterEmptyMessage` cover the wording, and
|
|
545
|
+
`GOG_CONFIG.dropdown.filter` turns it on app-wide. The query resets when the panel closes, and
|
|
546
|
+
`gog-multiselect`'s "select all" deliberately takes only the _visible_ options so it means what
|
|
547
|
+
it says while a filter is active.
|
|
548
|
+
- `styles/presets/one-dark.css` and `styles/presets/one-light.css` — the Atom/JetBrains One
|
|
549
|
+
palettes, with the syntax hues mapped onto the library's semantic roles (blue is the accent,
|
|
550
|
+
green/red/yellow/cyan become success/danger/warning/info).
|
|
551
|
+
|
|
552
|
+
- **The token catalogue is generated, not hand-copied.** `npm run generate:tokens` derives
|
|
553
|
+
`GogTokenName` (a union of every `--gog-*` the library declares or documents), the
|
|
554
|
+
`GOG_TOKEN_GROUPS` runtime metadata, and the README's theming table straight from
|
|
555
|
+
`theme.css`. `npm run check:tokens` fails when they are out of date, so a stylesheet edit
|
|
556
|
+
cannot silently leave the docs behind. `GOG_TOKEN_GROUPS` is exported so a theme editor can
|
|
557
|
+
enumerate real tokens instead of keeping its own copy.
|
|
558
|
+
- `styles/presets/slate.css` — a second, importable preset (`data-theme="slate"`, cool/indigo).
|
|
559
|
+
It declares palette tokens only and still restyles everything, which is the theming contract
|
|
560
|
+
demonstrated rather than described.
|
|
561
|
+
|
|
562
|
+
- **`gog-select` and `gog-multiselect` take your own objects.** `optionLabel`, `optionValue` and
|
|
563
|
+
`optionDisabled` accept a property path (dot-paths included, `'profile.fullName'`) or a
|
|
564
|
+
function, so a real DTO goes straight in — no mapping into `{ id, name }` first, and no losing
|
|
565
|
+
the original object on the way back out. Set `[optionValue]="null"` and the control emits the
|
|
566
|
+
**option object itself** instead of an id. Both controls are now generic over their option and
|
|
567
|
+
value types, inferred from the bindings.
|
|
568
|
+
|
|
569
|
+
Defaults are `'name'` / `'id'` / `'disabled'`, so **existing code is unaffected** — the whole
|
|
570
|
+
21.2.x select/multiselect spec suite passes unchanged. `GogDropdownOption` is no longer a
|
|
571
|
+
requirement, just the shape those default accessors expect.
|
|
572
|
+
|
|
573
|
+
- `gogDropdownOption` — a projected template for one option row, with
|
|
574
|
+
`{ $implicit: option, selected, disabled, label }` as its context.
|
|
575
|
+
- `getByPath`, `readOption`, `isSameOptionValue` and the `GogOptionAccessor<TOption, TResult>`
|
|
576
|
+
type are exported; `gog-table` now shares the same `getByPath` rather than keeping its own copy.
|
|
577
|
+
|
|
578
|
+
- **One slot mechanism across the library.** Custom markup is now projected as content and
|
|
579
|
+
picked up with `contentChild`, instead of a `TemplateRef` input per slot. New directives:
|
|
580
|
+
`gogColumnBody` / `gogColumnHeader` (per column, replacing the string-keyed
|
|
581
|
+
`<ng-template template="…" type="…">`), `gogCheckboxIcon`, `gogTagIcon`,
|
|
582
|
+
`gogMultiselectClearIcon`, `gogDropdownChevron`, and `gogInputAddonStart` /
|
|
583
|
+
`gogInputAddonEnd`. A projected slot always wins over the deprecated input it replaces, so a
|
|
584
|
+
codebase can migrate one call site at a time.
|
|
585
|
+
- `GogColumn` with the `gog-column` selector — the library's last unprefixed element name.
|
|
586
|
+
- `gog-inputfield` addon slots take arbitrary markup, including a real `<button>` with its own
|
|
587
|
+
`aria-label` and `(click)`. This replaces six inputs (`icon{Start,End}{Template,Fn,Label}`)
|
|
588
|
+
with two slots. On `type="password"` the built-in reveal toggle keeps the trailing slot, so a
|
|
589
|
+
projected addon can never displace the only control that shows the value.
|
|
590
|
+
|
|
591
|
+
### Fixed
|
|
592
|
+
|
|
593
|
+
- **An auto-width dropdown clipped its own options.** With `[fullWidth]="false"` the trigger
|
|
594
|
+
sizes to the _current_ selection, and the panel copied that width — so picking a short option
|
|
595
|
+
cut the longer ones off the list. The relationship is now inverted: the panel sizes to its own
|
|
596
|
+
content with the trigger's width as a **floor**, capped by
|
|
597
|
+
`--gog-{select,multiselect}-panel-max-width`. New `minWidth` input (any CSS length) plus
|
|
598
|
+
`--gog-{select,multiselect}-min-width` (120px) so an auto-width trigger cannot collapse to its
|
|
599
|
+
own chrome either.
|
|
600
|
+
- **`gog-multiselect` now collapses a long selection into `+N`.** The trigger shows what fits on
|
|
601
|
+
one line and a count for the rest, with the full list in a tooltip. Measured with
|
|
602
|
+
`canvas.measureText` rather than by rendering candidates, and re-measured from a
|
|
603
|
+
`ResizeObserver` on the value element, since the space available changes when the _container_
|
|
604
|
+
resizes — something Angular never renders for.
|
|
605
|
+
- **`gog-select`'s chevron sat 42px from the trigger's right edge.**
|
|
606
|
+
`--gog-select-chevron-inset` was applied as the trigger's `padding-right` while the chevron
|
|
607
|
+
itself was a flex child _inside_ that padding, so the inset was counted twice. It now lands on
|
|
608
|
+
`--gog-control-icon-offset` (10px), the same line as `gog-inputfield`'s icons and
|
|
609
|
+
`gog-multiselect`'s arrow, which were at 10px and 16px — the three controls did not line up in
|
|
610
|
+
a form. The token keeps its name and now means what it says.
|
|
611
|
+
- **`gog-textarea`'s clear button sat inside the scrollbar.** It was inset 8px from the border
|
|
612
|
+
box while a scrolling textarea's scrollbar is ~19px wide, so once the content overflowed the
|
|
613
|
+
button was half-covered and competed with the thumb for clicks. It is now offset by the
|
|
614
|
+
measured scrollbar width (`--gog-textarea-scrollbar-width`, written from
|
|
615
|
+
`offsetWidth - clientWidth`; `scrollbar-gutter: stable` was rejected because it reserves the
|
|
616
|
+
gutter even when the field isn't scrolling).
|
|
617
|
+
- **`gog-textarea`'s clear glyph was 30% too small** — 13.4px against the library's 19.2px,
|
|
618
|
+
because it reused the dropdowns' 0.7 ratio, which suits their dense trigger and not a large
|
|
619
|
+
multi-line box. New `--gog-textarea-clear-icon-ratio` defaults to a full-size glyph.
|
|
620
|
+
- Nine specs in `scroll.component.spec.ts` awaited a single animation frame after dispatching a
|
|
621
|
+
scroll, while `ScrollComponent` coalesces measurement into its own frame — if that frame fired
|
|
622
|
+
during `whenStable()`, the effect scheduled a second one _after_ the test's, and the assertion
|
|
623
|
+
ran before the measurement. Intermittent by construction; replaced with a `settleMeasure()`
|
|
624
|
+
helper that covers both orderings.
|
|
625
|
+
|
|
626
|
+
### Changed
|
|
627
|
+
|
|
628
|
+
- The clear button now takes the **outermost** trailing position on `gog-select` and
|
|
629
|
+
`gog-multiselect`, with the chevron/arrow shifting inward when it appears. Previously
|
|
630
|
+
`gog-multiselect` had them the other way round. Keeps the trigger width stable and keeps the
|
|
631
|
+
destructive control off the very edge.
|
|
632
|
+
- Float-label fields are less tall: `--gog-field-float-label-reserve` 18px → 14px and
|
|
633
|
+
`--gog-field-float-label-in-top` 8px → 6px, taking an `md` field from 63px to 59px (a plain one
|
|
634
|
+
is 45px). Both are tokens, so the old numbers are one declaration away.
|
|
635
|
+
|
|
636
|
+
### Deprecated
|
|
637
|
+
|
|
638
|
+
Each of these keeps working unchanged and is **removed in 21.5.0**; the `@deprecated` tag on
|
|
639
|
+
every symbol carries the same date and removal version, so `grep -rn "@deprecated since"` lists
|
|
640
|
+
the full set at any time.
|
|
641
|
+
|
|
642
|
+
- `<column>` → `<gog-column>`, and the `Column` export → `GogColumn`.
|
|
643
|
+
- All `--gog-ms-*` tokens → `--gog-multiselect-*`. Both spellings work for the whole window:
|
|
644
|
+
the `--gog-ms-*` name stays the _declared_ one and the new name derives from it, so an
|
|
645
|
+
existing override of either still reaches the component. Verified in a browser both ways.
|
|
646
|
+
- `<ng-template template="field" type="body|header">` inside `gog-table` → a `gogColumnBody` /
|
|
647
|
+
`gogColumnHeader` template declared inside the column itself. The old form matched columns by
|
|
648
|
+
a string the compiler cannot check, so a typo silently fell back to the default cell.
|
|
649
|
+
- `gog-checkbox`'s `checkIconTemplate` → `gogCheckboxIcon`.
|
|
650
|
+
- `gog-tag`'s `iconTemplate` → `gogTagIcon`.
|
|
651
|
+
- `gog-multiselect`'s `clearIconTemplate` → `gogMultiselectClearIcon`.
|
|
652
|
+
- `gog-select` / `gog-multiselect` `chevronTemplate` → `gogDropdownChevron`.
|
|
653
|
+
- `gog-inputfield`'s `iconStartTemplate`, `iconEndTemplate`, `iconStartFn`, `iconEndFn`,
|
|
654
|
+
`iconStartLabel`, `iconEndLabel` → `gogInputAddonStart` / `gogInputAddonEnd`. `iconStart` and
|
|
655
|
+
`iconEnd` (a bare icon name) stay — that is the genuinely common case.
|
|
656
|
+
|
|
657
|
+
### Changed
|
|
658
|
+
|
|
659
|
+
- **`provideGogConfig(...)` now merges with the config from the parent injector instead of
|
|
660
|
+
replacing it.** Previously a nested call — in a route's or a component's `providers` —
|
|
661
|
+
silently dropped every key it did not restate, so a route setting only `{ tooltip: … }` lost
|
|
662
|
+
the app-wide `button.debounce` with no error anywhere. Merging is one level deep, per
|
|
663
|
+
component key, nearest provider winning field by field. If you were working around the old
|
|
664
|
+
behaviour by repeating the whole config at each level, those repeats are now redundant but
|
|
665
|
+
harmless.
|
|
666
|
+
|
|
667
|
+
- Float label geometry is now themeable through `theme.css` instead of being hardcoded in the
|
|
668
|
+
component stylesheets. `--gog-{input,select,ms}-float-label-{reserve,in-top,over-gap,over-reserve}`
|
|
669
|
+
previously existed only as literal fallbacks (`18px`, `8px`, `1.4em`) inside four component
|
|
670
|
+
`.scss` files, so they were overridable but not discoverable, and `theme.css` did not describe
|
|
671
|
+
the components' full surface. They are now declared component tokens deriving from a new
|
|
672
|
+
shared `--gog-field-float-label-{reserve,in-top,over-gap,over-reserve}` scale, so one
|
|
673
|
+
declaration retunes every field at once while a single control can still be overridden.
|
|
674
|
+
No visual change — the defaults are identical. `--gog-{input,select,ms}-float-label-on-bg`
|
|
675
|
+
stays an instance-layer (undeclared) token as before.
|
|
676
|
+
|
|
677
|
+
### Added
|
|
678
|
+
|
|
679
|
+
- Float label support for `gog-inputfield`, `gog-select`, `gog-multiselect` and
|
|
680
|
+
`gog-textarea`: a `floatLabel` input (`GogFloatLabelVariant`: `'none'` default, or
|
|
681
|
+
`'in'`/`'on'`/`'over'`, modeled on PrimeNG's own variant names) that rests the label inside
|
|
682
|
+
the field like a placeholder and floats it up on focus or once the field has content —
|
|
683
|
+
`'in'` stays fully inside the border, `'on'` ends up centered on the top border line (with
|
|
684
|
+
a background patch masking it), `'over'` floats fully above the field, outside the border.
|
|
685
|
+
A `floatLabelShowPlaceholder` input (`boolean`, default `false`) reveals the field's own
|
|
686
|
+
`placeholder` once the label has floated out of the way; left off, the placeholder stays
|
|
687
|
+
hidden the whole time a float label is active since the resting label already occupies that
|
|
688
|
+
space. Both are also settable app-wide via the new `GOG_CONFIG.floatLabel` (`variant` /
|
|
689
|
+
`showPlaceholder`), with the usual per-instance input taking priority. Implemented as a
|
|
690
|
+
style variant on each component (not a directive, unlike `gogTooltip`) since each control
|
|
691
|
+
already owns its label and has a different notion of "has content" (`value`,
|
|
692
|
+
`selectedOption`, selection length) that a directive sitting outside the component couldn't
|
|
693
|
+
see. New `--gog-{input,select,ms}-float-label-{in-top,on-bg,over-gap,over-reserve}` tokens.
|
|
694
|
+
- `gog-slider`'s new `orientation` input (`'horizontal'` default / `'vertical'`) — the
|
|
695
|
+
developer picks per instance, no global default, since it's a layout decision rather than a
|
|
696
|
+
house style. The vertical variant is the same native `<input type="range">` rotated via
|
|
697
|
+
`writing-mode: vertical-lr` + `direction: rtl` (not a custom drag implementation), so
|
|
698
|
+
dragging, touch and keyboard (Up/Down as well as Left/Right) all keep working exactly as they
|
|
699
|
+
do horizontally; value increases upward, matching a volume-fader convention. New
|
|
700
|
+
`--gog-slider-vertical-length` token (default `160px`) sizes its length, the vertical
|
|
701
|
+
counterpart to `--gog-slider-auto-width`. `fullWidth` is ignored when vertical, since a
|
|
702
|
+
vertical slider's width is its thickness, not its length.
|
|
703
|
+
- `gog-radio-group`: a new options-driven radio control (`GogRadioOption[]`), the radio
|
|
704
|
+
counterpart to `gog-checkbox`. Renders native `<input type="radio">`s sharing one
|
|
705
|
+
auto-generated (or explicit `name`) group name, so mutual exclusivity and arrow-key/Home/End
|
|
706
|
+
navigation between options come from the browser for free — no roving-focus code needed.
|
|
707
|
+
`ControlValueAccessor`-based, works with `formControl`/`formControlName`. `label`,
|
|
708
|
+
`ariaLabel`, `name`, `size`, `disabled` (group-level, plus per-option `disabled`),
|
|
709
|
+
`orientation` (`'vertical'` default / `'horizontal'`), `errorMessage`, `errorDisplay` and
|
|
710
|
+
`fullWidth` inputs; `[(value)]` two-way bindable. Reuses the `--gog-control-checkbox-*`
|
|
711
|
+
size scale via the shared checkable-control config, plus new `--gog-radio-*` tokens in
|
|
712
|
+
`theme.css`.
|
|
713
|
+
- `gog-collapsible`'s `collapseOnFocusOut` input (`boolean`, default `false`): closes the
|
|
714
|
+
panel once focus leaves both the trigger and the content — e.g. Tabbing past the last
|
|
715
|
+
focusable element inside, or a click landing elsewhere on the page. Off by default, since
|
|
716
|
+
plenty of consumers (an FAQ list, a settings section read top to bottom) want the panel to
|
|
717
|
+
stay open regardless of where focus goes next.
|
|
718
|
+
- `gogTooltip`: a new directive, not a component — drop it on any element, a `gog-*`
|
|
719
|
+
component's own host tag or a plain native one (`<button gogTooltip="Save changes">`,
|
|
720
|
+
`<gog-chip [gogTooltip]="hint">`), to add a hover/focus tooltip without that element
|
|
721
|
+
needing to know anything about it. Content is a plain string or a `TemplateRef` for richer
|
|
722
|
+
markup. `gogTooltipPosition` (`GogTooltipPosition`: `'auto'` default, or an explicit
|
|
723
|
+
`'top'`/`'bottom'`/`'left'`/`'right'` that flips to its opposite if it has no room),
|
|
724
|
+
`gogTooltipShowDelay` (default `300`ms), `gogTooltipHideDelay` (default `100`ms) and
|
|
725
|
+
`gogTooltipDisabled` inputs; the first three also read `GOG_CONFIG.tooltip` for an
|
|
726
|
+
app-wide default the same way `gog-scroll`/`gog-button` already do, with an instance's own
|
|
727
|
+
input always winning. Shown on both mouse hover and keyboard focus (`focusin`/`focusout`,
|
|
728
|
+
not `focus`/`blur`, so it stays replay-safe under SSR event replay), dismissible with
|
|
729
|
+
Escape, and hoverable — moving the pointer from the trigger onto the bubble itself (e.g. to
|
|
730
|
+
read more of a long one, or scroll one taller than `--gog-tooltip-max-height`) cancels the
|
|
731
|
+
pending hide instead of racing it — per WCAG 2.1 SC 1.4.13. The bubble is appended to
|
|
732
|
+
`document.body` (so it's never clipped by an ancestor's `overflow: hidden`) via a new
|
|
733
|
+
internal `GogTooltipOverlay`, built on `ViewContainerRef.createComponent` + relocating the
|
|
734
|
+
node rather than `GogDropdownOverlay`'s `TemplateRef` approach, since a directive has no
|
|
735
|
+
template of its own to attach from. Visually it's the same "floating panel" recipe as
|
|
736
|
+
`gog-dialog`'s panel and `gog-select`'s dropdown (`--gog-surface-color` background, plain
|
|
737
|
+
`--gog-border-color` border, `--gog-panel-shadow`), not a bespoke inverted bubble, so it
|
|
738
|
+
reads as part of a themed app rather than a generic dark tooltip dropped on top of it.
|
|
739
|
+
Content wraps to `--gog-tooltip-max-width` (`280px`) and is capped at
|
|
740
|
+
`--gog-tooltip-max-height` (`220px`) through an internal `gog-scroll` — content under the
|
|
741
|
+
cap renders at exactly its own height, content over it scrolls, using the same themeable
|
|
742
|
+
scrollbar every other overflowing panel in this library uses instead of a native one (see
|
|
743
|
+
`styling.instructions.md`'s new "Scrollable content" section for that convention).
|
|
744
|
+
`gogTooltipClass` applies a class straight to the bubble, for restyling (or resizing) one
|
|
745
|
+
instance — needed because the bubble sits outside any scoped ancestor's stylesheet once
|
|
746
|
+
appended to `document.body`, the same "Panels rendered outside the component subtree"
|
|
747
|
+
limitation `gog-select`'s `[appendToBody]` panel already has, so the class has to come from
|
|
748
|
+
an unscoped (global) stylesheet. New `--gog-tooltip-*` tokens in `theme.css`; `gog-dialog`'s
|
|
749
|
+
panel now also raises `--gog-tooltip-z` (mirroring the existing `--gog-dropdown-z` bump) so
|
|
750
|
+
a tooltip triggered inside a dialog stacks above it.
|
|
751
|
+
|
|
752
|
+
### Changed
|
|
753
|
+
|
|
754
|
+
- `gog-slider`'s track now paints a border (new `--gog-slider-track-border-width`/`-style`/
|
|
755
|
+
`-color` tokens, transparent by default — same opt-in convention as `--gog-btn-primary-border`)
|
|
756
|
+
and its fill is bound via `background` instead of `background-color`, so
|
|
757
|
+
`--gog-slider-fill-bg` also accepts a gradient (e.g. `linear-gradient(...)`), not just a
|
|
758
|
+
solid color. The thumb ("handle") was already fully customizable via its existing
|
|
759
|
+
`--gog-slider-thumb-*` tokens (size, background, border, radius, glow) — no change there.
|
|
760
|
+
|
|
761
|
+
### Fixed
|
|
762
|
+
|
|
763
|
+
- `gog-slider`'s track background (`--gog-slider-track-bg`) no longer reuses
|
|
764
|
+
`--gog-accent-dim` — it sat on the same hue ramp as the fill (`--gog-accent-color`), so at
|
|
765
|
+
the track's 4px height the two read as one blob instead of a recessed groove with an
|
|
766
|
+
accent fill on top. Now `color-mix(in srgb, var(--gog-text-color) 30%, var(--gog-border-color))`:
|
|
767
|
+
a desaturated, theme-adaptive gray that darkens toward black in the light theme and
|
|
768
|
+
lightens toward parchment in the dark theme (`--gog-text-color` sits at whichever end of
|
|
769
|
+
that range per theme), so it's always distinct from the accent-colored fill and legible
|
|
770
|
+
against its own theme's surface.
|
|
771
|
+
|
|
772
|
+
## [21.2.4] - 05.08.2026
|
|
773
|
+
|
|
774
|
+
### Added
|
|
775
|
+
|
|
776
|
+
- `gog-collapsible`: a headless expand/collapse primitive — inline, not a portal (unlike
|
|
777
|
+
`gog-select`/`gog-multiselect`'s panel). Owns no markup: project any element as the
|
|
778
|
+
trigger via `gogCollapsibleTrigger` and any element as the panel via
|
|
779
|
+
`gogCollapsibleContent`; `[(open)]` is two-way bindable, `disabled` blocks toggling.
|
|
780
|
+
New `--gog-collapsible-*` tokens in `theme.css`; the trigger/content CSS classes live in
|
|
781
|
+
`utilities.css` since the projected content sits outside the component's own view.
|
|
782
|
+
- `gog-textarea`: a multi-line counterpart to `gog-inputfield`, sharing its
|
|
783
|
+
`--gog-input-*` tokens. `ControlValueAccessor`-based, works with
|
|
784
|
+
`formControl`/`formControlName`. `label`, `placeholder`, `errorMessage`,
|
|
785
|
+
`errorDisplay`, `disabled`, `size`, `fullWidth` and `rows` inputs.
|
|
786
|
+
- `gog-inputfield`'s `type` input now also accepts `'number'` and `'date'`,
|
|
787
|
+
plus new `min`/`max`/`step` inputs (applied only for `type="number"`). For a
|
|
788
|
+
`number` field the value written to/read from an attached
|
|
789
|
+
`formControl`/`formControlName` is a `number` (`null` when the field is
|
|
790
|
+
empty) rather than a string — `[(value)]` stays a string either way, since
|
|
791
|
+
it mirrors the native input's raw text.
|
|
792
|
+
- `gog-scroll`: a drop-in replacement for a native `overflow: auto` region.
|
|
793
|
+
Content keeps scrolling natively (wheel, touch, keyboard, focus-into-view);
|
|
794
|
+
only the browser's own scrollbar chrome is hidden and replaced with a
|
|
795
|
+
themeable, draggable overlay thumb. `axis` (`vertical`/`horizontal`/`both`),
|
|
796
|
+
`size` (`normal`/`thin`), `autoHide`/`hideDelay`, `reachThreshold` with
|
|
797
|
+
`gogReachStart`/`gogReachEnd` outputs, a `gogScroll` metrics output, and
|
|
798
|
+
`scrollTo`/`scrollToTop`/`scrollToBottom`/`scrollToLeft`/`scrollToRight`
|
|
799
|
+
public methods. New `--gog-scroll-*` tokens in `theme.css`.
|
|
800
|
+
- `gog-scroll`'s `overscrollBehavior` input (`'auto'` | `'contain'` | `'none'`,
|
|
801
|
+
mirrors the CSS property of the same name): what happens when a scroll
|
|
802
|
+
gesture reaches this instance's edge. Defaults to `'auto'` — chains to the
|
|
803
|
+
next scrollable ancestor, same as an un-customized `overflow: auto` div, so
|
|
804
|
+
scrolling to the end of a `gog-scroll`'d section and continuing the same
|
|
805
|
+
gesture now keeps scrolling the page instead of stopping dead. `gog-select`/
|
|
806
|
+
`gog-multiselect`'s option panel and `gog-dialog`'s body now set
|
|
807
|
+
`overscrollBehavior="contain"` explicitly, preserving their existing
|
|
808
|
+
(correct, overlay-appropriate) behavior now that the component-wide default
|
|
809
|
+
has changed to chain-through.
|
|
810
|
+
- `GOG_CONFIG`/`GogGlobalConfig`/`provideGogConfig(...)`: one injection token
|
|
811
|
+
for app-wide defaults across the library's component inputs, instead of a
|
|
812
|
+
separate token per component per setting. Call `provideGogConfig({ scroll:
|
|
813
|
+
{...}, button: {...} })` once in your app's providers (or a route's/
|
|
814
|
+
component's own `providers` for a subtree-scoped override); any instance
|
|
815
|
+
that doesn't set the input itself falls back to the configured value, then
|
|
816
|
+
to the component's own hardcoded default. `gog-scroll`'s `size`, `autoHide`,
|
|
817
|
+
`hideDelay` and `overscrollBehavior` and `gog-button`'s `debounce` are the
|
|
818
|
+
first inputs wired up to it — see the "Global configuration" section in
|
|
819
|
+
`gleks-ui-library.instructions.md` for how to add more. This only covers
|
|
820
|
+
inputs read in TypeScript that can't already be a CSS token; visual
|
|
821
|
+
defaults remain the `--gog-*` custom properties in `theme.css`.
|
|
822
|
+
|
|
823
|
+
### Changed
|
|
824
|
+
|
|
825
|
+
- `gog-checkbox` now registers its `ControlValueAccessor` by self-injecting
|
|
826
|
+
`NgControl` in the constructor, matching every other form control in the
|
|
827
|
+
library, instead of the `NG_VALUE_ACCESSOR`/`forwardRef` provider pattern.
|
|
828
|
+
No behavior change — `formControl`/`formControlName` usage is unaffected.
|
|
829
|
+
- `gog-scroll`'s `size`, `autoHide`, `hideDelay` and `overscrollBehavior` inputs and
|
|
830
|
+
`gog-button`'s `debounce` input now default to `undefined` instead of a hardcoded
|
|
831
|
+
value, so they can fall through to `GOG_CONFIG` — read the resolved value (e.g. via
|
|
832
|
+
the rendered DOM) rather than the raw input signal if you need the effective default.
|
|
833
|
+
- `gog-select` and `gog-multiselect`: the option panel now scrolls via
|
|
834
|
+
`gog-scroll` instead of native `overflow-y`.
|
|
835
|
+
- `gog-dialog`: the body now scrolls via `gog-scroll` instead of native
|
|
836
|
+
`overflow-y`.
|
|
837
|
+
- `gog-table`: horizontal scrolling now goes through `gog-scroll` instead of
|
|
838
|
+
native `overflow-x`.
|
|
839
|
+
|
|
840
|
+
### Fixed
|
|
841
|
+
|
|
842
|
+
- `gog-scroll` internals used `height: 100%` chains from `:host` down to the
|
|
843
|
+
viewport. A host whose own height comes from being flex-grown inside a
|
|
844
|
+
`max-height`-only ancestor (exactly the select/multiselect dropdown panel
|
|
845
|
+
and dialog body cases above) still failed to resolve a percentage height
|
|
846
|
+
read off it, collapsing back to content size — the panel stopped clipping
|
|
847
|
+
and scrolling. Switched every level to flex-basis chains
|
|
848
|
+
(`flex: 1 1 auto` + `min-height: 0`), which don't have that failure mode.
|
|
849
|
+
- `gog-scroll`'s horizontal content wrapper used `width: max-content`, which
|
|
850
|
+
created a circular sizing reference against a `width: 100%` child (e.g.
|
|
851
|
+
`gog-table`'s own `<table>`) and made some browsers fall back to a huge
|
|
852
|
+
sentinel width (~1,000,000px), pushing the table off-screen. Removed —
|
|
853
|
+
children already overflow a normal block parent without it.
|
|
854
|
+
- `gog-scroll` set `overscroll-behavior: contain` (both axes) on the
|
|
855
|
+
viewport unconditionally, which also blocked wheel scroll on an axis the
|
|
856
|
+
instance never actually scrolls (e.g. vertical wheel over a horizontal-only
|
|
857
|
+
instance), preventing it from bubbling up to scroll the page. Now set only
|
|
858
|
+
on the axis that's actually acting as a scroll container.
|
|
859
|
+
- `gog-scroll` kept a disabled or currently-non-overflowing axis at
|
|
860
|
+
`overflow: hidden`/`auto`, which makes an element a "scroll container" per
|
|
861
|
+
spec regardless of whether it has anything to scroll — becoming the
|
|
862
|
+
containing block for `position: sticky` descendants and a scroll-chaining
|
|
863
|
+
boundary, whether needed or not. This broke `gog-table`'s `stickyHeader`
|
|
864
|
+
and swallowed wheel scroll whenever a `gog-table` (which always wraps its
|
|
865
|
+
own horizontal scroll in a `gog-scroll`) was itself nested inside another
|
|
866
|
+
scrolling container, e.g. a `gog-scroll` capping its height. Both axes are
|
|
867
|
+
now `visible` unless that specific axis is genuinely scrolling.
|
|
868
|
+
|
|
869
|
+
## [21.2.3] - 03.08.2026
|
|
870
|
+
|
|
871
|
+
### Added
|
|
872
|
+
|
|
873
|
+
- `fullWidth` input on `gog-checkbox`, `gog-chip` and `gog-tag`, matching the
|
|
874
|
+
existing `gog-button` behavior: `false` by default (sized to content), `true`
|
|
875
|
+
stretches the component to fill its container.
|
|
876
|
+
- `fullWidth` input on `gog-inputfield`, `gog-select`, `gog-multiselect`,
|
|
877
|
+
`gog-table`, `gog-paginator` and `gog-slider`. Inverted from the input above:
|
|
878
|
+
these are already full width of their container by default, so `fullWidth`
|
|
879
|
+
defaults to `true` and set it to `false` to shrink the control to fit its
|
|
880
|
+
content instead (a fixed `--gog-slider-auto-width`, 240px by default, for
|
|
881
|
+
`gog-slider` specifically — its track has no content of its own to size to).
|
|
882
|
+
- `gog-accordion`'s `skeletonCount` input: how many skeleton rows to render
|
|
883
|
+
while `loading` is true and `items` is still empty. Defaults to `3`.
|
|
884
|
+
|
|
885
|
+
### Changed
|
|
886
|
+
|
|
887
|
+
- `gog-accordion`'s `loading` skeleton now renders with `gog-skeleton` instead
|
|
888
|
+
of a bespoke shimmer implementation. **Breaking:** the
|
|
889
|
+
`--gog-accordion-skeleton-start/-mid/-end/-radius/-height/-width/-duration`
|
|
890
|
+
tokens are gone — restyle the loading state via the shared `--gog-skeleton-*`
|
|
891
|
+
tokens instead.
|
|
892
|
+
|
|
893
|
+
### Fixed
|
|
894
|
+
|
|
895
|
+
- `gog-accordion`'s `loading` skeleton now actually renders while `items` is
|
|
896
|
+
empty. It previously rendered one skeleton row per existing item, so the
|
|
897
|
+
most common real-world case — showing loading state before the item list
|
|
898
|
+
has arrived at all — silently rendered nothing. It now falls back to
|
|
899
|
+
`skeletonCount` rows whenever `items` is empty, and still mirrors `items`
|
|
900
|
+
once they exist.
|
|
901
|
+
- `gog-accordion`'s chevron no longer force-rotates 180° when a custom
|
|
902
|
+
`gogAccordionChevron` template is supplied. Previously the wrapper always
|
|
903
|
+
rotated on open regardless of what the template rendered, so a template that
|
|
904
|
+
swapped between a `chevron-up`/`chevron-down` icon per `open` state ended up
|
|
905
|
+
double-transformed (both states visually pointing the same way). The rotation
|
|
906
|
+
now only applies to the built-in default chevron; a custom template owns its
|
|
907
|
+
open/closed presentation entirely, including bringing its own animation or
|
|
908
|
+
swapping in a completely different icon.
|
|
909
|
+
|
|
910
|
+
## [21.2.2] - 30.07.2026
|
|
911
|
+
|
|
912
|
+
### Added
|
|
913
|
+
|
|
914
|
+
- `column`'s `comparator` input for custom per-column sort ordering; the default
|
|
915
|
+
comparator now uses `Intl.Collator` for numeric-aware string sorting
|
|
916
|
+
(`"item2" < "item10"`) instead of raw `<`/`>`.
|
|
917
|
+
- `gog-table` cell/sort values now resolve dot-path nested fields (e.g.
|
|
918
|
+
`field="address.city"`).
|
|
919
|
+
- ESLint (`@angular-eslint`, flat config) across `@gleks/ui` and `ui-showcase`, wired
|
|
920
|
+
into CI alongside `format:check` and a token-consistency check (every
|
|
921
|
+
`var(--gog-*)` read with no fallback must resolve to a declared default).
|
|
922
|
+
- `LICENSE` (MIT) and this changelog.
|
|
923
|
+
|
|
924
|
+
### Changed
|
|
925
|
+
|
|
926
|
+
- **Breaking:** every previously unprefixed global design token in `theme.css`
|
|
927
|
+
(`--accent-color`, `--text-color`, `--radius`, `--control-*`, `--field-*`,
|
|
928
|
+
`--dropdown-z`, etc.) is now `--gog-*` prefixed, matching the component-token
|
|
929
|
+
convention. Update any consumer theme overrides to the new names.
|
|
930
|
+
- **Breaking:** `column`'s `field` input is now a plain `string` (was
|
|
931
|
+
`keyof T & string`) to support nested dot-paths.
|
|
932
|
+
- `gog-select`/`gog-multiselect` panel sizing constants (max height, estimated row
|
|
933
|
+
height) are now read from CSS custom properties
|
|
934
|
+
(`--gog-select-panel-max-height`, `--gog-select-option-height`, and the
|
|
935
|
+
multiselect equivalents) instead of hardcoded in TypeScript, so they're themeable.
|
|
936
|
+
- `gog-table`'s pagination state now uses `linkedSignal` instead of a manual
|
|
937
|
+
`effect`, resetting to page 1 on sort changes and clamping to `totalPages` on
|
|
938
|
+
data/page-size changes, while still deferring to `gog-paginator`'s own
|
|
939
|
+
self-clamping `page` model.
|
|
940
|
+
|
|
941
|
+
### Fixed
|
|
942
|
+
|
|
943
|
+
- An append-to-body dropdown panel now copies the trigger's scoped `data-theme`
|
|
944
|
+
(not just `:root`'s) onto its overlay host, so panels stay themed when opened
|
|
945
|
+
inside a themed subtree.
|
|
946
|
+
- `gog-select` now correctly reads its own `--gog-select-option-gap` token for
|
|
947
|
+
panel-height estimation instead of the unused base default, fixing a latent
|
|
948
|
+
under-estimate in the panel's up/down placement math.
|
|
949
|
+
|
|
950
|
+
## [0.0.1] through 0.2.2
|
|
951
|
+
|
|
952
|
+
Initial development, published as `0.0.1`: accordion, button, checkbox, chip, dialog,
|
|
953
|
+
icon, inputfield, multiselect, paginator, select, skeleton, slider, spinner, table, tag
|
|
954
|
+
and toast components, plus the shared theme (`styles/theme.css`) and `ThemeService`.
|
|
955
|
+
Versions up to `0.2.2` were developed without per-release changelog entries. `0.2.2` was
|
|
956
|
+
published with the wrong version scheme and immediately re-published, with no code
|
|
957
|
+
changes, as `21.2.2` — this file tracks changes from `21.2.2` onward.
|