@guildofgleks/ui 21.4.3 → 21.4.4

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/CHANGELOG.md CHANGED
@@ -6,12 +6,78 @@ reached 1.0, so breaking changes may land in minor versions.
6
6
 
7
7
  ## [21.5.0] - planned
8
8
 
9
- Nothing yet. What this release already owes is in the source: every
10
- `@deprecated Removed in 21.5.0` tag — the six legacy icon inputs on `gog-inputfield`, the
11
- `checkIconTemplate` / `clearIconTemplate` / `iconTemplate` / `chevronTemplate` inputs, the
12
- `<column>` element with its `Column` const and type, the string-keyed `[template]` column slot,
13
- and the `GogSelectOption` / `GogMultiselectOption` aliases (those two overran their announced
14
- 21.4.0 removal). Each names its replacement in the tag itself.
9
+ **The breaking release** the one version consumers have to read before upgrading into. It
10
+ carries the removals below and, per `docs/hardening-21.5.0.md`, the token-prefix rename
11
+ (`--gog-ms-*`, `--gog-btn-*`, `--gog-input-*` spelled out in full). Everything non-breaking that
12
+ is ready today ships in 21.4.4 instead, so a reader upgrading to 21.4.4 has nothing to migrate
13
+ and a reader upgrading to 21.5.0 has one list to work through rather than one buried among fixes.
14
+
15
+ ### Removed
16
+
17
+ Not done yet — this section records what the version owes. Fourteen public symbols carry an
18
+ `@deprecated … Removed in 21.5.0` tag naming its own replacement:
19
+
20
+ - the six legacy icon inputs on `gog-inputfield`;
21
+ - the `checkIconTemplate` / `clearIconTemplate` / `iconTemplate` / `chevronTemplate` inputs;
22
+ - the `<column>` element, with its `Column` const and type;
23
+ - the string-keyed `[template]` column slot;
24
+ - the `GogSelectOption` / `GogMultiselectOption` aliases — **these two overran their announced
25
+ 21.4.0 removal**, which is the reason the date on this list is not moved again.
26
+
27
+ One more is promised in prose rather than by a tag, so it has no `@deprecated` to grep for and is
28
+ the one most likely to be missed:
29
+
30
+ - the **`./src/styles/*` export** in `package.json`. Stylesheets moved to `./styles/*` in 21.3.2
31
+ and the README says the old path "keeps working until 21.5.0". Removing it breaks anyone still
32
+ importing `@guildofgleks/ui/src/styles/…`, and the README paragraph promising it goes too.
33
+
34
+ ## [21.4.4] - 17.08.2026
35
+
36
+ Everything that is ready. Two defects and one addition, none of which changes an existing
37
+ signature, so upgrading from 21.4.3 needs no migration — see the `gog-collapsible` entry only if
38
+ you were relying on a panel being capped at 480px.
39
+
40
+ ### Added
41
+
42
+ - **`ng add @guildofgleks/ui` now works.** It installs the latest version and adds
43
+ `node_modules/@guildofgleks/ui/styles/index.css` to your project's `angular.json` styles —
44
+ the one setup step that's pure mechanical JSON editing. Importing components and placing
45
+ `<gog-dialog />` / `<gog-toast-container />` are still manual; see the README.
46
+
47
+ In a patch rather than a minor because it is purely additive — it adds a way to install the
48
+ package and touches no existing API — the same reasoning that put "`CHANGELOG.md` now ships
49
+ inside the package" in 21.4.2.
50
+
51
+ ### Fixed
52
+
53
+ - **An open `gog-collapsible` no longer clips content taller than 480px.**
54
+ `--gog-collapsible-max-height` defaulted to `480px` and the panel is `overflow: hidden`, so any
55
+ panel taller than that lost the rest of its content — with no scrollbar, no ellipsis and nothing
56
+ else to indicate it. The cap existed only to give the CSS transition an animatable target, which
57
+ meant every consumer had to discover the limit by having content disappear, then override the
58
+ token per instance. The default is now `max-content`, and `interpolate-size: allow-keywords` on
59
+ the panel keeps the open/close transition animating to it. `gog-accordion` never had this
60
+ problem — it animates `grid-template-rows` instead — so the two components now behave the same
61
+ way.
62
+
63
+ No token was added or removed, and nothing about the closed state changed. **Setting
64
+ `--gog-collapsible-max-height` to a length still caps the panel and still clips**, which is now
65
+ a deliberate opt-in rather than the default; per-instance overrides that only existed to work
66
+ around the old cap can be deleted.
67
+
68
+ - **`gog-button`'s loading spinner was painted with the page's text colour.**
69
+ `--gog-btn-primary-spinner-color` and `--gog-btn-secondary-spinner-color` resolved to
70
+ `--gog-text-color` — the colour of text on the page background — while the label beside the
71
+ spinner used `--gog-accent-text-color`, the colour meant to sit on the button's fill. On the two
72
+ filled variants those are opposite ends of the palette, so the spinner came out washed out: on
73
+ the dark theme, `#f3ebd8` parchment on a `#fbbf24` amber button, next to a near-black label.
74
+ Both now resolve to the variant's own label colour, so a spinner reads exactly as strongly as
75
+ the text it replaced and follows any re-theming of the button's foreground. `outline` and
76
+ `ghost` were already correct and are untouched.
77
+
78
+ Only the two tokens' values changed; no token was added or removed. A theme that sets either
79
+ one explicitly is unaffected. Note the button as a whole still dims to
80
+ `--gog-btn-loading-opacity` (0.7) while loading — that is deliberate and separate from this.
15
81
 
