@guildofgleks/ui 21.6.0 → 21.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +326 -82
- package/CHANGELOG.md +269 -2
- package/README.md +98 -20
- package/TOKENS.md +10 -7
- package/fesm2022/guildofgleks-ui.mjs +1067 -1383
- package/fesm2022/guildofgleks-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/button.css +11 -32
- package/styles/index.css +5 -0
- package/styles/presets/bevel.css +82 -0
- package/styles/presets/ledger.css +66 -0
- package/styles/presets/material.css +111 -0
- package/styles/presets/one-dark.css +22 -5
- package/styles/presets/one-light.css +17 -4
- package/styles/presets/parchment.css +63 -0
- package/styles/presets/parchment.fonts.css +29 -0
- package/styles/presets/primeng.css +121 -0
- package/styles/presets/slate.css +26 -8
- package/styles/presets/terminal.css +67 -0
- package/styles/presets/terminal.fonts.css +26 -0
- package/styles/ripple.css +94 -0
- package/styles/surfaces.css +151 -0
- package/styles/theme.css +620 -516
- package/types/guildofgleks-ui.d.ts +359 -36
package/AGENTS.md
CHANGED
|
@@ -5,12 +5,13 @@ an app that **consumes** the published `@guildofgleks/ui` npm package. It is not
|
|
|
5
5
|
authoring the library — if you are working inside the `gleks_web_ui` monorepo itself, read
|
|
6
6
|
`.github/instructions/*.md` instead.
|
|
7
7
|
|
|
8
|
-
Everything below reflects the library's actual source as of **`21.
|
|
9
|
-
of deprecated API — see **Removed in 21.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
types and
|
|
8
|
+
Everything below reflects the library's actual source as of **`21.7.0`**. 21.7.0 removed the three
|
|
9
|
+
abbreviated token prefixes and 21.5.0 removed a batch of deprecated API — see **Removed in 21.7.0**
|
|
10
|
+
and **Removed in 21.5.0** near the end of this file, which exist so code written against an older
|
|
11
|
+
version can be migrated — and `CHANGELOG.md` has the rest. `README.md` covers the same ground at a
|
|
12
|
+
higher level — install, setup, theming, global configuration — and is accurate; this file goes
|
|
13
|
+
further, into per-component input tables, and is the one to trust for exact names, types and
|
|
14
|
+
defaults.
|
|
14
15
|
|
|
15
16
|
> **Maintainers:** this file ships inside the npm package and is the API reference an agent reads
|
|
16
17
|
> while writing code against it, so a stale table here becomes wrong code in someone else's app —
|
|
@@ -166,30 +167,66 @@ exist.
|
|
|
166
167
|
|
|
167
168
|
## Theming
|
|
168
169
|
|
|
169
|
-
Full model is in `README.md`'s Theming section
|
|
170
|
+
Full model is in `README.md`'s Theming section; short version:
|
|
170
171
|
|
|
171
172
|
- Every visual value (color, spacing, radius, shadow, duration) is a `--gog-*` CSS custom
|
|
172
173
|
property, layered **foundation** (`--gog-accent-color`, `--gog-space-md`, …, restyles
|
|
173
174
|
everything) → **component** (`--gog-button-primary-bg`, …, one block per component, named after
|
|
174
175
|
the component's own element) → **instance** (`--gog-button-bg`, …, deliberately undeclared
|
|
175
176
|
escape hatch for one element).
|
|
177
|
+
- **Foundation includes a small character layer** (since 21.7.0, `docs/themes.md` iteration 1):
|
|
178
|
+
`--gog-radius` (corner rounding), `--gog-control-border-*`/`--gog-panel-border-*`/`--gog-border-*`
|
|
179
|
+
(border weight — form fields, raised surfaces, everything smaller and inline, respectively),
|
|
180
|
+
`--gog-text-transform`/`--gog-letter-spacing` (emphasis casing/tracking). Component tokens in
|
|
181
|
+
the categories these cover derive from them by default; setting one in a `[data-theme]` block
|
|
182
|
+
restyles every component that reads it, with nothing to re-list per component.
|
|
183
|
+
- **`--gog-density` is the character layer for spacing** (since 21.7.0, `docs/themes.md`
|
|
184
|
+
iteration 6). It multiplies the fourteen-step scale `--gog-space-2` … `--gog-space-48`, named
|
|
185
|
+
for their pixel value at density 1, and every padding and gap in the library derives from a
|
|
186
|
+
step. `--gog-density: 0.9` in a `[data-theme]` block makes the whole library tighter; nothing
|
|
187
|
+
else needs to be named. `--gog-space-xs|sm|md|lg|2xl` are aliases for steps 4/8/16/24/48 and
|
|
188
|
+
still work. Icon offsets follow density; the glyph box, focus-ring offset and float-label
|
|
189
|
+
reserve deliberately do not — they are legibility, not spacing.
|
|
176
190
|
- **Component prefixes are spelled out** since 21.5.0: `--gog-button-*`, `--gog-multiselect-*`,
|
|
177
191
|
`--gog-confirmation-dialog-*`. The abbreviated `--gog-btn-*`, `--gog-ms-*` and `--gog-confirm-*`
|
|
178
|
-
|
|
179
|
-
`--gog-input-*`, which is not an abbreviation: it is
|
|
180
|
-
`gog-inputfield` and `gog-textarea` both render, and it keeps
|
|
192
|
+
were removed in 21.7.0 — if you're reading a codebase or an example that still uses one, rename
|
|
193
|
+
it; it no longer resolves. The exception is `--gog-input-*`, which is not an abbreviation: it is
|
|
194
|
+
the shared text-field block that `gog-inputfield` and `gog-textarea` both render, and it keeps
|
|
195
|
+
that name.
|
|
181
196
|
- **The package does not need the app's `box-sizing` reset** (since 21.6.0): `utilities.css`
|
|
182
197
|
sets `border-box` on every element carrying a `gog-*` class, including the ones the library
|
|
183
198
|
puts on a consumer's own element. Do not add a reset "so the components line up" — they
|
|
184
199
|
already do, and a `* { box-sizing: content-box }` in an app is the only thing that undoes it.
|
|
185
200
|
- Theme switch is a `data-theme` attribute, usually on `<html>`, toggled through the
|
|
186
201
|
`ThemeService` (`inject(ThemeService).setTheme('dark')` / `.toggleTheme()` / `.theme` signal).
|
|
187
|
-
Ships `light` and `dark
|
|
188
|
-
|
|
202
|
+
Ships `light` and `dark`, plus nine importable presets at
|
|
203
|
+
`@guildofgleks/ui/styles/presets/<name>.css`. **All nine set palette and character** (since
|
|
204
|
+
21.7.0 — before it, three were palette-only, which made them recoloured defaults):
|
|
205
|
+
|
|
206
|
+
| Preset | Radius | Density | Identity |
|
|
207
|
+
| ---------------------- | ------ | ------- | ------------------------------------------------ |
|
|
208
|
+
| `slate` | 12px | 1.05 | soft modern — hairline borders, roomy |
|
|
209
|
+
| `one-dark`/`one-light` | 4px | 0.9 | editor chrome; identical character, two tones |
|
|
210
|
+
| `material` | 4px | 1.1 | Material Design 3, pill buttons |
|
|
211
|
+
| `primeng` | 6px | 0.95 | PrimeNG Aura |
|
|
212
|
+
| `ledger` | 0 | 0.9 | administrative — hard offset shadow, no motion |
|
|
213
|
+
| `terminal` | 0 | 0.85 | green phosphor, monospaced throughout, no motion |
|
|
214
|
+
| `bevel` | 0 | 0.9 | early-web desktop — `outset`/`inset` borders |
|
|
215
|
+
| `parchment` | 0 | 1.1 | ink on paper — old-style serif, oxblood |
|
|
216
|
+
|
|
217
|
+
`material`, `primeng` and `bevel` also set a few genuinely per-component things the character
|
|
218
|
+
layer has no vocabulary for (a pill button, a table's header font, a button bevel that has to
|
|
219
|
+
disagree with a field's); see their own file headers.
|
|
220
|
+
|
|
221
|
+
- **A preset never makes a network request.** Each sets a font _stack_ resolving to a real system
|
|
222
|
+
face. Where a webfont is worth offering, it is a separate opt-in file — `terminal.fonts.css`
|
|
223
|
+
(IBM Plex Mono), `parchment.fonts.css` (EB Garamond) — imported **after** the preset, since it
|
|
224
|
+
re-points the same tokens and later wins. Do not add an `@import url(…)` to a preset itself; put
|
|
225
|
+
it in a companion file, or the import becomes a download nobody asked for.
|
|
189
226
|
- Restyle one instance without touching a theme: `<gog-button style="--gog-button-bg: #ff4edb">`.
|
|
190
|
-
- Build a custom theme by declaring a palette against a new `data-theme`
|
|
191
|
-
`
|
|
192
|
-
don't restate them.
|
|
227
|
+
- Build a custom theme by declaring a palette **and a character** against a new `data-theme`
|
|
228
|
+
value (see `README.md`'s Theming section for the full worked example) — component tokens
|
|
229
|
+
re-derive automatically, you don't restate them.
|
|
193
230
|
|
|
194
231
|
## Right-to-left
|
|
195
232
|
|
|
@@ -235,6 +272,7 @@ parent's config**, one level deep per key — it does not replace it.
|
|
|
235
272
|
| `tooltip` | `position`, `showDelay`, `hideDelay` | the `gogTooltip` directive. |
|
|
236
273
|
| `scroll` | `autoHide`, `hideDelay`, `size`, `overscrollBehavior`, `showTrack` | `gog-scroll` (and every component that uses one internally). |
|
|
237
274
|
| `button` | `debounce` | `gog-button`. |
|
|
275
|
+
| `ripple` | `enabled` | the press ripple on `gog-button`, `[gogButton]`, `gog-button-toggle-group`, `gog-chip`, `gog-tabs`, `gog-accordion`, `gogCollapsibleTrigger`, `gogMenuItem` and the `gog-select`/`gog-multiselect`/`gog-autocomplete` options. **Off by default.** Each of those takes a `ripple` input that wins over it. Not the `gogRipple` directive — writing that attribute is already the per-element decision. |
|
|
238
276
|
| `inputfield` | `showSpinButtons` | `gog-inputfield`. |
|
|
239
277
|
| `textarea` | `resize` | `gog-textarea`. |
|
|
240
278
|
| `paginator` | `showPageSizeSelect`, `pageSizeOptions` | `gog-paginator`, and through it `gog-table`'s built-in pagination. |
|
|
@@ -252,39 +290,39 @@ in English sets these once rather than on every control:
|
|
|
252
290
|
```ts
|
|
253
291
|
provideGogConfig({
|
|
254
292
|
labels: {
|
|
255
|
-
clear: '
|
|
256
|
-
clearSelection: '
|
|
257
|
-
clearDate: '
|
|
258
|
-
selectAll: '
|
|
259
|
-
clearAll: '
|
|
260
|
-
increment: '
|
|
261
|
-
decrement: '
|
|
262
|
-
showPassword: '
|
|
263
|
-
hidePassword: '
|
|
264
|
-
closeDialog: '
|
|
265
|
-
closeToast: '
|
|
266
|
-
pagination: '
|
|
267
|
-
previousPage: '
|
|
268
|
-
nextPage: '
|
|
269
|
-
openCalendar: '
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
293
|
+
clear: 'Löschen', // inputfield / textarea clear button
|
|
294
|
+
clearSelection: 'Auswahl löschen', // select / multiselect / autocomplete
|
|
295
|
+
clearDate: 'Datum löschen', // datepicker
|
|
296
|
+
selectAll: 'Alle auswählen', // multiselect panel
|
|
297
|
+
clearAll: 'Alle löschen', // multiselect panel
|
|
298
|
+
increment: 'Erhöhen', // number spin buttons
|
|
299
|
+
decrement: 'Verringern',
|
|
300
|
+
showPassword: 'Passwort anzeigen',
|
|
301
|
+
hidePassword: 'Passwort verbergen',
|
|
302
|
+
closeDialog: 'Schließen',
|
|
303
|
+
closeToast: 'Schließen',
|
|
304
|
+
pagination: 'Seitennavigation',
|
|
305
|
+
previousPage: 'Vorherige Seite',
|
|
306
|
+
nextPage: 'Nächste Seite',
|
|
307
|
+
openCalendar: 'Kalender öffnen',
|
|
308
|
+
togglePanel: 'Bereich umschalten', // gog-panel's toggle, only when it has no heading
|
|
309
|
+
rowsPerPage: 'Zeilen pro Seite', // gog-paginator's size select
|
|
310
|
+
total: 'Gesamt', // gog-table's row-count label
|
|
311
|
+
tablePagination: 'Tabellennavigation',
|
|
312
|
+
selectRow: 'Zeile auswählen',
|
|
313
|
+
selectAllRows: 'Alle Zeilen auswählen',
|
|
314
|
+
today: 'Heute',
|
|
315
|
+
thisMonth: 'Aktueller Monat',
|
|
316
|
+
previousMonth: 'Vorheriger Monat',
|
|
317
|
+
nextMonth: 'Nächster Monat',
|
|
318
|
+
previousYear: 'Vorheriges Jahr',
|
|
319
|
+
nextYear: 'Nächstes Jahr',
|
|
320
|
+
hours: 'Stunden',
|
|
321
|
+
minutes: 'Minuten',
|
|
322
|
+
seconds: 'Sekunden',
|
|
284
323
|
// The one non-string field: it interpolates the page number, and word order and
|
|
285
324
|
// agreement around a number vary by language, so it takes a formatter.
|
|
286
|
-
page: (page, isCurrent) =>
|
|
287
|
-
isCurrent ? `Страница ${page}, текущая` : `Перейти на страницу ${page}`,
|
|
325
|
+
page: (page, isCurrent) => (isCurrent ? `Seite ${page}, aktuell` : `Zu Seite ${page} wechseln`),
|
|
288
326
|
},
|
|
289
327
|
});
|
|
290
328
|
```
|
|
@@ -320,7 +358,7 @@ provideGogConfig({
|
|
|
320
358
|
followSystem: true, // open in the OS prefers-color-scheme, and keep following it
|
|
321
359
|
// until the app calls setTheme/toggleTheme
|
|
322
360
|
lightTheme: 'light', // the two names followSystem maps to and toggleTheme alternates
|
|
323
|
-
darkTheme: '
|
|
361
|
+
darkTheme: 'one-dark', // between
|
|
324
362
|
defaultTheme: 'light', // used when nothing else decides
|
|
325
363
|
},
|
|
326
364
|
});
|
|
@@ -368,10 +406,31 @@ async confirmDelete(): Promise<void> {
|
|
|
368
406
|
}
|
|
369
407
|
```
|
|
370
408
|
|
|
371
|
-
`DialogConfig
|
|
372
|
-
`open()` returns `{ close(result?), afterClosed: Promise<TResult | undefined> }`. Also:
|
|
409
|
+
`DialogConfig<TData>`: `{ title?, component, data?: TData, modal? (default true), closable?, draggable?, closeIconName?, closeIconTemplate?, width?, maxWidth?, role? ('dialog' default | 'alertdialog'), zIndex? }`.
|
|
410
|
+
`open<TResult, TData>()` returns `{ close(result?), afterClosed: Promise<TResult | undefined> }`. Also:
|
|
373
411
|
`closeAll(result?)`, `updatePosition(id, offsetX, offsetY)` (for `draggable` dialogs).
|
|
374
412
|
|
|
413
|
+
**`open<TResult, TData>()` type-checks `data` against `TData` when you supply both type
|
|
414
|
+
arguments** — supplying only `TResult` (the common case above) leaves `TData` as `unknown`,
|
|
415
|
+
exactly as before:
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
interface EditUserData {
|
|
419
|
+
userId: string;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const handle = this.dialogService.open<{ saved: boolean }, EditUserData>({
|
|
423
|
+
component: EditDialogComponent,
|
|
424
|
+
data: { userId: user.id }, // checked against EditUserData here
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
This checks only the call site. `EditDialogComponent` still reads its data via `inject(DIALOG_DATA)`
|
|
429
|
+
— an `InjectionToken<unknown>` shared by every dialog, so it still needs its own cast
|
|
430
|
+
(`inject<EditUserData>(DIALOG_DATA)`, shown below). Angular's DI has no way to carry a
|
|
431
|
+
per-call-site type through one shared token, so the receiving half of the round trip is still on
|
|
432
|
+
trust — this closes only the half that can be closed.
|
|
433
|
+
|
|
375
434
|
The library ships a ready-made `ConfirmationDialogComponent` for yes/no prompts — pass it as
|
|
376
435
|
`component` with `data: { title, description, confirmText, cancelText }`; it resolves the
|
|
377
436
|
dialog's result to `true`/`false`.
|
|
@@ -415,12 +474,20 @@ Every component below is exported from `@guildofgleks/ui`'s root — `import { X
|
|
|
415
474
|
| `loading` | `boolean` | `false` | shows an inline `gog-spinner`, blocks clicks |
|
|
416
475
|
| `debounce` | `number \| undefined` | `300` | ms; via `GOG_CONFIG.button.debounce` — see note below |
|
|
417
476
|
| `ariaLabel` | `string \| null` | `null` | **use this, not a raw `aria-label` attribute** |
|
|
477
|
+
| `ripple` | `boolean \| undefined` | `false` | press ripple; via `GOG_CONFIG.ripple.enabled` |
|
|
418
478
|
|
|
419
479
|
Outputs: `gogClick: MouseEvent`.
|
|
420
480
|
|
|
421
481
|
**`debounce` is a spam guard, not a delay before the first click.** The first click in a window
|
|
422
482
|
fires immediately (leading edge); further clicks within `debounce` ms are silently dropped.
|
|
423
483
|
|
|
484
|
+
**Use `(gogClick)`, never `(click)`, on `gog-button`.** The click handler that drives `debounce`
|
|
485
|
+
and emits `gogClick` is bound on the `<button>` inside the component's own template, not on the
|
|
486
|
+
host — a native click still bubbles up through `<gog-button>`, so a `(click)` listener written
|
|
487
|
+
there fires on every press, silently bypassing the debounce entirely. This is specific to the
|
|
488
|
+
component: `[gogButton]` on your own `<a>`/`<button>` has no debounce to bypass, so `(click)` on
|
|
489
|
+
it works exactly as written.
|
|
490
|
+
|
|
424
491
|
```html
|
|
425
492
|
<gog-button variant="primary" [loading]="saving()" (gogClick)="save()">Save</gog-button>
|
|
426
493
|
<gog-button variant="ghost" ariaLabel="Close" (gogClick)="close()"
|
|
@@ -432,18 +499,19 @@ fires immediately (leading edge); further clicks within `debounce` ms are silent
|
|
|
432
499
|
|
|
433
500
|
A row of buttons, single- or multi-select, built from your own option objects.
|
|
434
501
|
|
|
435
|
-
| Input | Type | Default | Notes
|
|
436
|
-
| ------------------------------------ | ------------------------------------------ | ---------------------- |
|
|
437
|
-
| `options` | `TOption[]` | `[]` |
|
|
438
|
-
| `optionLabel` | accessor | `'name'` |
|
|
439
|
-
| `optionValue` | accessor \| `null` | `'id'` | `null` emits the option object
|
|
440
|
-
| `optionDisabled` | accessor | `'disabled'` |
|
|
441
|
-
| `optionIcon` | accessor → `GogIconName \| null` \| `null` | `null` | optional leading icon per option
|
|
442
|
-
| `multiple` | `boolean` | `false` | changes ARIA role entirely — see note
|
|
443
|
-
| `appearance` | `'joined' \| 'separated'` | `'joined'` |
|
|
444
|
-
| `orientation` | `GogOrientation` | `'horizontal'` |
|
|
445
|
-
| `size` | `GogSize \| undefined` | `'md'` | via `GOG_CONFIG.control.size`
|
|
446
|
-
| `disabled`, `fullWidth`, `ariaLabel` | | `false`, `false`, `''` |
|
|
502
|
+
| Input | Type | Default | Notes |
|
|
503
|
+
| ------------------------------------ | ------------------------------------------ | ---------------------- | --------------------------------------------- |
|
|
504
|
+
| `options` | `TOption[]` | `[]` | |
|
|
505
|
+
| `optionLabel` | accessor | `'name'` | |
|
|
506
|
+
| `optionValue` | accessor \| `null` | `'id'` | `null` emits the option object |
|
|
507
|
+
| `optionDisabled` | accessor | `'disabled'` | |
|
|
508
|
+
| `optionIcon` | accessor → `GogIconName \| null` \| `null` | `null` | optional leading icon per option |
|
|
509
|
+
| `multiple` | `boolean` | `false` | changes ARIA role entirely — see note |
|
|
510
|
+
| `appearance` | `'joined' \| 'separated'` | `'joined'` | |
|
|
511
|
+
| `orientation` | `GogOrientation` | `'horizontal'` | |
|
|
512
|
+
| `size` | `GogSize \| undefined` | `'md'` | via `GOG_CONFIG.control.size` |
|
|
513
|
+
| `disabled`, `fullWidth`, `ariaLabel` | | `false`, `false`, `''` | |
|
|
514
|
+
| `ripple` | `boolean \| undefined` | `false` | press ripple; via `GOG_CONFIG.ripple.enabled` |
|
|
447
515
|
|
|
448
516
|
Model: `value: TValue | TValue[] | null` (single value, or array in `multiple` mode). CVA: yes.
|
|
449
517
|
Slot: `<ng-template gogButtonToggleOption let-opt let-selected="selected">` for custom button
|
|
@@ -552,6 +620,7 @@ and multiselect unless noted otherwise):
|
|
|
552
620
|
| `disabled`, `fullWidth` | | `false`, `true` | |
|
|
553
621
|
| `floatLabel`, `floatLabelShowPlaceholder` | | `'none'`, `false` | |
|
|
554
622
|
| `inputId` (select/autocomplete only) | `string` | `''` | |
|
|
623
|
+
| `ripple` | `boolean \| undefined` | `false` | press ripple; via `GOG_CONFIG.ripple.enabled` |
|
|
555
624
|
|
|
556
625
|
`gog-select`-specific: `value: model<TValue>(null)`.
|
|
557
626
|
`gog-multiselect`-specific additions: `value: model<TValue[]>([])`, `showControls: boolean` (default `false`, a select-all/clear row), `controlsPosition: 'top'|'bottom'` (default `'top'`), and `selectAllLabel`/`clearAllLabel` for that row's two buttons (`'Select all'`/`'Clear'`, also via `GOG_CONFIG.labels`).
|
|
@@ -595,6 +664,7 @@ panel-filter box; it filters/searches off what's typed in the field itself.
|
|
|
595
664
|
| `loading` | `boolean` | `false` | shows a spinner in the trailing slot |
|
|
596
665
|
| `emptyMessage` | `string` | `'No matches'` | |
|
|
597
666
|
| `forceSelection` | `boolean` | `true` | see note below |
|
|
667
|
+
| `ripple` | `boolean \| undefined` | `false` | press ripple; via `GOG_CONFIG.ripple.enabled` |
|
|
598
668
|
|
|
599
669
|
Outputs: `gogSearch: string` (debounced query — wire your server lookup here),
|
|
600
670
|
`gogLoadMore: void` (panel scrolled to the end — fetch the next page).
|
|
@@ -855,11 +925,12 @@ the element stays yours and the directive only gives it the look.
|
|
|
855
925
|
<a gogButton fullWidth routerLink="/checkout">Checkout</a>
|
|
856
926
|
```
|
|
857
927
|
|
|
858
|
-
| Input | Type | Default
|
|
859
|
-
| ----------- | ------------------------ |
|
|
860
|
-
| `variant` | `GogVariant` | `'primary'`
|
|
861
|
-
| `size` | `GogSize \| undefined` | `'md'`; via `GOG_CONFIG.control.size`
|
|
862
|
-
| `fullWidth` | `boolean` (bare attr ok) | `false`
|
|
928
|
+
| Input | Type | Default |
|
|
929
|
+
| ----------- | ------------------------ | ---------------------------------------- |
|
|
930
|
+
| `variant` | `GogVariant` | `'primary'` |
|
|
931
|
+
| `size` | `GogSize \| undefined` | `'md'`; via `GOG_CONFIG.control.size` |
|
|
932
|
+
| `fullWidth` | `boolean` (bare attr ok) | `false` |
|
|
933
|
+
| `ripple` | `boolean \| undefined` | `false`; via `GOG_CONFIG.ripple.enabled` |
|
|
863
934
|
|
|
864
935
|
Selector is `a[gogButton], button[gogButton]` — deliberately not a bare `[gogButton]`, because on
|
|
865
936
|
a `<div>` the result looks like a button and is invisible to the keyboard and to assistive tech.
|
|
@@ -900,16 +971,17 @@ are impossible by design.
|
|
|
900
971
|
|
|
901
972
|
#### `gog-chip`
|
|
902
973
|
|
|
903
|
-
| Input | Type | Default
|
|
904
|
-
| ------------------------------ | ----------------------------------- |
|
|
905
|
-
| `size` | `GogSize` | `'md'`
|
|
906
|
-
| `shape` | `GogTagShape` (`'rounded'\|'pill'`) | `'rounded'`
|
|
907
|
-
| `disabled`, `clickable` | `boolean` | `false`, `true`
|
|
908
|
-
| `removable` | `boolean` | `false`
|
|
909
|
-
| `fullWidth` | `boolean` | `false`
|
|
910
|
-
| `ariaLabel`, `removeAriaLabel` | `string` | `''`, `'Remove chip'`
|
|
911
|
-
| `avatarUrl`, `avatarAlt` | `string \| null` / `string` | `null`, `''`
|
|
912
|
-
| `iconName` | `GogIconName \| null` | `null`
|
|
974
|
+
| Input | Type | Default |
|
|
975
|
+
| ------------------------------ | ----------------------------------- | ---------------------------------------- |
|
|
976
|
+
| `size` | `GogSize` | `'md'` |
|
|
977
|
+
| `shape` | `GogTagShape` (`'rounded'\|'pill'`) | `'rounded'` |
|
|
978
|
+
| `disabled`, `clickable` | `boolean` | `false`, `true` |
|
|
979
|
+
| `removable` | `boolean` | `false` |
|
|
980
|
+
| `fullWidth` | `boolean` | `false` |
|
|
981
|
+
| `ariaLabel`, `removeAriaLabel` | `string` | `''`, `'Remove chip'` |
|
|
982
|
+
| `avatarUrl`, `avatarAlt` | `string \| null` / `string` | `null`, `''` |
|
|
983
|
+
| `iconName` | `GogIconName \| null` | `null` |
|
|
984
|
+
| `ripple` | `boolean \| undefined` | `false`; via `GOG_CONFIG.ripple.enabled` |
|
|
913
985
|
|
|
914
986
|
Outputs: `gogClick: MouseEvent | KeyboardEvent`, `gogRemove: void`.
|
|
915
987
|
|
|
@@ -1000,6 +1072,63 @@ Label is projected content, not an input — put an icon or a `gog-tag` inside i
|
|
|
1000
1072
|
<gog-divider>OR</gog-divider>
|
|
1001
1073
|
```
|
|
1002
1074
|
|
|
1075
|
+
#### `gogRipple` — directive, not a component
|
|
1076
|
+
|
|
1077
|
+
A pointer-position wash that grows from where you pressed and fades when you let go. Drop it on
|
|
1078
|
+
any element you already have — it adds no wrapper and changes no layout.
|
|
1079
|
+
|
|
1080
|
+
| Input | Type | Default |
|
|
1081
|
+
| ---------------- | --------- | ----------------------------------------------------------- |
|
|
1082
|
+
| `rippleDisabled` | `boolean` | `false` |
|
|
1083
|
+
| `rippleCentred` | `boolean` | `false` — start from the middle instead of from the pointer |
|
|
1084
|
+
|
|
1085
|
+
```html
|
|
1086
|
+
<button gogRipple>Press me</button>
|
|
1087
|
+
<div gogRipple rippleCentred class="tile">A tile</div>
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
Four things suppress it, none of which you have to wire up: `rippleDisabled`, a host carrying
|
|
1091
|
+
`disabled`, a host carrying `aria-disabled="true"`, and `prefers-reduced-motion: reduce` — the
|
|
1092
|
+
last one **suppressed outright, not shortened**. Keyboard activation (`Enter`/`Space`) is always
|
|
1093
|
+
centred, because a key press carries no coordinates.
|
|
1094
|
+
|
|
1095
|
+
**Put it on the element that paints the surface.** The wash lives in its own layer that clips
|
|
1096
|
+
itself — the host is never given `overflow: hidden`, so a `gogBadge` on the same element is not
|
|
1097
|
+
clipped — and that layer takes its corner radius from its host with `border-radius: inherit`. On a
|
|
1098
|
+
wrapper whose _child_ paints the rounded background, the layer inherits the wrapper's radius (very
|
|
1099
|
+
often `0`) and the wash squares off at the corners.
|
|
1100
|
+
|
|
1101
|
+
Tokens: `--gog-ripple-color` (`currentColor`, so the wash reads as the surface's own foreground on
|
|
1102
|
+
a filled surface and a ghost one alike), `--gog-ripple-opacity`, `--gog-ripple-enter-duration`,
|
|
1103
|
+
`--gog-ripple-exit-duration`, `--gog-ripple-easing`. All five are ordinary inherited custom
|
|
1104
|
+
properties, so setting one anywhere above the host is the per-instance override.
|
|
1105
|
+
|
|
1106
|
+
#### Turning the ripple on for the library's own components
|
|
1107
|
+
|
|
1108
|
+
You do **not** add `gogRipple` to a `gog-*` component: each one already owns the element that
|
|
1109
|
+
paints its surface, so it wires its own. What you do is switch it on, once:
|
|
1110
|
+
|
|
1111
|
+
```ts
|
|
1112
|
+
provideGogConfig({ ripple: { enabled: true } });
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
That covers `gog-button`, `[gogButton]`, `gog-button-toggle-group`, `gog-chip`, `gog-tabs`
|
|
1116
|
+
headers, `gog-accordion` headers, `gogCollapsibleTrigger`, `gogMenuItem`, and the options inside
|
|
1117
|
+
`gog-select` / `gog-multiselect` / `gog-autocomplete`. `gog-paginator` follows because its page
|
|
1118
|
+
buttons are `gog-button`s.
|
|
1119
|
+
|
|
1120
|
+
**Off by default**, so adding the ripple to the library changed the look of nothing. Every one of
|
|
1121
|
+
those takes a `ripple` input that beats the config in both directions: `[ripple]="false"` opts one
|
|
1122
|
+
control out of an app-wide on, `[ripple]="true"` opts one in without switching the app over.
|
|
1123
|
+
|
|
1124
|
+
Not covered, and deliberately: `gog-table` rows and `gogCardLink`. A row and a card are hundreds
|
|
1125
|
+
of pixels wide, so the wave has to travel the whole surface and reads as a flash rather than as
|
|
1126
|
+
feedback at the point you pressed — and a table renders one directive per row, with no
|
|
1127
|
+
virtualization in this library yet. Put `gogRipple` on them yourself if you disagree.
|
|
1128
|
+
|
|
1129
|
+
A chip that is not `clickable`, or is `disabled`, never ripples whatever the config says: a label
|
|
1130
|
+
answering a press is a promise it cannot keep.
|
|
1131
|
+
|
|
1003
1132
|
#### `gogTooltip` — directive, not a component
|
|
1004
1133
|
|
|
1005
1134
|
Drop on any element — a `gog-*` component's host tag or a plain native one.
|
|
@@ -1029,6 +1158,7 @@ Drop on any element — a `gog-*` component's host tag or a plain native one.
|
|
|
1029
1158
|
| `skeletonCount` | `number` | `3` — rows shown while `loading` and `items` is still empty |
|
|
1030
1159
|
| `showChevron` | `boolean` | `true` |
|
|
1031
1160
|
| `headingLevel` | `2\|3\|4\|5\|6 \| undefined` | `undefined` — wraps headers in `role="heading"` when set |
|
|
1161
|
+
| `ripple` | `boolean \| undefined` | `false`; via `GOG_CONFIG.ripple.enabled` |
|
|
1032
1162
|
|
|
1033
1163
|
Model: `openIds: ReadonlySet<string | number>`. Output: `gogToggle: { item, open }`.
|
|
1034
1164
|
|
|
@@ -1070,6 +1200,10 @@ ARIA wiring, because the browser already handles focus and keys. On anything els
|
|
|
1070
1200
|
announces is one a keyboard can actually reach. If you set `role` or `tabindex` yourself, the
|
|
1071
1201
|
directive leaves both alone: you have said what the element is.
|
|
1072
1202
|
|
|
1203
|
+
`gogCollapsibleTrigger` takes a **`ripple`** input of its own (`boolean | undefined`, `false`, via
|
|
1204
|
+
`GOG_CONFIG.ripple.enabled`) — the trigger is your element, but the directive owns the ripple so
|
|
1205
|
+
you do not have to add `gogRipple` beside it.
|
|
1206
|
+
|
|
1073
1207
|
An open panel is as tall as its content — `--gog-collapsible-max-height` defaults to
|
|
1074
1208
|
`max-content`. Set it to a length on an instance to cap one deliberately; the panel is
|
|
1075
1209
|
`overflow: hidden`, so a cap **clips** rather than scrolls. (Before 21.4.4 that default was
|
|
@@ -1085,6 +1219,7 @@ An open panel is as tall as its content — `--gog-collapsible-max-height` defau
|
|
|
1085
1219
|
| `fullWidth`, `ariaLabel` | | `false`, `''` |
|
|
1086
1220
|
| `scrollActiveIntoView` | `boolean` | `true` |
|
|
1087
1221
|
| `showScrollTrack` | `boolean \| undefined` | follows `scrollActiveIntoView` (hidden when it's on) |
|
|
1222
|
+
| `ripple` | `boolean \| undefined` | `false`; via `GOG_CONFIG.ripple.enabled` |
|
|
1088
1223
|
|
|
1089
1224
|
Model: `activeIndex: number`. Output: `gogTabChange: number`.
|
|
1090
1225
|
|
|
@@ -1108,6 +1243,94 @@ hidden via `[hidden]` while inactive — preserves scroll/input state).
|
|
|
1108
1243
|
</gog-tabs>
|
|
1109
1244
|
```
|
|
1110
1245
|
|
|
1246
|
+
#### `gog-card` + `gogCardHeader` / `gogCardMedia` / `gogCardFooter` / `gogCardLink`
|
|
1247
|
+
|
|
1248
|
+
A surface for one self-contained thing — a product tile, a summary, a search result.
|
|
1249
|
+
|
|
1250
|
+
| Input | Type | Default |
|
|
1251
|
+
| --------------- | -------------------------------------------------------- | --------------------------------------- |
|
|
1252
|
+
| `variant` | `GogSurfaceVariant` (`'outlined'\|'elevated'\|'filled'`) | `'outlined'` |
|
|
1253
|
+
| `size` | `GogSize` | `'md'` — drives padding and the row gap |
|
|
1254
|
+
| `disabled` | `boolean` (bare attribute works) | `false` |
|
|
1255
|
+
| `loading` | `boolean` (bare attribute works) | `false` |
|
|
1256
|
+
| `skeletonLines` | `number` | `2` — body lines shown while `loading` |
|
|
1257
|
+
|
|
1258
|
+
No outputs. Slots, all **attribute** directives on your own elements (not `ng-template`):
|
|
1259
|
+
`gogCardHeader`, `gogCardMedia`, `gogCardFooter`, `gogCardLink`. Layout order is fixed by the
|
|
1260
|
+
component — media, heading, body (the default slot), footer — not by the order you write them.
|
|
1261
|
+
|
|
1262
|
+
```html
|
|
1263
|
+
<gog-card>
|
|
1264
|
+
<img gogCardMedia [src]="person.photo" alt="" />
|
|
1265
|
+
<h3 gogCardHeader><a gogCardLink [routerLink]="['/people', person.id]">{{ person.name }}</a></h3>
|
|
1266
|
+
<p>{{ person.role }}</p>
|
|
1267
|
+
<div gogCardFooter>
|
|
1268
|
+
<gog-button size="xsm" (gogClick)="shortlist(person)">Shortlist</gog-button>
|
|
1269
|
+
</div>
|
|
1270
|
+
</gog-card>
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
- **`gogCardHeader` names the card.** The card reads that element's `id` (minting one if it has
|
|
1274
|
+
none) and points its own `aria-labelledby` at it, with `role="group"`. A card with no header
|
|
1275
|
+
gets neither — an unnamed group is noise, not structure. The heading level is yours; the visual
|
|
1276
|
+
size comes from `--gog-card-heading-font-size` regardless of it.
|
|
1277
|
+
- **There is no `interactive` input, and no `gogClick` output.** A card becomes interactive by
|
|
1278
|
+
_containing_ a `gogCardLink`, which stretches that link's hit area over the whole surface. The
|
|
1279
|
+
link stays yours: `routerLink`, `href`, `target`, middle-click, "open in new tab" and Enter all
|
|
1280
|
+
behave normally, and the focus ring is drawn around the card. `gogCardLink` only applies to
|
|
1281
|
+
`<a>` and `<button>` — on a `<div>` it does nothing, deliberately.
|
|
1282
|
+
- **Other controls inside an interactive card still get their own clicks.** A footer button, a
|
|
1283
|
+
checkbox, a second link: each sits above the stretched hit area automatically.
|
|
1284
|
+
- Two costs of the pattern, inherent to it: text in the card cannot be selected by dragging, and
|
|
1285
|
+
a second link is reachable by keyboard but not by clicking the surface around it.
|
|
1286
|
+
- **`loading`** replaces the content with a title bar plus `skeletonLines` text lines and sets
|
|
1287
|
+
`aria-busy`; **`disabled`** dims the card, sets `aria-disabled`, and takes the card link out of
|
|
1288
|
+
the tab order. Both make the link non-clickable. For a _refresh_ of a card that already has
|
|
1289
|
+
content, project a `gog-spinner-overlay` instead — `loading` is the first-paint treatment.
|
|
1290
|
+
- `gogCardMedia` runs full-bleed to the card's edges, and rounds into its top corners when it is
|
|
1291
|
+
the first element in the card.
|
|
1292
|
+
|
|
1293
|
+
#### `gog-panel` + `gogPanelHeader` / `gogPanelFooter`
|
|
1294
|
+
|
|
1295
|
+
A titled region of a page — a settings section, a dashboard area, a form group.
|
|
1296
|
+
|
|
1297
|
+
| Input | Type | Default |
|
|
1298
|
+
| --------------- | -------------------------------- | ------------ |
|
|
1299
|
+
| `variant` | `GogSurfaceVariant` | `'elevated'` |
|
|
1300
|
+
| `size` | `GogSize` | `'lg'` |
|
|
1301
|
+
| `collapsible` | `boolean` (bare attribute works) | `false` |
|
|
1302
|
+
| `disabled` | `boolean` (bare attribute works) | `false` |
|
|
1303
|
+
| `loading` | `boolean` (bare attribute works) | `false` |
|
|
1304
|
+
| `skeletonLines` | `number` | `3` |
|
|
1305
|
+
|
|
1306
|
+
Model: `open: boolean` (default `true`, ignored while `collapsible` is off). No outputs beyond
|
|
1307
|
+
`openChange`. Slots: `gogPanelHeader`, `gogPanelFooter` — attribute directives on your elements.
|
|
1308
|
+
|
|
1309
|
+
```html
|
|
1310
|
+
<gog-panel [collapsible]="true" [(open)]="notificationsOpen">
|
|
1311
|
+
<h2 gogPanelHeader>Notifications</h2>
|
|
1312
|
+
<gog-checkbox label="Email digest" [(checked)]="emailDigest" />
|
|
1313
|
+
<div gogPanelFooter><gog-button size="xsm">Save</gog-button></div>
|
|
1314
|
+
</gog-panel>
|
|
1315
|
+
```
|
|
1316
|
+
|
|
1317
|
+
- **It is a landmark.** With a `gogPanelHeader` it renders `role="region"` named by that heading —
|
|
1318
|
+
which is why the panel gets one and `gog-card` gets `role="group"`: a handful of named regions
|
|
1319
|
+
is how a page is navigated, a landmark per card would bury that list.
|
|
1320
|
+
- **Collapsing composes `gog-collapsible`**, so the state, the id wiring and the animation are the
|
|
1321
|
+
library's existing ones. The heading stays a heading: the toggle is a separate `<button>` named
|
|
1322
|
+
by it through `aria-labelledby`, with its hit area stretched across the header row so clicking
|
|
1323
|
+
the title works for the pointer. Without a header the toggle falls back to
|
|
1324
|
+
`GOG_CONFIG.labels.togglePanel` (default `'Toggle section'`).
|
|
1325
|
+
- **A non-collapsible panel does not clip.** It undoes the collapse geometry it inherits,
|
|
1326
|
+
`overflow` included, so a dropdown or menu opened inside it escapes the panel's box. A
|
|
1327
|
+
_collapsible_ one does clip while animating, exactly like `gog-collapsible` — prefer
|
|
1328
|
+
`[appendToBody]` for an overlay inside one.
|
|
1329
|
+
- **`loading` keeps the heading and the footer** and replaces only the body: a page section is
|
|
1330
|
+
titled before its content arrives, and blanking the title would move the layout twice.
|
|
1331
|
+
- **The surface is never itself a link** — there is no `gogPanelLink`. Controls live inside a
|
|
1332
|
+
panel, and a region that is a link cannot hold them. Use `gog-card` for that.
|
|
1333
|
+
|
|
1111
1334
|
#### `gog-paginator`
|
|
1112
1335
|
|
|
1113
1336
|
| Input | Type | Default |
|
|
@@ -1198,7 +1421,7 @@ rather than a hard split, so those can usually go.
|
|
|
1198
1421
|
|
|
1199
1422
|
**`stickyHeader` needs `maxHeight`** (both since 21.6.0 for the pairing). A sticky element
|
|
1200
1423
|
resolves against its nearest scroll container, and the table wraps itself in a `gog-scroll`;
|
|
1201
|
-
once that scroller moves on either axis it is a scroll container on
|
|
1424
|
+
once that scroller moves on either axis it is a scroll container on _both_, because CSS coerces
|
|
1202
1425
|
`overflow-y: visible` to `auto` beside a scrolling `overflow-x` (and `clip` to `hidden`). So the
|
|
1203
1426
|
header can only ever stick to something inside the table — and without `maxHeight` that viewport
|
|
1204
1427
|
is exactly as tall as its content and never scrolls, so there is nothing to stick to.
|
|
@@ -1386,6 +1609,10 @@ trigger's measured rect, so a menu inside `gog-scroll`, `gog-table` or any `over
|
|
|
1386
1609
|
ancestor is not clipped and needs no configuration. It also takes the `--gog-dropdown-z` its
|
|
1387
1610
|
trigger inherits, so a menu opened inside a `gog-dialog` stacks above the dialog.
|
|
1388
1611
|
|
|
1612
|
+
`gogMenuItem` takes a **`ripple`** input (`boolean | undefined`, `false`, via
|
|
1613
|
+
`GOG_CONFIG.ripple.enabled`). The item is your own `<button>`, but the directive owns the ripple,
|
|
1614
|
+
so there is no `gogRipple` to add.
|
|
1615
|
+
|
|
1389
1616
|
Output: `gogClosed` — fires after every close, whatever caused it.
|
|
1390
1617
|
|
|
1391
1618
|
Public methods, for driving it yourself: `open(trigger, 'first' | 'last')`, `close(restoreFocus?)`,
|
|
@@ -1463,17 +1690,33 @@ Everything the package currently deprecates, as data:
|
|
|
1463
1690
|
```ts
|
|
1464
1691
|
import { GOG_DEPRECATIONS, type GogDeprecation } from '@guildofgleks/ui';
|
|
1465
1692
|
|
|
1466
|
-
GOG_DEPRECATIONS
|
|
1467
|
-
// { kind: 'token', name: '--gog-btn-bg', replacement: '--gog-button-bg',
|
|
1468
|
-
// since: '21.5.0', sinceDate: '2026-08-19', removedIn: '21.7.0' }
|
|
1693
|
+
GOG_DEPRECATIONS; // []
|
|
1469
1694
|
```
|
|
1470
1695
|
|
|
1471
1696
|
`kind` is `'symbol'` for an export or input and `'token'` for a `--gog-*` custom property. The
|
|
1472
1697
|
list is generated from the library's source — tags for symbols, stylesheets for tokens — so it
|
|
1473
1698
|
matches what actually still resolves in the version you installed.
|
|
1474
1699
|
|
|
1475
|
-
**
|
|
1476
|
-
|
|
1700
|
+
**As of 21.7.0 the list is empty on both halves.** Nothing in the TypeScript API is deprecated, and
|
|
1701
|
+
the three abbreviated token prefixes that used to fill the token half are gone rather than
|
|
1702
|
+
deprecated — see the removal table below. An empty list here means exactly that: nothing to
|
|
1703
|
+
migrate away from right now.
|
|
1704
|
+
|
|
1705
|
+
## Removed in 21.7.0
|
|
1706
|
+
|
|
1707
|
+
**Nothing in this table exists any more.** Three CSS custom-property prefixes, abbreviations of a
|
|
1708
|
+
component's own name, are gone — each was honoured only as a fallback the spelled-out token wrapped
|
|
1709
|
+
(`--gog-button-x: var(--gog-btn-x, value)`), never declared on its own.
|
|
1710
|
+
|
|
1711
|
+
| Removed | Replacement |
|
|
1712
|
+
| ----------------- | ----------------------------- |
|
|
1713
|
+
| `--gog-btn-*` | `--gog-button-*` |
|
|
1714
|
+
| `--gog-ms-*` | `--gog-multiselect-*` |
|
|
1715
|
+
| `--gog-confirm-*` | `--gog-confirmation-dialog-*` |
|
|
1716
|
+
|
|
1717
|
+
A consumer's CSS that still sets one of the left-hand names doesn't fail their build — an
|
|
1718
|
+
unresolved `var()` just stops matching anything, silently. If a themed surface stopped picking up
|
|
1719
|
+
an override after upgrading to 21.7.0, this table is the first thing to check.
|
|
1477
1720
|
|
|
1478
1721
|
## Removed in 21.5.0
|
|
1479
1722
|
|
|
@@ -1508,6 +1751,7 @@ Shared enum-like types (`import type { ... } from '@guildofgleks/ui'`):
|
|
|
1508
1751
|
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
1509
1752
|
| `GogSize` | `'xsm' \| 'sm' \| 'md' \| 'lg' \| 'slg'` |
|
|
1510
1753
|
| `GogVariant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` |
|
|
1754
|
+
| `GogSurfaceVariant` | `'outlined' \| 'elevated' \| 'filled'` — `gog-card` and `gog-panel` |
|
|
1511
1755
|
| `GogTagVariant` | `'success' \| 'danger' \| 'warning' \| 'info'` |
|
|
1512
1756
|
| `GogOrientation` | `'horizontal' \| 'vertical'` |
|
|
1513
1757
|
| `GogTagShape` | `'rounded' \| 'pill'` |
|