16
82
  ## [21.4.3] - 16.08.2026
17
83
 
@@ -32,6 +98,7 @@ first entry if you were relying on a calendar filling its container.
32
98
 
33
99
  This sizes `inline` mode too — `[inline]="true"` renders `gog-calendar` with a border and
34
100
  nothing else. **Set `--gog-calendar-max-width: 100%` to keep the old full-width behaviour.**
101
+
35
102
  - **`--gog-datepicker-panel-width`** (default `max-content`) exposes the dropdown panel's width,
36
103
  which was hardcoded. Same value as before; nothing changes unless you set it.
37
104
 
@@ -80,7 +147,7 @@ entries above are that kind of gap, which is why a documentation-only patch was
80
147
  - **Overlays ignored custom properties set on `:root`.** A select panel, tooltip or any other
81
148
  overlay rendered into `<body>` copied the `data-theme` of its trigger's nearest themed
82
149
  ancestor. When that ancestor is `<html>` — the usual case — the copy made the overlay match
83
- `theme.css`'s derived layer (`:root, [data-theme]`) *locally*, re-declaring every component
150
+ `theme.css`'s derived layer (`:root, [data-theme]`) _locally_, re-declaring every component
84
151
  token against the plain preset palette and discarding anything set on the root that the preset
85
152
  does not itself declare.
86
153
 
@@ -88,7 +155,7 @@ entries above are that kind of gap, which is why a documentation-only patch was
88
155
  `document.documentElement` — a live theme editor, or any runtime accent switch — saw the
89
156
  document follow while every overlay kept rendering the un-edited theme.
90
157
 
91
- The attribute is now copied only for a genuinely *scoped* theme, where the overlay would
158
+ The attribute is now copied only for a genuinely _scoped_ theme, where the overlay would
92
159
  otherwise pick up the document's; when the theme sits on the document element, inheritance
93
160
  already does the work. Several themes rendered side by side in scoped subtrees keep working
94
161
  exactly as before.
@@ -108,6 +175,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
108
175
  `gogPageChange` deliberately stays quiet in two cases: the initial render, and the reset to
109
176
  page 1 that a new sort causes — that reset is part of the sort, and a consumer refetching from
110
177
  both events would issue two requests for one user action.
178
+
111
179
  - **`gog-table`: `lazy` — server-driven sorting and paging.** With `[lazy]="true"` the table
112
180
  stops sorting and slicing `value` and renders it exactly as handed over, treating it as the
113
181
  current page; `totalRecords` tells the paginator how many pages exist, and the two outputs are
@@ -124,6 +192,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
124
192
  **The select-all covers the current page, not the whole data set** — in `lazy` mode the table
125
193
  has never seen the other pages, and a control that meant different things in the two modes
126
194
  would be worse than either behaviour on its own.
195
+
127
196
  - **`gog-table`: `dataKey`.** The field (or dot-path) identifying a row. Selection matches on it
128
197
  instead of object identity — without it a refetch producing new objects silently drops the
129
198
  selection — and it becomes the `@for` track key, so the rendered DOM survives a refetch of the
@@ -132,7 +201,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
132
201
  Enter and Space activating the focused row. `gogRowClick` fires on a click either way; this is
133
202
  what stops a whole-row target from being mouse-only.
134
203
  - **`[gogButton]` — a link that looks like a button.** `gog-button` renders its own `<button>`,
135
- so it could never *be* a link, and a large share of buttons on a real site are navigation. The
204
+ so it could never _be_ a link, and a large share of buttons on a real site are navigation. The
136
205
  directive inverts the relationship: the element stays the consumer's, and only the look is
137
206
  applied.
138
207
 
@@ -153,6 +222,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
153
222
  on an `<a>`) and no `loading` (the spinner is a projected child a directive cannot add). The
154
223
  selector is `a[gogButton], button[gogButton]`, not a bare attribute, so it cannot be put on a
155
224
  `<div>` and produce something that looks clickable and is invisible to the keyboard.
225
+
156
226
  - **`gog-paginator`: a rows-per-page select.** `showPageSizeSelect` turns it on (**off by
157
227
  default** — a paginator that silently grew a control would change every existing layout) and
158
228
  `pageSizeOptions` sets the choices, defaulting to `[10, 20, 30, 40, 50]`. Both are also
@@ -160,7 +230,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
160
230
  while the rest of the app uses the house default.
161
231
  - **`gog-paginator`: `pageSize` (a `model`) and `totalRecords`.** Given `totalRecords`, the
162
232
  paginator derives the page count from `pageSize` itself — which removes the
163
- `computed(() => Math.ceil(total / size))` a consumer would otherwise have to write *and* keep
233
+ `computed(() => Math.ceil(total / size))` a consumer would otherwise have to write _and_ keep
164
234
  in sync with the select. `totalPages` still works and is right when a server hands you a page
165
235
  count directly; `totalRecords` wins if both are set. Changing the size returns to page 1:
166
236
  "page 5" of 10-row pages is not "page 5" of 50-row ones, so clamping alone would leave the user
@@ -174,7 +244,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
174
244
  - **`provideGogIcons(...)` — register your own icons by name.** `gog-icon` shipped a closed set
175
245
  of 20 glyphs, and the only way to render anything else was a `TemplateRef` per instance,
176
246
  which costs an `<ng-template>` at every use site and does not work at all for the components
177
- that take an icon *name* (`gog-tag`, `gog-chip`, `gog-tabs`, `gog-button-toggle-group`,
247
+ that take an icon _name_ (`gog-tag`, `gog-chip`, `gog-tabs`, `gog-button-toggle-group`,
178
248
  `ToastService`, `DialogService`). In practice that meant installing a second icon library —
179
249
  precisely the dependency the "no CDK, no Material" footprint exists to avoid.
180
250
 
@@ -184,8 +254,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
184
254
  ```
185
255
 
186
256
  ```html
187
- <gog-icon name="cart" />
188
- <gog-tag iconName="cart">In basket</gog-tag>
257
+ <gog-icon name="cart" /> <gog-tag iconName="cart">In basket</gog-tag>
189
258
  ```
190
259
 
191
260
  - A registered name **overrides a built-in of the same name**, so an app can replace the
@@ -193,6 +262,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
193
262
  - Providing it again lower in the injector tree **layers onto** the parent set rather than
194
263
  replacing it, matching `provideGogConfig`.
195
264
  - The registry is also exposed as the `GOG_ICONS` injection token.
265
+
196
266
  - **`GogBuiltinIconName`** — the closed union of the shipped glyphs, for code that wants
197
267
  exhaustiveness (an icon gallery, a `Record` keyed by icon).
198
268
  - **21 more built-in icons, taking the set from 20 to 41.** The old set covered what the
@@ -213,6 +283,7 @@ A minor rather than a patch: this adds public API. Iterations 5 and 6 of the con
213
283
 
214
284
  Cost: `ICON_DEFS` is one object, so every consumer pays for all of it — it grew from 8.0 KB to
215
285
  16.5 KB raw, **1.6 KB to 2.7 KB gzipped**.
286
+
216
287
  - **Attribution for the icons.** The glyphs were always Lucide but the package said so nowhere;
217
288
  Lucide's ISC licence asks for the notice to travel with them. It is now at the top of
218
289
  `icons.ts` and summarised in the README's licence section.
@@ -400,7 +471,7 @@ made unreachable.
400
471
  overriding it, and ignored outside `range` mode (nothing to disable "one side" of there). A
401
472
  one-sided disable only dims and disables that one thumb (its native input's own `disabled`
402
473
  attribute takes it out of the tab order); the whole-control `.gog-slider--disabled` styling
403
- (dimming + `pointer-events: none` over the whole track) only kicks in once *both* sides are
474
+ (dimming + `pointer-events: none` over the whole track) only kicks in once _both_ sides are
404
475
  disabled, since applying it for just one would also block pointer input to the other,
405
476
  still-enabled thumb. Reactive forms are unaffected by this addition: a `[formControl]`'s own
406
477
  `.disable()`/`.enable()` still speaks for both thumbs at once, same as before — one
package/README.md CHANGED
@@ -31,6 +31,20 @@ npm install @guildofgleks/ui
31
31
 
32
32
  ## Setup
33
33
 
34
+ Install it with whichever package manager you use — or with `ng add`, which installs it and does
35
+ step 1 for you:
36
+
37
+ ```bash
38
+ npm install @guildofgleks/ui
39
+ # or
40
+ yarn add @guildofgleks/ui
41
+ # or — also does step 1 below
42
+ ng add @guildofgleks/ui
43
+ ```
44
+
45
+ Steps 2 and 3 are yours either way: a schematic can't know where in your app you want components
46
+ or dialog and toast hosts.
47
+
34
48
  **1. Add the stylesheet.** It carries the baseline theme and the utility classes the components
35
49
  use — without it they render unstyled.
36
50
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guildofgleks/ui",
3
- "version": "21.4.3",
3
+ "version": "21.4.4",
4
4
  "engines": {
5
5
  "node": ">=20.19.0"
6
6
  },
@@ -37,6 +37,7 @@
37
37
  "tslib": "^2.3.0"
38
38
  },
39
39
  "sideEffects": false,
40
+ "schematics": "./schematics/collection.json",
40
41
  "exports": {
41
42
  "./styles/*": {
42
43
  "default": "./styles/*"
@@ -0,0 +1,9 @@
1
+ {
2
+ "schematics": {
3
+ "ng-add": {
4
+ "description": "Adds the @guildofgleks/ui baseline stylesheet to your project's angular.json.",
5
+ "factory": "./ng-add/index.cjs#ngAdd",
6
+ "schema": "./ng-add/schema.json"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ngAdd = ngAdd;
4
+ const workspace_1 = require("@schematics/angular/utility/workspace");
5
+ const STYLE_PATH = 'node_modules/@guildofgleks/ui/styles/index.css';
6
+ function ngAdd(options) {
7
+ return (_tree, context) => {
8
+ return (0, workspace_1.updateWorkspace)((workspace) => {
9
+ const projectNames = options.project
10
+ ? [options.project]
11
+ : [...workspace.projects.keys()].filter((name) => workspace.projects.get(name)?.extensions['projectType'] === 'application');
12
+ if (projectNames.length === 0) {
13
+ context.logger.warn(`@guildofgleks/ui: no application project found to add "${STYLE_PATH}" to. ` +
14
+ "Add it to your project's styles array yourself.");
15
+ }
16
+ let added = false;
17
+ for (const name of projectNames) {
18
+ const project = workspace.projects.get(name);
19
+ const build = project?.targets.get('build');
20
+ if (!build) {
21
+ if (options.project) {
22
+ context.logger.warn(`@guildofgleks/ui: project "${name}" has no "build" target — skipping the styles setup.`);
23
+ }
24
+ continue;
25
+ }
26
+ build.options ?? (build.options = {});
27
+ added = prependStyle(build.options) || added;
28
+ // `@angular/build:unit-test`, the v21 default, has no `styles` of its own — it builds
29
+ // through `buildTarget`, so the line above already covers component tests. The karma
30
+ // builders do carry their own array, and there the build target's styles are not read.
31
+ // Only touch the test target when it already declares one: adding the key to a builder
32
+ // whose schema forbids it would make `ng test` fail schema validation.
33
+ const test = project?.targets.get('test');
34
+ if (test?.options && Array.isArray(test.options['styles'])) {
35
+ added = prependStyle(test.options) || added;
36
+ }
37
+ }
38
+ // Only say so when something actually changed — a re-run that finds the stylesheet already
39
+ // there, or a workspace where no project could be updated, should not claim otherwise.
40
+ if (added) {
41
+ context.logger.info("@guildofgleks/ui: added the baseline stylesheet to your project's styles. Next: import " +
42
+ 'the standalone components you use, and if you use dialogs or toasts, add ' +
43
+ '<gog-dialog /> and <gog-toast-container /> once in your root component. See ' +
44
+ 'https://ui.guildofgleks.com for details.');
45
+ }
46
+ });
47
+ };
48
+ }
49
+ /**
50
+ * Puts the baseline stylesheet first in a target's `styles`, so anything the consumer already had
51
+ * still comes after it and wins. Returns whether it changed anything — a second `ng add` must be
52
+ * a no-op.
53
+ */
54
+ function prependStyle(options) {
55
+ const existing = options['styles'];
56
+ const styles = Array.isArray(existing) ? existing : [];
57
+ if (styles.includes(STYLE_PATH)) {
58
+ return false;
59
+ }
60
+ options['styles'] = [STYLE_PATH, ...styles];
61
+ return true;
62
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "GuildOfGleksUiNgAdd",
4
+ "title": "GuildOfGleks UI ng-add schema",
5
+ "type": "object",
6
+ "properties": {
7
+ "project": {
8
+ "type": "string",
9
+ "description": "The name of the project to add the library's stylesheet to.",
10
+ "$default": {
11
+ "$source": "projectName"
12
+ }
13
+ }
14
+ }
15
+ }
@@ -400,10 +400,15 @@
400
400
  rules (they style content this component's consumer projects, which sits outside
401
401
  `gog-collapsible`'s own view and can't be reached by its scoped stylesheet). */
402
402
  --gog-collapsible-transition-duration: var(--gog-duration-slow);
403
- /* Generous fixed cap rather than a measured height: the CSS-only max-height transition
404
- trades exact timing for arbitrary content (any number of children) without JS. Override
405
- per-instance if a particular panel's content can exceed this. */
406
- --gog-collapsible-max-height: 480px;
403
+ /* The panel's natural height, so an open panel never truncates whatever it holds. This was
404
+ a fixed `480px` cap, which bought the CSS-only transition an animatable target but paid
405
+ for it by silently clipping any taller content `overflow: hidden` means no scrollbar
406
+ and no other sign that the rest of the panel is missing. `max-content` still animates,
407
+ via `interpolate-size: allow-keywords` on the content element (see utilities.css); where
408
+ that is unsupported the panel snaps open instead of easing, which is the right way round
409
+ for the trade — losing an animation is visible and harmless, losing content is neither.
410
+ Set a length here to cap a particular panel on purpose; it will clip, as before. */
411
+ --gog-collapsible-max-height: max-content;
407
412
  --gog-collapsible-disabled-opacity: var(--gog-disabled-opacity);
408
413
 
409
414
  /* ── Button ────────────────────────────────────────────────────────────────
@@ -436,7 +441,10 @@
436
441
  --gog-btn-primary-hover-color: var(--gog-btn-primary-color);
437
442
  --gog-btn-primary-hover-shadow: 0 0 16px
438
443
  color-mix(in srgb, var(--gog-accent-bright) 45%, transparent);
439
- --gog-btn-primary-spinner-color: var(--gog-text-color);
444
+ /* The label's colour, not the page's. `--gog-text-color` is the colour of text on the page
445
+ background, and a filled button is not the page background — on the dark theme that put pale
446
+ parchment on bright amber, which read as a washed-out spinner beside a near-black label. */
447
+ --gog-btn-primary-spinner-color: var(--gog-btn-primary-color);
440
448
 
441
449
  --gog-btn-secondary-bg: var(--gog-secondary-color);
442
450
  --gog-btn-secondary-color: var(--gog-accent-text-color, var(--gog-primary-color));
@@ -445,7 +453,8 @@
445
453
  --gog-btn-secondary-hover-bg: var(--gog-accent-color);
446
454
  --gog-btn-secondary-hover-color: var(--gog-btn-secondary-color);
447
455
  --gog-btn-secondary-hover-shadow: none;
448
- --gog-btn-secondary-spinner-color: var(--gog-text-color);
456
+ /* Same reasoning as primary: the other filled variant, the same mismatch. */
457
+ --gog-btn-secondary-spinner-color: var(--gog-btn-secondary-color);
449
458
 
450
459
  --gog-btn-outline-bg: transparent;
451
460
  --gog-btn-outline-color: var(--gog-accent-color);