@guildofgleks/ui 21.11.0 → 21.13.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.
@@ -0,0 +1,2000 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { Signal, InjectionToken, Type, Provider, DoCheck, TemplateRef, ModelSignal, ElementRef, ApplicationRef } from '@angular/core';
3
+ import { NgControl, ControlValueAccessor } from '@angular/forms';
4
+ import * as _guildofgleks_ui_shared from '@guildofgleks/ui/shared';
5
+
6
+ interface GogCheckableControlSizeConfig {
7
+ readonly boxSize: string;
8
+ readonly labelSize: string;
9
+ readonly indicatorSize: string;
10
+ }
11
+ declare const GOG_CHECKABLE_CONTROL_PADDING = "var(--gog-control-checkbox-padding, 8px)";
12
+ declare const GOG_CHECKABLE_CONTROL_SIZE_MAP: {
13
+ readonly xsm: {
14
+ readonly boxSize: "var(--gog-control-checkbox-box-size-xsm, 12px)";
15
+ readonly labelSize: "var(--gog-control-checkbox-label-size-xsm, 0.6875rem)";
16
+ readonly indicatorSize: "var(--gog-control-checkbox-icon-size-xsm, 10px)";
17
+ };
18
+ readonly sm: {
19
+ readonly boxSize: "var(--gog-control-checkbox-box-size-sm, 18px)";
20
+ readonly labelSize: "var(--gog-control-checkbox-label-size-sm, 0.8125rem)";
21
+ readonly indicatorSize: "var(--gog-control-checkbox-icon-size-sm, 12px)";
22
+ };
23
+ readonly md: {
24
+ readonly boxSize: "var(--gog-control-checkbox-box-size-md, 24px)";
25
+ readonly labelSize: "var(--gog-control-checkbox-label-size-md, 0.9375rem)";
26
+ readonly indicatorSize: "var(--gog-control-checkbox-icon-size-md, 14px)";
27
+ };
28
+ readonly lg: {
29
+ readonly boxSize: "var(--gog-control-checkbox-box-size-lg, 32px)";
30
+ readonly labelSize: "var(--gog-control-checkbox-label-size-lg, 1.0625rem)";
31
+ readonly indicatorSize: "var(--gog-control-checkbox-icon-size-lg, 18px)";
32
+ };
33
+ readonly slg: {
34
+ readonly boxSize: "var(--gog-control-checkbox-box-size-slg, 40px)";
35
+ readonly labelSize: "var(--gog-control-checkbox-label-size-slg, 1.1875rem)";
36
+ readonly indicatorSize: "var(--gog-control-checkbox-icon-size-slg, 22px)";
37
+ };
38
+ };
39
+
40
+ type GogSize = 'xsm' | 'sm' | 'md' | 'lg' | 'slg';
41
+ type GogVariant = 'primary' | 'secondary' | 'outline' | 'ghost';
42
+ /**
43
+ * The `aria-haspopup` values that make sense on a button, matching the ARIA 1.2 enumeration.
44
+ * `true` is a synonym for `'menu'` in the spec; prefer the specific value, since a screen
45
+ * reader announces it ("has menu", "has dialog").
46
+ */
47
+ type GogAriaHasPopup = boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';
48
+ /**
49
+ * How a surface paints itself, shared by `gog-card` and `gog-panel` so the two agree:
50
+ * - `'outlined'` — a border, no shadow. The quietest, and right for a grid of many.
51
+ * - `'elevated'` — the shared surface shadow (`--gog-panel-shadow`), no border.
52
+ * - `'filled'` — a tinted background, neither border nor shadow.
53
+ */
54
+ type GogSurfaceVariant = 'outlined' | 'elevated' | 'filled';
55
+ /**
56
+ * Which way a component lays its children out. Shared rather than re-declared per component:
57
+ * `gog-radio-group`, `gog-slider`, `gog-divider`, `gog-tabs` and `gog-button-toggle-group` all
58
+ * mean the same thing by it, and `roving-focus.ts` picks its arrow pair from this.
59
+ */
60
+ type GogOrientation = 'horizontal' | 'vertical';
61
+ type GogSpinnerVariant = 'runic' | 'ring' | 'custom';
62
+ type GogTagVariant = 'success' | 'danger' | 'warning' | 'info';
63
+ type GogTagShape = 'rounded' | 'pill';
64
+ type GogSkeletonShape = 'text' | 'circle' | 'rect';
65
+ type GogSkeletonAnimation = 'pulse' | 'wave' | 'none';
66
+ type GogPaginatorRangeMode = 'window' | 'ellipsis';
67
+ type GogSliderOrientation = GogOrientation;
68
+ /** A `gog-slider`'s value pair when `range` is on. `start` is always kept ≤ `end`. */
69
+ interface GogSliderRange {
70
+ start: number;
71
+ end: number;
72
+ }
73
+ type GogScrollAxis = 'vertical' | 'horizontal' | 'both';
74
+ type GogScrollSize = 'normal' | 'thin';
75
+ /**
76
+ * Mirrors the CSS `overscroll-behavior` value space directly:
77
+ * - `'auto'` — scrolling past this instance's edge chains to the next scrollable ancestor
78
+ * (a page, a dialog body, another gog-scroll), the same as an un-customized native
79
+ * `overflow: auto` div. The default — matches what most embedded content expects.
80
+ * - `'contain'` — scrolling stops dead at this instance's edge; nothing behind it moves.
81
+ * Suited to overlay-style panels (a dropdown, a modal) where scrolling past the end
82
+ * shouldn't also scroll whatever is behind them.
83
+ * - `'none'` — like `'contain'`, and additionally suppresses the platform's own overscroll
84
+ * affordances (rubber-banding, pull-to-refresh) for this instance.
85
+ */
86
+ type GogScrollOverscrollBehavior = 'auto' | 'contain' | 'none';
87
+ /**
88
+ * Which side of the trigger the tooltip bubble renders on. `'auto'` (the default) picks
89
+ * whichever of the four sides has room for the bubble, preferring top, then bottom, then
90
+ * right, then left — see `resolveTooltipPlacement` in `tooltip-position.ts`. An explicit
91
+ * side still flips to its opposite if the requested side has no room but the opposite does.
92
+ */
93
+ type GogTooltipPosition = 'auto' | 'top' | 'bottom' | 'left' | 'right';
94
+ /**
95
+ * Where a field's label sits once it "floats" out of its resting position (overlapping the
96
+ * field like a placeholder) on focus or once the field has content. `'none'` (the default)
97
+ * keeps today's static label-above-the-field layout — nothing floats.
98
+ * - `'in'` — floats up but stays fully inside the field's border.
99
+ * - `'on'` — floats up until vertically centered on the top border line.
100
+ * - `'over'` — floats all the way above the field, outside the border.
101
+ */
102
+ type GogFloatLabelVariant = 'none' | 'in' | 'on' | 'over';
103
+ /**
104
+ * Which end of a dropdown panel the search box sticks to. Matches `gog-multiselect`'s
105
+ * `controlsPosition` vocabulary — the same idea applied to its select-all row.
106
+ */
107
+ type GogDropdownFilterPosition = 'top' | 'bottom';
108
+ /** How `gog-divider` paints its rule. */
109
+ type GogDividerVariant = 'solid' | 'dashed' | 'dotted';
110
+ /**
111
+ * Which corner of its host a `gogBadge` sits on. Named by block/inline edge rather than
112
+ * left/right so it follows the writing direction in an RTL layout.
113
+ */
114
+ type GogBadgePosition = 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start';
115
+ /**
116
+ * - `'determinate'` — the bar reflects `value`.
117
+ * - `'indeterminate'` — work of unknown length; the bar animates and reports no value to
118
+ * assistive tech, which is what marks it indeterminate.
119
+ * - `'buffer'` — `value` plus a second, lighter `buffer` level ahead of it (streaming/preload).
120
+ */
121
+ type GogProgressbarMode = 'determinate' | 'indeterminate' | 'buffer';
122
+ /**
123
+ * `gog-progressbar`'s colour. Wider than `GogTagVariant` by one: progress is usually just
124
+ * "the app is working", which is the accent colour rather than any of the four status hues —
125
+ * so `'accent'` is the default and the status names are the exception.
126
+ */
127
+ type GogProgressbarVariant = GogSeverity;
128
+ /**
129
+ * What an action or a reading *means*, as opposed to how loudly it is drawn. `'accent'` is the
130
+ * absence of a claim — the library's own colour, and the default everywhere this appears — and
131
+ * the four status names are the exception, so nothing has to opt out of a severity it does not
132
+ * have.
133
+ *
134
+ * Deliberately orthogonal to `GogVariant` on `gog-button`: a destructive action can be filled,
135
+ * outlined or a ghost and is destructive in all three, so `severity` says what it does and
136
+ * `variant` says only how much room it takes up. Shared rather than re-declared per component —
137
+ * `gog-progressbar` had this exact union first, under its own name, which is kept as an alias.
138
+ */
139
+ type GogSeverity = 'accent' | 'success' | 'danger' | 'warning' | 'info';
140
+ /**
141
+ * How `gog-alert` announces itself, and it is a decision the component cannot make for you.
142
+ *
143
+ * - `'assertive'` — interrupts whatever a screen reader is saying. For a message that *just
144
+ * happened* and changes what the reader should do: a failed save, a rejected payment.
145
+ * - `'polite'` — waits for a pause. The right answer for most appearing messages.
146
+ * - `'off'` — announces nothing. **The right answer for a message that was already on the page
147
+ * when it loaded**, which is otherwise an interruption about something nobody asked about yet.
148
+ *
149
+ * The choice follows from *why the message appeared*, not from how bad it is — the same red box
150
+ * earns an interruption on submit and does not on page load. Nothing in `@angular/core` lets a
151
+ * component tell those apart: `ApplicationRef` exposes no stability member a component can read
152
+ * synchronously at construction, and `afterNextRender` reports the component's *own* first render
153
+ * rather than the application's. Measured before being decided; see `docs/alert.md` §1.
154
+ */
155
+ type GogAlertLive = 'assertive' | 'polite' | 'off';
156
+ /**
157
+ * - `'joined'` — one segmented control, buttons sharing borders (Material's look).
158
+ * - `'separated'` — discrete buttons with a gap between them.
159
+ */
160
+ type GogButtonToggleAppearance = 'joined' | 'separated';
161
+ /** How the tab headers distribute along the tablist. `'stretch'` makes them share the width. */
162
+ type GogTabsAlign = 'start' | 'center' | 'end' | 'stretch';
163
+ /** Whether `gog-datepicker` picks one day or a start/end pair. */
164
+ type GogDateSelectionMode = 'single' | 'range';
165
+ /** Clock convention for `gog-datepicker`'s time section. */
166
+ type GogHourFormat = '12' | '24';
167
+ /** Matches the native CSS `resize` value space, applied to `gog-textarea`'s field. */
168
+ type GogTextareaResize = 'vertical' | 'horizontal' | 'both' | 'none';
169
+ /**
170
+ * The `type`s `gog-inputfield` renders as a single-line text-entry field.
171
+ *
172
+ * Deliberately not the whole native list: `checkbox`, `radio`, `range`, `file`, `color`,
173
+ * `submit`, `hidden` and friends are different controls with different markup and different
174
+ * accessibility contracts — the library ships `gog-checkbox`, `gog-radio-group`, `gog-slider`
175
+ * and `gog-button` for those rather than making one component shape-shift.
176
+ */
177
+ type GogInputType = 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url' | 'date' | 'time' | 'datetime-local';
178
+ /**
179
+ * Mirrors the native `inputmode` attribute — the hint that decides which on-screen keyboard a
180
+ * touch device brings up. Worth setting whenever `type` alone doesn't imply it: a postcode or a
181
+ * card number is `type="text"` (no browser validation wanted) but `inputmode="numeric"`.
182
+ */
183
+ type GogInputMode = 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
184
+ /**
185
+ * Which corner a toast stack occupies.
186
+ *
187
+ * Here rather than beside `ToastService`, where it was declared until 2026-09-12, for two reasons
188
+ * that turned out to be the same one: `gleks-ui-library.instructions.md` puts public types in this
189
+ * file, and `shared/config.ts` needs it — so declaring it in a service made `shared` depend on
190
+ * `services`, which depends on `shared`. A cycle nothing minded while the package is one flat
191
+ * bundle, and one that a secondary entry point cannot express at all.
192
+ */
193
+ type ToastPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
194
+
195
+ /**
196
+ * `'manual'` (default): the field shows `errorMessage` for as long as it is non-empty — the
197
+ * consumer decides when to clear it, e.g.
198
+ * `errorMessage="control.invalid && control.touched ? 'Required' : ''"`.
199
+ *
200
+ * `'auto'`: shown once the attached form control has been touched and is invalid — the
201
+ * consumer only supplies the message text, not the timing. Requires a
202
+ * `[formControl]` / `formControlName` on the element; without one this falls back to
203
+ * `'manual'`, since there is no control state to key off.
204
+ */
205
+ type GogErrorDisplay = 'auto' | 'manual';
206
+ /**
207
+ * Shared error-visibility state for the library's form controls. A plain class rather than
208
+ * a base class or directive so it drops into components that can't share a base class
209
+ * (`gog-inputfield`, `gog-slider`) as well as ones that already do (`GogDropdownBase`).
210
+ * Each consumer owns its own instance and wires `check()` into its own `ngDoCheck`.
211
+ */
212
+ declare class GogErrorState {
213
+ private readonly errorMessage;
214
+ private readonly errorDisplay;
215
+ private readonly ngControl;
216
+ private readonly controlTouched;
217
+ private readonly controlInvalid;
218
+ constructor(errorMessage: Signal<string>, errorDisplay: Signal<GogErrorDisplay>, ngControl: NgControl | null);
219
+ readonly hasError: Signal<boolean>;
220
+ readonly visibleError: Signal<string>;
221
+ /**
222
+ * `NgControl` exposes validity as plain properties, and has no change notification for
223
+ * `touched` at all — `statusChanges` fires only on validity transitions, never on
224
+ * `markAsTouched()` — while its `control` does not exist yet during construction, so
225
+ * subscribing early would miss it regardless. Mirroring on each check sidesteps both;
226
+ * re-setting a signal to its current value notifies nothing, so the common case costs two
227
+ * comparisons.
228
+ */
229
+ check(): void;
230
+ }
231
+
232
+ type GogDropdownDirection = 'auto' | 'up' | 'down';
233
+ interface GogDropdownTriggerRect {
234
+ top: number;
235
+ bottom: number;
236
+ left: number;
237
+ width: number;
238
+ }
239
+ interface GogDropdownPlacement {
240
+ direction: 'up' | 'down';
241
+ top: number;
242
+ left: number;
243
+ width: number;
244
+ maxHeight: number;
245
+ }
246
+ declare function resolveDropdownDirection(direction: GogDropdownDirection, triggerRect: GogDropdownTriggerRect, panelHeight: number, viewportHeight: number, gap?: number, viewportPadding?: number): 'up' | 'down';
247
+ declare function resolveDropdownPlacement(direction: GogDropdownDirection, triggerRect: GogDropdownTriggerRect, panelHeight: number, viewportHeight: number, gap?: number, viewportPadding?: number): GogDropdownPlacement;
248
+ /**
249
+ * Resolves a CSS length to pixels for the placement math. Only `px`, `%` and `vh` can be
250
+ * resolved without laying out the DOM — `%` and `vh` are taken relative to the viewport
251
+ * height, which is exactly what a `position: fixed` panel's height resolves against in CSS.
252
+ * Any other unit (`rem`, `em`, `auto`, a bare number, …) returns null: the caller falls back
253
+ * to its own estimate for the up/down decision, while the original string is still written
254
+ * to the panel's `style.max-height` as-is — only the direction heuristic loses precision.
255
+ */
256
+ declare function resolveCssLengthPx(value: string, viewportHeight: number): number | null;
257
+
258
+ /**
259
+ * App-wide defaults for the handful of component inputs where that actually makes sense —
260
+ * timing/behavior knobs a whole app typically wants to set once (a house style for how long
261
+ * scrollbars stay visible, how aggressively buttons debounce clicks), not visual ones.
262
+ * Visual defaults (colors, radii, animation *durations expressed in CSS*) already have a
263
+ * global mechanism: the `--gog-*` custom properties in `styles/theme.css`. This is only for
264
+ * inputs that can't be a CSS token because a component reads them in TypeScript (a
265
+ * `setTimeout` delay, an RxJS `timer` duration) — see `styling.instructions.md` and
266
+ * `gleks-ui-library.instructions.md`'s "Global configuration" section for the line between
267
+ * the two and for how to add a new field here when a component needs one.
268
+ *
269
+ * Every field is optional at every level: set only the ones you want to change from the
270
+ * component's own built-in default. An instance's own input, when set, always wins over
271
+ * this — this only fills in what the instance didn't specify itself.
272
+ */
273
+ interface GogGlobalConfig {
274
+ /**
275
+ * The loading indicator, app-wide.
276
+ *
277
+ * `component` is the one config key that carries markup rather than a value, and it is here
278
+ * because of what it removes: a house spinner otherwise has to be passed into every control
279
+ * that can show one, and cannot be passed into the ones that render their own. Set it once and
280
+ * **every** spinner the library draws is yours — `gog-spinner`, `gog-spinner-overlay`, and the
281
+ * ones inside `gog-button`, `gog-autocomplete` and `gog-table`'s loading states, which have no
282
+ * input to reach. It is rendered through `NgComponentOutlet` inside the size wrapper, so it
283
+ * keeps the sizing, the overlay behaviour, the `role="status"` and the accessible name; only
284
+ * the visual is yours.
285
+ *
286
+ * Precedence is the library's usual one, with a wrinkle worth stating: an instance's own
287
+ * `variant` wins over both keys here, `component` wins over `variant`, and the built-in
288
+ * `runic` is the fallback. So `<gog-spinner variant="ring">` still gets a ring in an app that
289
+ * has set a component — an instance asking for something specific is not overridden by a
290
+ * default.
291
+ *
292
+ * Applies to: `gog-spinner`, `gog-spinner-overlay`, and the spinners inside `gog-button`,
293
+ * `gog-autocomplete` and `gog-table`. Two of those were wrong until 21.10.0 and are worth the
294
+ * warning: `gog-table` was never listed although it always honoured the key, and
295
+ * `gog-spinner-overlay` was listed although it did not — it forwards its own `variant` down,
296
+ * and that input defaulted to `'runic'`, which the spinner inside correctly read as an
297
+ * instance overruling a default. Neither shows up in a grep for `globalConfig.spinner`,
298
+ * because neither reads the config: they render a `gog-spinner` that does.
299
+ */
300
+ spinner?: {
301
+ component?: Type<unknown>;
302
+ variant?: GogSpinnerVariant;
303
+ };
304
+ scroll?: {
305
+ autoHide?: boolean;
306
+ hideDelay?: number;
307
+ size?: GogScrollSize;
308
+ overscrollBehavior?: GogScrollOverscrollBehavior;
309
+ /**
310
+ * Whether the overlay thumb/track ever renders. Scrolling itself is unaffected either way
311
+ * — this is purely the visual affordance. Defaults to `true`.
312
+ */
313
+ showTrack?: boolean;
314
+ /**
315
+ * Turns a vertical wheel into horizontal scrolling on a `gog-scroll` that has nothing to
316
+ * scroll vertically. Defaults to `false`; see the component's `horizontalWheel` input for
317
+ * the conditions it applies under and why it never swallows a gesture at the content's end.
318
+ */
319
+ horizontalWheel?: boolean;
320
+ };
321
+ button?: {
322
+ debounce?: number;
323
+ };
324
+ /**
325
+ * Whether the library's own interactive surfaces show a press ripple: `gog-button`,
326
+ * `[gogButton]`, `gog-button-toggle`, `gog-chip`, `gog-tabs`, `gog-accordion`,
327
+ * `gog-collapsible`, `gog-menu` and the three dropdowns' options. **Off by default**, so the
328
+ * effect is additive and nothing changes appearance until an app asks for it.
329
+ *
330
+ * This is the one visual default that is *not* expressible as a CSS token, which is why it is
331
+ * here at all: `--gog-ripple-opacity: 0` would hide the wash but still pay for the DOM node,
332
+ * the pointer listeners and the animation frames on every press. A real off has to reach the
333
+ * TypeScript.
334
+ *
335
+ * Per-instance: every component listed above takes a `ripple` input that wins over this, so
336
+ * `[ripple]="false"` opts one control out of an app-wide `true` (and `[ripple]="true"` opts one
337
+ * in without switching the app over). The `[gogRipple]` directive on your **own** element is
338
+ * not covered — writing the attribute is already the per-element decision, the same way
339
+ * `[filter]="true"` on one `gog-select` is; `rippleDisabled` turns that one off.
340
+ */
341
+ ripple?: {
342
+ enabled?: boolean;
343
+ };
344
+ tooltip?: {
345
+ showDelay?: number;
346
+ hideDelay?: number;
347
+ position?: GogTooltipPosition;
348
+ };
349
+ /**
350
+ * Applies to `gog-inputfield`, `gog-textarea`, `gog-select`, `gog-multiselect`,
351
+ * `gog-autocomplete` and `gog-datepicker` — every field that can float a label. All six read
352
+ * it through the same `GogFloatLabelState`, three of them via `GogDropdownBase`.
353
+ */
354
+ floatLabel?: {
355
+ variant?: GogFloatLabelVariant;
356
+ /**
357
+ * Whether the field's own `placeholder` reappears once its label has floated out of
358
+ * the way. Defaults to `false` — the placeholder stays hidden the whole time a float
359
+ * label is active, since the resting label already occupies that space.
360
+ */
361
+ showPlaceholder?: boolean;
362
+ };
363
+ /**
364
+ * Defaults for the interactive form controls — the two settings an app otherwise repeats on
365
+ * literally every one of them: a compact app writes `size="sm"` everywhere, and a
366
+ * Reactive-Forms app writes `errorDisplay="auto"` on every field.
367
+ *
368
+ * - `size` applies to `gog-button` and `[gogButton]`, `gog-button-toggle-group`,
369
+ * `gog-checkbox`, `gog-toggle`, `gog-radio-group`, `gog-inputfield`, `gog-textarea`,
370
+ * `gog-select`, `gog-multiselect`, `gog-autocomplete` and `gog-datepicker`. Deliberately
371
+ * **not** to `gog-table`, `gog-accordion` or `gog-paginator` (whose `size` means row/layout
372
+ * density and whose defaults differ), nor to `gog-spinner`, `gog-skeleton`, `gog-tag` or
373
+ * `gog-chip` (sized to fit whatever they sit next to, not to a form's density).
374
+ * - `errorDisplay` applies to every control that renders a validation message:
375
+ * `gog-inputfield`, `gog-textarea`, `gog-select`, `gog-multiselect`, `gog-autocomplete`,
376
+ * `gog-datepicker`, `gog-radio-group` and `gog-slider`.
377
+ *
378
+ * A component's own built-in default still applies when this is unset, so setting `size`
379
+ * here does not flatten the different defaults those excluded components have.
380
+ *
381
+ * **When you add a reader, add it here — and note that "reader" is not the same as "names
382
+ * the field".** These lists were wrong for four keys until 2026-09-02, always in the same
383
+ * direction and for the same reason: `gog-select`, `gog-multiselect` and `gog-autocomplete`
384
+ * resolve `size`/`errorDisplay`/`clearable`/`floatLabel` inside `GogDropdownBase`, and
385
+ * `gog-datepicker` composes the same state classes directly, so none of the four contains the
386
+ * `globalConfig.control?.…` expression that a grep for readers finds. Nor does the resolved
387
+ * value always reach a template by name — `size` arrives as a computed class (`sizeClass`,
388
+ * `panelSizeClass`) and `dropdown.direction` is consumed by placement code, so "is the
389
+ * computed referenced in the component's HTML?" answers *no* for components that genuinely
390
+ * honour the key. Trace the shared state classes, not just the components.
391
+ */
392
+ control?: {
393
+ size?: GogSize;
394
+ errorDisplay?: GogErrorDisplay;
395
+ /**
396
+ * Whether `gog-inputfield`, `gog-textarea`, `gog-select`, `gog-multiselect`,
397
+ * `gog-autocomplete` and `gog-datepicker` offer a clear button — every control that
398
+ * composes `GogClearableState`. The button only ever appears once the control actually has
399
+ * something to clear, so switching this on app-wide adds no permanent chrome.
400
+ *
401
+ * Component defaults are `false`, except `gog-multiselect`, which had a clear button
402
+ * before this input existed and keeps it.
403
+ */
404
+ clearable?: boolean;
405
+ };
406
+ /**
407
+ * Applies per field rather than per component, which is why this is not one sentence:
408
+ *
409
+ * - `appendToBody` and `direction` reach `gog-select`, `gog-multiselect`,
410
+ * `gog-autocomplete` (all three through `GogDropdownBase`) and `gog-datepicker`, which
411
+ * resolves the same pair itself.
412
+ * - `filter` and `filterPosition` reach `gog-select` and `gog-multiselect` only.
413
+ * `gog-autocomplete` inherits both inputs from the same base class and renders no filter
414
+ * box for them — its own text field *is* the filter, so a second search box inside the
415
+ * panel would be a duplicate. Setting these does nothing to an autocomplete.
416
+ */
417
+ dropdown?: {
418
+ /**
419
+ * Whether the panel is rendered into `<body>` instead of inline. Worth setting app-wide
420
+ * for a layout whose dropdowns generally live inside scrollable or overflow-clipped
421
+ * containers, which is the case this exists for.
422
+ */
423
+ appendToBody?: boolean;
424
+ direction?: GogDropdownDirection;
425
+ /** Whether the panel shows a search box. Off by default. */
426
+ filter?: boolean;
427
+ /** Which end of the panel the search box sticks to. `'top'` by default. */
428
+ filterPosition?: GogDropdownFilterPosition;
429
+ /**
430
+ * Whether the option list renders only the rows in view instead of all of them. Reaches
431
+ * `gog-select`. **Off by default**, and deliberately not switched on above some row count:
432
+ * a windowed list and a plain one differ under `Ctrl+F`, under a screen reader's "list all
433
+ * items", and under consumer CSS that targets `:last-child`, so a data-dependent threshold
434
+ * would make behaviour depend on how much data happened to arrive.
435
+ *
436
+ * Worth setting app-wide for an app whose selects are generally fed long lists; a per-field
437
+ * `virtualize` still wins over it.
438
+ */
439
+ virtualize?: boolean;
440
+ };
441
+ /**
442
+ * Applies to `gog-datepicker` and `gog-calendar`. Every field here is something an app sets
443
+ * once rather than per field — a locale and a date format repeated on every date input is
444
+ * exactly the boilerplate this config exists to remove.
445
+ */
446
+ datepicker?: {
447
+ /** BCP-47 tag driving month and weekday names. */
448
+ locale?: string;
449
+ /** 0 = Sunday … 6 = Saturday. Unset, it comes from the locale. */
450
+ firstDayOfWeek?: number;
451
+ /** Display and parse pattern (`dd.MM.yyyy`, `yyyy-MM-dd`, …). */
452
+ format?: string;
453
+ };
454
+ /**
455
+ * Applies to `gog-paginator`, and through it to `gog-table`'s built-in pagination.
456
+ *
457
+ * The page-size select is the one piece of paginator chrome an app decides once — either its
458
+ * tables offer the choice or they don't, and the option list is a house style. Both are still
459
+ * overridable per instance, for the page whose table genuinely needs `5, 10, 20` while the rest
460
+ * of the app uses `20, 50, 100`.
461
+ */
462
+ paginator?: {
463
+ /** Whether the rows-per-page select renders at all. **Off by default.** */
464
+ showPageSizeSelect?: boolean;
465
+ /** The choices it offers. Defaults to `[10, 20, 30, 40, 50]`. */
466
+ pageSizeOptions?: number[];
467
+ };
468
+ /** Applies to `gog-autocomplete`. */
469
+ autocomplete?: {
470
+ /**
471
+ * Milliseconds to wait after the last keystroke before `gogSearch` fires. A whole app
472
+ * usually wants one answer here, tuned to its backend rather than to each field.
473
+ */
474
+ searchDebounce?: number;
475
+ /** How many characters before the panel opens at all. */
476
+ minLength?: number;
477
+ /**
478
+ * Whether focusing the field opens the panel immediately, showing the full option list.
479
+ * Defaults to `true`.
480
+ */
481
+ openOnFocus?: boolean;
482
+ };
483
+ /** Applies to `gog-inputfield`. */
484
+ inputfield?: {
485
+ /**
486
+ * Whether a `type="number"` field shows the library's own spin buttons in place of the
487
+ * browser's native ones. Defaults to `true`.
488
+ */
489
+ showSpinButtons?: boolean;
490
+ };
491
+ /** Applies to `gog-textarea`. */
492
+ textarea?: {
493
+ /**
494
+ * Which direction(s) the field's own drag handle resizes it in — matches the native CSS
495
+ * `resize` value space. Defaults to `'vertical'`.
496
+ */
497
+ resize?: GogTextareaResize;
498
+ };
499
+ toast?: {
500
+ position?: ToastPosition;
501
+ /** How long a non-sticky toast stays up, in ms. */
502
+ duration?: number;
503
+ };
504
+ /**
505
+ * Every fixed, user-visible string the library renders — button text and accessible names for
506
+ * chrome the consumer never writes markup for.
507
+ *
508
+ * These are here rather than as one input per string because they are the definition of a
509
+ * setting an app states once: a Russian-language app relabels "Clear" once, not on all 340
510
+ * fields. Where a per-instance input already exists (`clearAriaLabel`, `todayLabel`, …) it
511
+ * still wins for that one control — the usual instance → config → default order.
512
+ *
513
+ * Deliberately excludes anything that is *content* rather than chrome: `gog-checkbox`'s
514
+ * `ariaLabel`, `gog-button`'s `ariaLabel`, a field's `label` or `placeholder`. Those differ
515
+ * per instance by definition and have no meaningful app-wide value.
516
+ */
517
+ labels?: {
518
+ /** Clear button on `gog-inputfield` / `gog-textarea`. */
519
+ clear?: string;
520
+ /**
521
+ * Clear button on `gog-select` / `gog-multiselect` / `gog-autocomplete`, which clears a
522
+ * selection rather than text.
523
+ */
524
+ clearSelection?: string;
525
+ /** Clear button on `gog-datepicker`. */
526
+ clearDate?: string;
527
+ /** `gog-multiselect`'s select-all / clear-all buttons — visible text, not just a label. */
528
+ selectAll?: string;
529
+ clearAll?: string;
530
+ /** `gog-inputfield`'s number spin buttons. */
531
+ increment?: string;
532
+ decrement?: string;
533
+ /** `gog-inputfield`'s password reveal toggle, in its two states. */
534
+ showPassword?: string;
535
+ hidePassword?: string;
536
+ /** Close buttons on the two service-driven overlays. */
537
+ closeDialog?: string;
538
+ closeToast?: string;
539
+ /**
540
+ * `gog-alert`'s dismiss button. Separate from `closeToast` on purpose: a toast closes
541
+ * something that was going to leave anyway, an alert dismisses a message that would have
542
+ * stayed, and several languages use different verbs for the two.
543
+ */
544
+ closeAlert?: string;
545
+ /** `gog-paginator`'s `<nav>` accessible name and its two step buttons. */
546
+ pagination?: string;
547
+ previousPage?: string;
548
+ nextPage?: string;
549
+ /**
550
+ * `gog-paginator`'s per-page button names ("Go to page 4", "Page 4, current page").
551
+ *
552
+ * A function rather than a string, and the only one in this block: these interpolate the
553
+ * page number, and a template string with a `{0}` placeholder would be a second, weaker
554
+ * formatting language to learn — one that also can't express languages where the number's
555
+ * position or the surrounding grammar depends on its value. The default is
556
+ * `` (page, isCurrent) => isCurrent ? `Page ${page}, current page` : `Go to page ${page}` ``.
557
+ */
558
+ page?: (page: number, isCurrent: boolean) => string;
559
+ /** `gog-datepicker`'s button that opens the calendar panel. */
560
+ openCalendar?: string;
561
+ /**
562
+ * `gog-panel`'s collapse toggle, used **only** when the panel has no `gogPanelHeader` to
563
+ * borrow a name from. A panel with a heading names its toggle after that heading, which is
564
+ * both more useful and per-instance by definition.
565
+ */
566
+ togglePanel?: string;
567
+ /** `gog-paginator`'s rows-per-page select. */
568
+ rowsPerPage?: string;
569
+ /** `gog-table`: the row-count label, its paginator, and the selection checkboxes. */
570
+ total?: string;
571
+ tablePagination?: string;
572
+ selectRow?: string;
573
+ selectAllRows?: string;
574
+ /** `gog-calendar` navigation and shortcuts. */
575
+ today?: string;
576
+ thisMonth?: string;
577
+ previousMonth?: string;
578
+ nextMonth?: string;
579
+ previousYear?: string;
580
+ nextYear?: string;
581
+ /** `gog-calendar`'s time section. */
582
+ hours?: string;
583
+ minutes?: string;
584
+ seconds?: string;
585
+ };
586
+ /**
587
+ * Applies to `ThemeService`. Every field is off/neutral by default, so an app that configures
588
+ * nothing keeps the pre-21.3.2 behaviour: adopt whatever `data-theme` is already on `<html>`,
589
+ * else `'light'`.
590
+ */
591
+ theme?: {
592
+ /**
593
+ * `localStorage` key the chosen theme is written to and read back from. Unset, nothing is
594
+ * persisted and the theme resets on every load.
595
+ */
596
+ storageKey?: string | null;
597
+ /** Theme applied when nothing else decides. `'light'` by default. */
598
+ defaultTheme?: string;
599
+ /**
600
+ * Whether to fall back to the OS `prefers-color-scheme` setting — and to keep following it
601
+ * until the app calls `setTheme`/`toggleTheme`. Off by default: switching this on changes
602
+ * which theme an existing app opens in.
603
+ */
604
+ followSystem?: boolean;
605
+ /** Theme names `toggleTheme()` alternates between, and `followSystem` maps the OS setting to. */
606
+ lightTheme?: string;
607
+ darkTheme?: string;
608
+ };
609
+ }
610
+ /**
611
+ * Resolves to `{}` — every field falls through to its component's own hardcoded default —
612
+ * until a `provideGogConfig(...)` call overrides it somewhere in the injector tree.
613
+ */
614
+ declare const GOG_CONFIG: InjectionToken<GogGlobalConfig>;
615
+ /**
616
+ * Sets app-wide (or subtree-wide, if placed in a route's or component's own `providers`
617
+ * instead of the bootstrap config) defaults for every `@guildofgleks/ui` component that
618
+ * reads `GOG_CONFIG` — one call instead of a separate injection token per setting:
619
+ *
620
+ * ```ts
621
+ * // app.config.ts
622
+ * providers: [
623
+ * provideGogConfig({
624
+ * scroll: { hideDelay: 1000 },
625
+ * button: { debounce: 500 },
626
+ * }),
627
+ * ]
628
+ * ```
629
+ *
630
+ * **Providing this again further down the injector tree layers onto the parent's config
631
+ * rather than replacing it.** A route that only cares about tooltips can say so, and the
632
+ * app-wide `button.debounce` stays in effect inside it:
633
+ *
634
+ * ```ts
635
+ * // a route's providers — button.debounce from app.config.ts still applies here
636
+ * provideGogConfig({ tooltip: { showDelay: 0 } })
637
+ * ```
638
+ *
639
+ * Merging is one level deep, per component key: the nearest provider wins field by field, so
640
+ * `{ tooltip: { showDelay: 0 } }` overrides only `showDelay` and leaves a parent's
641
+ * `tooltip.position` alone. To drop an inherited value rather than change it, set it back to
642
+ * the component's own default explicitly — there is no "unset" marker.
643
+ */
644
+ declare function provideGogConfig(config: GogGlobalConfig): Provider;
645
+ /**
646
+ * The library's precedence rule for a configurable input, in one place: an instance's own
647
+ * input wins, then the app-wide `GOG_CONFIG` value, then the component's built-in default.
648
+ *
649
+ * Every configurable input resolves through this rather than repeating the `??` chain, so the
650
+ * order can't drift between components — a component that accidentally checked the config
651
+ * first would silently ignore the input on that one control only, which is close to invisible
652
+ * in review. Kept a plain function (no `inject`) so it works anywhere: inside a `computed`, in
653
+ * a composition class like `GogFloatLabelState`, and in unit tests without an injector.
654
+ *
655
+ * ```ts
656
+ * private readonly globalConfig = inject(GOG_CONFIG);
657
+ * protected readonly resolvedDebounce = computed(() =>
658
+ * resolveConfigured(this.debounce(), this.globalConfig.button?.debounce, DEFAULT_DEBOUNCE),
659
+ * );
660
+ * ```
661
+ */
662
+ declare function resolveConfigured<T>(instanceValue: T | undefined, configuredValue: T | undefined, fallback: T): T;
663
+
664
+ /**
665
+ * Shared "show a clear button" state for the field-style controls.
666
+ *
667
+ * A plain composition class, same reasoning as `GogErrorState` and `GogFloatLabelState`: it has
668
+ * to serve `gog-inputfield` and `gog-textarea` (no common base class) as well as
669
+ * `GogDropdownBase`, which is one.
670
+ *
671
+ * The two things each control supplies itself are `hasValue` — "there is something to clear"
672
+ * differs per control (non-empty string / non-null selection / non-empty array) — and the
673
+ * actual clearing, since only the control knows its own empty value and how to notify forms.
674
+ */
675
+ declare class GogClearableState {
676
+ private readonly clearableInput;
677
+ private readonly hasValue;
678
+ private readonly isNotEditable;
679
+ private readonly config;
680
+ private readonly fallback;
681
+ /**
682
+ * @param clearableInput the control's own `clearable` input (`undefined` when unset)
683
+ * @param hasValue whether there is anything to clear
684
+ * @param isNotEditable whether the control currently refuses edits — disabled, or (for the
685
+ * text controls) read-only. Either way it offers no clear button: the affordance would
686
+ * promise a change the control won't accept.
687
+ * @param config the injected `GOG_CONFIG`
688
+ * @param fallback the control's own default, read lazily — `GogDropdownBase` constructs this
689
+ * in a field initializer, before its subclass has assigned `clearableByDefault`. `false`
690
+ * everywhere except `gog-multiselect`, which shipped a clear button before this input
691
+ * existed and keeps it.
692
+ */
693
+ constructor(clearableInput: Signal<boolean | undefined>, hasValue: Signal<boolean>, isNotEditable: Signal<boolean>, config: GogGlobalConfig, fallback: () => boolean);
694
+ /** Whether the control is clearable at all — instance input, then config, then the default. */
695
+ readonly enabled: Signal<boolean>;
696
+ /**
697
+ * Whether the clear button should render *right now*. Deliberately value-driven: the control
698
+ * shows nothing to clear until there is something to clear, so the affordance appears with the
699
+ * content rather than sitting there permanently as dead chrome.
700
+ */
701
+ readonly isVisible: Signal<boolean>;
702
+ }
703
+
704
+ /** Returns the next id for `prefix`, e.g. `nextGogControlId('gog-input')` → `'gog-input-3'`. */
705
+ declare function nextGogControlId(prefix: string): string;
706
+
707
+ /**
708
+ * Every date calculation `gog-datepicker` and `gog-calendar` do, as pure functions.
709
+ *
710
+ * Kept out of the components so the arithmetic is testable without a fixture, and so a range
711
+ * calculation is written once rather than once per selection mode.
712
+ *
713
+ * **Everything here works in local time.** Nothing round-trips through `toISOString()` or
714
+ * compares `Date` objects directly: an ISO round trip converts to UTC, which moves the date
715
+ * across midnight for anyone east or west of Greenwich, and two `Date`s for "the same day"
716
+ * are almost never equal because they carry different times. Comparisons go through
717
+ * `startOfDay` and `isSameDay` instead. This is the single most common defect in a datepicker.
718
+ */
719
+ /** A start/end pair. `end` is null while a range is half-picked. */
720
+ interface GogDateRange {
721
+ start: Date | null;
722
+ end: Date | null;
723
+ }
724
+ /** Midnight local time on the same calendar day. */
725
+ declare function startOfDay(date: Date): Date;
726
+ /** Whether two dates fall on the same calendar day, ignoring the time of day. */
727
+ declare function isSameDay(a: Date | null, b: Date | null): boolean;
728
+ /** Whether two dates fall in the same calendar month. */
729
+ declare function isSameMonth(a: Date | null, b: Date | null): boolean;
730
+ declare function addDays(date: Date, days: number): Date;
731
+ /** Days in a given month. `month` is 0-based, as `Date` uses it. */
732
+ declare function daysInMonth(year: number, month: number): number;
733
+ /**
734
+ * Adds whole months, **clamping the day** to the target month's length: 31 January plus one
735
+ * month is 28 February, not 3 March. `Date.setMonth` does the latter, which is why this is
736
+ * not a one-liner.
737
+ */
738
+ declare function addMonths(date: Date, months: number): Date;
739
+ declare function addYears(date: Date, years: number): Date;
740
+ /** Day-granularity comparison: `a` is strictly before `b`'s day. */
741
+ declare function isBeforeDay(a: Date, b: Date): boolean;
742
+ /** Day-granularity comparison: `a` is strictly after `b`'s day. */
743
+ declare function isAfterDay(a: Date, b: Date): boolean;
744
+ /** Whether `date`'s day falls within `[min, max]`, either bound optional. */
745
+ declare function isWithinBounds(date: Date, min: Date | null, max: Date | null): boolean;
746
+ /** Whether `date`'s day falls inside a range, inclusive of both ends. */
747
+ declare function isInRange(date: Date, start: Date | null, end: Date | null): boolean;
748
+ /** Pulls `date` inside `[min, max]`, keeping its time of day. */
749
+ declare function clampDate(date: Date, min: Date | null, max: Date | null): Date;
750
+ /** A new date on `day`'s calendar day carrying `time`'s clock. */
751
+ declare function copyTimeOnto(day: Date, time: Date): Date;
752
+ /** A new date on the same day with the clock replaced. */
753
+ declare function withTime(date: Date, hours: number, minutes: number, seconds?: number): Date;
754
+ /**
755
+ * The six-week grid a month is drawn on, always 6×7 so the calendar's height never changes as
756
+ * you page through months — a grid that grows and shrinks pushes the rest of the page around
757
+ * and moves the button you were about to click.
758
+ *
759
+ * `firstDayOfWeek` is 0 (Sunday) to 6 (Saturday). Leading and trailing cells come from the
760
+ * neighbouring months, as every calendar does.
761
+ */
762
+ declare function buildMonthGrid(year: number, month: number, firstDayOfWeek: number): Date[][];
763
+ /** Weekday names in `locale`, rotated so `firstDayOfWeek` comes first. */
764
+ declare function weekdayNames(locale: string, firstDayOfWeek: number, style?: 'short' | 'narrow' | 'long'): string[];
765
+ /** Month names in `locale`. */
766
+ declare function monthNames(locale: string, style?: 'long' | 'short'): string[];
767
+ /**
768
+ * The first day of the week for a locale, from `Intl.Locale.prototype.getWeekInfo` where the
769
+ * engine has it, falling back to Monday.
770
+ *
771
+ * `getWeekInfo` reports 1–7 with 1 = Monday and 7 = Sunday; `Date.getDay()` uses 0 = Sunday.
772
+ * Converting between the two is exactly the kind of off-by-one that silently shifts a whole
773
+ * calendar by a day, which is why it happens here once.
774
+ */
775
+ declare function localeFirstDayOfWeek(locale: string): number;
776
+ /**
777
+ * Formats a date against a token pattern.
778
+ *
779
+ * Supported tokens: `yyyy`, `MM`, `dd`, `HH` (24h), `hh` (12h), `mm`, `ss`, `a` (AM/PM).
780
+ * Anything else is copied through literally.
781
+ *
782
+ * Deliberately **not** `Intl.DateTimeFormat`: this pattern is also what `parseDate` reads, and
783
+ * a formatter whose output cannot be parsed back is how a typed date silently becomes a
784
+ * different one. `Intl` is still used for month and weekday *names*, which are never parsed.
785
+ */
786
+ declare function formatDate(date: Date, pattern: string): string;
787
+ /**
788
+ * Reads a date back out of text written in `pattern`. Returns `null` when the text doesn't
789
+ * match, or matches but isn't a real date (`31.02.2026`).
790
+ *
791
+ * The out-of-range check matters: `new Date(2026, 1, 31)` happily rolls over to 3 March, so a
792
+ * typo would be accepted as a different date rather than rejected.
793
+ */
794
+ declare function parseDate(text: string, pattern: string): Date | null;
795
+
796
+ /** What kind of thing a deprecation is about: an exported symbol, or a CSS custom property. */
797
+ type GogDeprecationKind = 'symbol' | 'token';
798
+ /** One deprecated part of the public API, with the version that removes it. */
799
+ interface GogDeprecation {
800
+ kind: GogDeprecationKind;
801
+ /** The deprecated name — an export, an input, or a `--gog-*` custom property. */
802
+ name: string;
803
+ /** What to use instead. */
804
+ replacement: string;
805
+ /** The version that deprecated it, and the day it was announced. */
806
+ since: string;
807
+ sinceDate: string;
808
+ /** The version that removes it. Until then, the deprecated name still works. */
809
+ removedIn: string;
810
+ }
811
+ /**
812
+ * Everything `@guildofgleks/ui` currently deprecates: 28 symbol(s) and 3 token(s).
813
+ *
814
+ * Generated from the library's own source — `@deprecated` tags for symbols, and the stylesheets
815
+ * themselves for tokens — so it cannot drift from what actually still resolves. Meant for tooling
816
+ * that has to answer "is this still supported, and until when?": a docs site marking an API row,
817
+ * an editor plugin, a codemod.
818
+ *
819
+ * An empty `symbol` half means exactly what it says: nothing in the TypeScript API is deprecated
820
+ * right now.
821
+ */
822
+ declare const GOG_DEPRECATIONS: readonly GogDeprecation[];
823
+
824
+ /**
825
+ * How a collection-driven component reads one field off a consumer's own object.
826
+ *
827
+ * A `string` is a property name, or a dot-path into a nested one (`'profile.city'`). A function
828
+ * is anything else. This is what lets `gog-select` / `gog-multiselect` take a consumer's real
829
+ * DTO instead of forcing everything through a `{ id, name }` shape first.
830
+ */
831
+ type GogOptionAccessor<TOption, TResult> = string | ((option: TOption) => TResult);
832
+ /** Resolves `field` against `source`, following dot-paths (e.g. `"address.city"`). */
833
+ declare function getByPath(source: unknown, field: string): unknown;
834
+ /** Applies an accessor — a property path or a function — to one option. */
835
+ declare function readOption<TOption, TResult>(option: TOption, accessor: GogOptionAccessor<TOption, TResult>): TResult;
836
+ /**
837
+ * Whether two resolved option values refer to the same option.
838
+ *
839
+ * Primitives are compared as strings, so a `formControl` holding `'1'` still matches an option
840
+ * whose value is the number `1` — the library behaved this way before option values could be
841
+ * anything, and forms routinely stringify. Objects are compared by identity instead: coercing
842
+ * them would make every plain object equal to every other (`"[object Object]"`).
843
+ */
844
+ declare function isSameOptionValue(a: unknown, b: unknown): boolean;
845
+
846
+ /**
847
+ * Custom markup for the trigger's chevron, on `gog-select` and `gog-multiselect`:
848
+ *
849
+ * ```html
850
+ * <gog-select [options]="opts">
851
+ * <ng-template gogDropdownChevron><gog-icon name="sort" /></ng-template>
852
+ * </gog-select>
853
+ * ```
854
+ */
855
+ declare class GogDropdownChevronDirective {
856
+ readonly templateRef: TemplateRef<unknown>;
857
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<GogDropdownChevronDirective, never>;
858
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<GogDropdownChevronDirective, "[gogDropdownChevron]", never, {}, {}, never, never, true, never>;
859
+ }
860
+ /** Context handed to a `gogDropdownOption` template. */
861
+ interface GogDropdownOptionContext<TOption> {
862
+ /** The consumer's own option object, untouched. */
863
+ $implicit: TOption;
864
+ selected: boolean;
865
+ disabled: boolean;
866
+ /** The resolved label, so a custom row can decorate it rather than re-derive it. */
867
+ label: string;
868
+ }
869
+ /**
870
+ * Custom markup for one option row, on `gog-select` and `gog-multiselect`:
871
+ *
872
+ * ```html
873
+ * <gog-select [options]="users" optionLabel="fullName" optionValue="id" [(value)]="userId">
874
+ * <ng-template gogDropdownOption let-user let-selected="selected">
875
+ * <img [src]="user.avatar" alt="" /> {{ user.fullName }}
876
+ * </ng-template>
877
+ * </gog-select>
878
+ * ```
879
+ */
880
+ declare class GogDropdownOptionDirective<TOption = unknown> {
881
+ readonly templateRef: TemplateRef<GogDropdownOptionContext<TOption>>;
882
+ static ngTemplateContextGuard<TOption>(_dir: GogDropdownOptionDirective<TOption>, ctx: unknown): ctx is GogDropdownOptionContext<TOption>;
883
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<GogDropdownOptionDirective<any>, never>;
884
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<GogDropdownOptionDirective<any>, "[gogDropdownOption]", never, {}, {}, never, never, true, never>;
885
+ }
886
+ /**
887
+ * The shape the listbox controls assume when their accessor inputs are left at their defaults.
888
+ *
889
+ * It is no longer required: `optionLabel` / `optionValue` / `optionDisabled` accept any property
890
+ * path or function, so a consumer can pass their own DTO straight through. This interface just
891
+ * describes what the *default* accessors (`'name'` / `'id'` / `'disabled'`) expect to find.
892
+ */
893
+ interface GogDropdownOption {
894
+ id: string | number;
895
+ name: string;
896
+ disabled?: boolean;
897
+ }
898
+ /**
899
+ * Shared behaviour for the listbox-style controls: open/close, placement, the
900
+ * append-to-body overlay, click-outside, keyboard navigation and `ControlValueAccessor`
901
+ * plumbing. Subclasses supply only what actually differs — the value type, the panel
902
+ * markup, and the BEM class names used to find the trigger and the options.
903
+ *
904
+ * Exported because it appears in the public type signatures of the components that
905
+ * extend it; it is not meant to be used or subclassed by consumers.
906
+ */
907
+ declare abstract class GogDropdownBase<TValue, TOption = GogDropdownOption> implements ControlValueAccessor, DoCheck {
908
+ private static nextUid;
909
+ readonly label: _angular_core.InputSignal<string>;
910
+ readonly ariaLabel: _angular_core.InputSignal<string>;
911
+ readonly placeholder: _angular_core.InputSignal<string>;
912
+ readonly options: _angular_core.InputSignal<TOption[]>;
913
+ /**
914
+ * How to read an option's visible text — a property path (`'name'`, `'profile.title'`) or a
915
+ * function. Defaults to `'name'`, matching `GogDropdownOption`.
916
+ */
917
+ readonly optionLabel: _angular_core.InputSignal<GogOptionAccessor<TOption, string>>;
918
+ /**
919
+ * How to read the value this control emits for an option. A property path or a function, or
920
+ * `null` to emit **the option object itself** — which is what lets a consumer keep their own
921
+ * DTO end to end instead of mapping ids back to objects on every change.
922
+ *
923
+ * Defaults to `'id'`, matching `GogDropdownOption`, so existing code is unaffected.
924
+ */
925
+ readonly optionValue: _angular_core.InputSignal<GogOptionAccessor<TOption, unknown> | null>;
926
+ /** How to read whether an option is disabled. Defaults to `'disabled'`. */
927
+ readonly optionDisabled: _angular_core.InputSignal<GogOptionAccessor<TOption, boolean>>;
928
+ /**
929
+ * Whether to offer a clear button once something is selected. Unset, falls back to
930
+ * `GOG_CONFIG.control.clearable`, then to the control's own default.
931
+ */
932
+ readonly clearable: _angular_core.InputSignal<boolean | undefined>;
933
+ /**
934
+ * Accessible name for the clear button. Unset, falls back to
935
+ * `GOG_CONFIG.labels.clearSelection`, then to `'Clear selection'`.
936
+ */
937
+ readonly clearAriaLabel: _angular_core.InputSignal<string | undefined>;
938
+ /** Instance input → `GOG_CONFIG.labels` → the built-in English default. */
939
+ protected readonly resolvedClearLabel: Signal<string>;
940
+ /**
941
+ * Smallest width the trigger may shrink to, as any CSS length. Only meaningful with
942
+ * `[fullWidth]="false"`, where the trigger otherwise sizes to whatever is currently selected
943
+ * and can collapse to almost nothing on a short option. Left unset it falls back to the
944
+ * `--gog-{select,multiselect}-min-width` token.
945
+ */
946
+ readonly minWidth: _angular_core.InputSignal<string | null>;
947
+ /**
948
+ * Whether the panel shows a search box that narrows the option list. Unset, falls back to
949
+ * `GOG_CONFIG.dropdown.filter`, then to `false`.
950
+ */
951
+ readonly filter: _angular_core.InputSignal<boolean | undefined>;
952
+ readonly filterPlaceholder: _angular_core.InputSignal<string>;
953
+ /**
954
+ * Which end of the panel the search box sticks to. Named to match `gog-multiselect`'s
955
+ * `controlsPosition`, which is the same idea for its select-all row. Unset, falls back to
956
+ * `GOG_CONFIG.dropdown.filterPosition`, then to `'top'`.
957
+ */
958
+ readonly filterPosition: _angular_core.InputSignal<GogDropdownFilterPosition | undefined>;
959
+ /** Shown in place of the list when the query matches nothing. */
960
+ readonly filterEmptyMessage: _angular_core.InputSignal<string>;
961
+ /**
962
+ * How an option is matched against the query. Left null, the resolved `optionLabel` is
963
+ * matched case-insensitively as a substring — pass a function to search other fields, match
964
+ * on a prefix, or plug in your own fuzzy matcher.
965
+ */
966
+ readonly filterMatch: _angular_core.InputSignal<((option: TOption, query: string) => boolean) | null>;
967
+ readonly errorMessage: _angular_core.InputSignal<string>;
968
+ /**
969
+ * See `GogErrorDisplay`. Unset, falls back to `GOG_CONFIG.control.errorDisplay`, then to
970
+ * `'manual'` — matching every other control in the library.
971
+ */
972
+ readonly errorDisplay: _angular_core.InputSignal<GogErrorDisplay | undefined>;
973
+ /** Unset, falls back to `GOG_CONFIG.control.size`, then to `'md'`. */
974
+ readonly size: _angular_core.InputSignal<GogSize | undefined>;
975
+ /** Unset, falls back to `GOG_CONFIG.dropdown.direction`, then to `'auto'`. */
976
+ readonly dropdownDirection: _angular_core.InputSignal<GogDropdownDirection | undefined>;
977
+ /**
978
+ * Explicit stacking order for the panel. Left unset the panel falls back to the
979
+ * stylesheet's `--gog-dropdown-z`, so the default lives in CSS where a consumer can
980
+ * retheme it, rather than being baked into the component.
981
+ */
982
+ readonly dropdownZIndex: _angular_core.InputSignal<number | null>;
983
+ /**
984
+ * Fixed panel width as any CSS length (`'320px'`, `'40ch'`, `'100%'`, …), applied only
985
+ * when `appendToBody` is set. Left unset the panel matches the trigger's width, same as
986
+ * the inline panel already does via CSS.
987
+ */
988
+ readonly dropdownWidth: _angular_core.InputSignal<string | null>;
989
+ /**
990
+ * Fixed panel max-height as any CSS length, applied only when `appendToBody` is set.
991
+ * `px`, `%` and `vh` also feed the up/down placement math (see `resolveCssLengthPx`); any
992
+ * other unit still renders correctly but is invisible to that heuristic, so the panel may
993
+ * pick the "wrong" side close to a viewport edge. Left unset the panel keeps the existing
994
+ * viewport-derived, auto-flipping height.
995
+ */
996
+ readonly dropdownMaxHeight: _angular_core.InputSignal<string | null>;
997
+ /** Unset, falls back to `GOG_CONFIG.dropdown.appendToBody`, then to `false`. */
998
+ readonly appendToBody: _angular_core.InputSignal<boolean | undefined>;
999
+ readonly disabled: _angular_core.InputSignal<boolean>;
1000
+ /** Projected `gogDropdownChevron` template, replacing the built-in chevron. */
1001
+ protected readonly chevronSlot: Signal<GogDropdownChevronDirective | undefined>;
1002
+ /**
1003
+ * Full width of the container by default, matching every other field-style control.
1004
+ * Set to `false` to shrink the trigger to fit its selected label instead.
1005
+ */
1006
+ readonly fullWidth: _angular_core.InputSignal<boolean>;
1007
+ /** Unset, falls back to `GOG_CONFIG.floatLabel.variant`, then to `'none'` (off). */
1008
+ readonly floatLabel: _angular_core.InputSignal<GogFloatLabelVariant | undefined>;
1009
+ /** Unset, falls back to `GOG_CONFIG.floatLabel.showPlaceholder`, then to `false`. */
1010
+ readonly floatLabelShowPlaceholder: _angular_core.InputSignal<boolean | undefined>;
1011
+ /**
1012
+ * Press ripple on the panel's options. Unset, falls back to `GOG_CONFIG.ripple.enabled`, then
1013
+ * to `false`. The trigger itself never ripples — it is a field, not a button.
1014
+ */
1015
+ readonly ripple: _angular_core.InputSignal<boolean | undefined>;
1016
+ readonly isOpen: _angular_core.WritableSignal<boolean>;
1017
+ /** Projected `gogDropdownOption` template, if the consumer supplied one. */
1018
+ protected readonly optionSlot: Signal<GogDropdownOptionDirective<any> | undefined>;
1019
+ /** An option's visible text, via `optionLabel`. */
1020
+ protected labelOf(option: TOption): string;
1021
+ /**
1022
+ * The value this control emits for an option, via `optionValue` — or the option object
1023
+ * itself when `optionValue` is `null`.
1024
+ */
1025
+ protected valueOf(option: TOption): unknown;
1026
+ /** Whether an option is disabled, via `optionDisabled`. Anything falsy counts as enabled. */
1027
+ protected isOptionDisabled(option: TOption): boolean;
1028
+ /** Context for a projected `gogDropdownOption` row. */
1029
+ protected optionContext(option: TOption, selected: boolean): GogDropdownOptionContext<TOption>;
1030
+ /** Shared by both controls to match a resolved option value against the current value. */
1031
+ protected sameValue(a: unknown, b: unknown): boolean;
1032
+ /** The `<ng-template>` holding the panel markup, rendered inline or into `<body>`. */
1033
+ protected abstract readonly panelTemplate: Signal<TemplateRef<unknown> | undefined>;
1034
+ /** Declared by the subclass so each control keeps its own value type. */
1035
+ protected abstract readonly value: ModelSignal<TValue>;
1036
+ /** Value applied when a form writes `null` / the control is reset. */
1037
+ protected abstract readonly emptyValue: TValue;
1038
+ /** BEM class of one option button, used to collect keyboard-navigable elements. */
1039
+ protected abstract readonly optionClass: string;
1040
+ /** BEM class of the focusable trigger. */
1041
+ protected abstract readonly triggerClass: string;
1042
+ /**
1043
+ * BEM block that carries the size modifier — `.gog-select` vs `.gog-ms-wrapper`. Separate
1044
+ * from `triggerClass` because in `gog-multiselect` the two are different elements.
1045
+ */
1046
+ protected abstract readonly sizeBlockClass: string;
1047
+ /** BEM block of the panel, which repeats the size modifier when appended to `<body>`. */
1048
+ protected abstract readonly panelBlockClass: string;
1049
+ /** Whether the control currently has a selection — drives the float-label "filled" state. */
1050
+ protected abstract readonly hasFloatValue: Signal<boolean>;
1051
+ /**
1052
+ * Spacing tokens feeding the height estimate. Overridable so each control keeps the
1053
+ * `--gog-<block>-*` names it already exposes to consumers for theming.
1054
+ */
1055
+ /**
1056
+ * The gap **between rows**, as a seed for the first frame. Like `optionHeightToken`, the real
1057
+ * value is measured from the rendered list and replaces this.
1058
+ *
1059
+ * **Read the options container's CSS before pointing this at a token, not the token's name.**
1060
+ * Two of the three controls name a token `--gog-<block>-option-gap` and use it for the gap
1061
+ * *inside* a row — between the check mark and the label — with no gap between rows at all.
1062
+ * Seeding from it added 12px per row of panel that does not exist. Only `gog-multiselect`'s
1063
+ * options container declares a `gap`, and only it overrides this.
1064
+ */
1065
+ protected readonly optionGapToken: string;
1066
+ protected readonly optionsPaddingToken: string;
1067
+ /** Keep in sync with the real `max-height` on the subclass's `__dropdown` block. */
1068
+ protected readonly panelMaxHeightToken: string;
1069
+ /** Estimated row height fed into the placement math; not a real layout property. */
1070
+ protected readonly optionHeightToken: string;
1071
+ /**
1072
+ * Unique per-instance suffix, so several dropdowns on a page can't collide on DOM ids.
1073
+ *
1074
+ * Deliberately a bare number rather than `nextGogControlId()` (which the single-element
1075
+ * controls use): each subclass derives *several* ids from this one instance — trigger,
1076
+ * listbox, label, error — so what it needs is the instance number, not one finished id.
1077
+ */
1078
+ protected readonly uid: number;
1079
+ protected readonly elRef: ElementRef<any>;
1080
+ private readonly injector;
1081
+ protected readonly isBrowser: boolean;
1082
+ private readonly document;
1083
+ private readonly appRef;
1084
+ private readonly destroyRef;
1085
+ private readonly ngControl;
1086
+ /** `protected` so subclasses can resolve their own inputs against the same config object. */
1087
+ protected readonly globalConfig: _guildofgleks_ui_shared.GogGlobalConfig;
1088
+ private readonly overlay;
1089
+ /** Set from `(focus)`/`(blur)` on the trigger — see `onFocusIn`/`onFocusOut`. */
1090
+ protected readonly isFocused: _angular_core.WritableSignal<boolean>;
1091
+ /** Instance input → `GOG_CONFIG` → the component's own default. See `resolveConfigured`. */
1092
+ protected readonly resolvedSize: Signal<GogSize>;
1093
+ protected readonly rippleEnabled: Signal<boolean>;
1094
+ protected readonly resolvedErrorDisplay: Signal<GogErrorDisplay>;
1095
+ protected readonly resolvedAppendToBody: Signal<boolean>;
1096
+ protected readonly resolvedDropdownDirection: Signal<GogDropdownDirection>;
1097
+ /**
1098
+ * The single size modifier for the wrapper, replacing one `[class.<block>--<size>]` binding
1099
+ * per size. Empty for `'md'`: that is the default size and has no modifier rule of its own —
1100
+ * every `--gog-<block>-size-*` chain bottoms out at the `md` tokens.
1101
+ */
1102
+ protected readonly sizeClass: Signal<string>;
1103
+ /**
1104
+ * Same modifier repeated on the panel, but only when it is appended to `<body>` — outside
1105
+ * the component's subtree the panel no longer inherits the wrapper's size tokens, so it has
1106
+ * to carry them itself. See the `--portal` blocks in the component stylesheets.
1107
+ */
1108
+ protected readonly panelSizeClass: Signal<string>;
1109
+ private readonly cvaDisabled;
1110
+ private readonly errorState;
1111
+ protected readonly isDisabled: Signal<boolean>;
1112
+ protected readonly dropdownDirectionState: _angular_core.WritableSignal<"up" | "down">;
1113
+ protected readonly panelPlacement: _angular_core.WritableSignal<GogDropdownPlacement | null>;
1114
+ /**
1115
+ * Stacking order to write onto the panel, or null to leave it to the stylesheet.
1116
+ *
1117
+ * Only needed when appending to `<body>`: an inline panel inherits `--gog-dropdown-z` from
1118
+ * its surroundings — which is how a dropdown inside a dialog ends up above the dialog —
1119
+ * but an appended one sits outside that subtree and inherits nothing, so the value has
1120
+ * to be resolved from the trigger and written out explicitly.
1121
+ */
1122
+ protected readonly panelZIndex: _angular_core.WritableSignal<number | null>;
1123
+ /**
1124
+ * Explicit panel width, or null to let it size to its own content.
1125
+ *
1126
+ * The panel used to be pinned to the trigger's width, which broke a trigger narrower than its
1127
+ * options: with `[fullWidth]="false"` the trigger shrinks to the *current* selection, so
1128
+ * picking a short option cut the longer ones off in the list. It now sizes to its content with
1129
+ * the trigger width as a floor — see `resolvedPanelMinWidth`.
1130
+ */
1131
+ protected readonly resolvedPanelWidth: Signal<string | null>;
1132
+ /** The trigger's width, used as the panel's minimum so it never renders narrower than it. */
1133
+ protected readonly resolvedPanelMinWidth: Signal<string | null>;
1134
+ /** `dropdownMaxHeight`, or the viewport-derived max-height from `panelPlacement`. */
1135
+ protected readonly resolvedPanelMaxHeight: Signal<string | null>;
1136
+ protected readonly hasError: Signal<boolean>;
1137
+ protected readonly visibleError: Signal<string>;
1138
+ /**
1139
+ * Each control supplies its own default: `gog-multiselect` shipped a clear button before
1140
+ * `clearable` existed, so it keeps one; `gog-select` opts in.
1141
+ */
1142
+ protected abstract readonly clearableByDefault: boolean;
1143
+ private readonly clearableState;
1144
+ /** Whether to render the clear button right now — see `GogClearableState`. */
1145
+ protected readonly showClear: Signal<boolean>;
1146
+ protected readonly resolvedFilter: Signal<boolean>;
1147
+ protected readonly resolvedFilterPosition: Signal<GogDropdownFilterPosition>;
1148
+ /** Current search text. Cleared whenever the panel closes, so reopening starts fresh. */
1149
+ protected readonly filterQuery: _angular_core.WritableSignal<string>;
1150
+ /**
1151
+ * The options actually rendered. Everything downstream — the loops, the keyboard navigation
1152
+ * target list, the panel height estimate, and multiselect's select-all — reads this rather
1153
+ * than `options()`, so filtering stays consistent instead of only hiding rows visually.
1154
+ */
1155
+ protected readonly visibleOptions: Signal<TOption[]>;
1156
+ protected onFilterInput(event: Event): void;
1157
+ /**
1158
+ * Scrolls `index` into view **without moving focus**, which is what a combobox needs: focus
1159
+ * stays in the text field and the highlight is pointed at with `aria-activedescendant`, so
1160
+ * nothing scrolls the row into view on its own the way focusing it would.
1161
+ */
1162
+ protected revealOption(index: number): void;
1163
+ /** Puts the scroller, the window and the keyboard's idea of "here" back at the top together. */
1164
+ protected resetPanelScroll(): void;
1165
+ /**
1166
+ * Moves the scroller and the window's own idea of where it is, in that order and in the same
1167
+ * turn.
1168
+ *
1169
+ * The signal is written here rather than waiting for the scroller to echo the change back
1170
+ * through `(gogScroll)`: that echo is coalesced into an animation frame, so a keyboard move
1171
+ * that scrolled would compute its new range one frame after it moved focus -- which is one
1172
+ * frame during which the row it is trying to focus has not been rendered.
1173
+ */
1174
+ private setPanelScrollTop;
1175
+ /**
1176
+ * `gog-scroll`'s scrolling element inside the open panel, found in the DOM rather than with a
1177
+ * `viewChild`: an appended panel is attached to `<body>` as its own change-detection root, so a
1178
+ * view query on this component does not reach it.
1179
+ */
1180
+ private panelViewportElement;
1181
+ /** Resets the control to its empty value and notifies any attached form. */
1182
+ protected clearValue(event: Event): void;
1183
+ /**
1184
+ * `hasFloatValue` is wrapped in a `computed` rather than passed straight through: these
1185
+ * field initializers run before the *subclass's* do, so `this.hasFloatValue` is still
1186
+ * undefined right here. The arrow defers the read until the signal is first evaluated, by
1187
+ * which time the subclass has assigned it.
1188
+ */
1189
+ private readonly floatLabelState;
1190
+ protected readonly resolvedFloatLabel: Signal<GogFloatLabelVariant>;
1191
+ protected readonly isFloatLabelActive: Signal<boolean>;
1192
+ protected readonly isFloatLabelFloated: Signal<boolean>;
1193
+ protected readonly effectivePlaceholder: Signal<string>;
1194
+ /** Measured once per open rather than per scroll tick — see `refreshPanelMetrics`. */
1195
+ private optionGap;
1196
+ private optionsPadding;
1197
+ private maxPanelHeight;
1198
+ private optionHeight;
1199
+ /**
1200
+ * A real row's height, once one has ever been rendered. `null` until then.
1201
+ *
1202
+ * The token this class reads for `optionHeight` calls itself an estimate, and it is a bad one:
1203
+ * measured against a rendered row in all eleven shipped themes it is wrong in every one, from
1204
+ * -0.62px (`terminal`) to +8.38px (`parchment`), and low in ten of them. No static value can be
1205
+ * right -- the same `parchment` row is 48.38px at `--gog-density: 1` and 42.38px at 0.85,
1206
+ * because the height is padding plus leading plus border and a theme or a consumer can move
1207
+ * every term.
1208
+ *
1209
+ * That matters because the estimate is not decorative: `estimatePanelHeight` multiplies it by
1210
+ * the option count and `resolveDropdownDirection` opens the panel up or down on the result. Low
1211
+ * by 7px a row means a five-row panel judged to fit below when it needs 37px more than there is.
1212
+ * Only short lists were ever affected -- above `panelMaxHeightToken` the cap dominates and the
1213
+ * error is masked -- which is why it went unseen.
1214
+ */
1215
+ private measuredOptionHeight;
1216
+ /**
1217
+ * The real gap between two rows, once a list has ever rendered. `null` until then.
1218
+ *
1219
+ * Measured for the same reason the row height is, and it came out of the same audit: the token
1220
+ * `optionGapToken` seeds from is the *inside* of a row in two of the three controls (mark to
1221
+ * label), while their options containers declare no row gap at all. Reading the container is
1222
+ * exact where reading a token is a guess about what the token means.
1223
+ */
1224
+ private measuredOptionGap;
1225
+ private measureFrame;
1226
+ private repositionFrame;
1227
+ /**
1228
+ * Whether this instance windows its list. Resolved the same way every other dropdown setting
1229
+ * is: instance input, then `GOG_CONFIG.dropdown.virtualize`, then off.
1230
+ *
1231
+ * **Off by default and never switched on automatically.** A windowed list and a plain one
1232
+ * differ under `Ctrl+F`, under a screen reader's "list all items", and under any consumer CSS
1233
+ * that targets `:last-child`; flipping that at a row-count threshold would make the component's
1234
+ * behaviour depend on how much data happened to arrive, which works in development and
1235
+ * surprises in production. `GOG_CONFIG.ripple.enabled` is off by default for the same reason.
1236
+ */
1237
+ protected readonly resolvedVirtualize: Signal<boolean>;
1238
+ /**
1239
+ * The subclass's own `virtualize` input, if it offers one.
1240
+ *
1241
+ * A subclass overrides this with its input rather than the base declaring one, so a control
1242
+ * that has not adopted windowing yet does not inherit a public input that does nothing. Read
1243
+ * only from inside a `computed`, which is what lets a subclass field override a base field
1244
+ * that was initialised first.
1245
+ */
1246
+ protected readonly virtualizeRequest: Signal<boolean | undefined>;
1247
+ /**
1248
+ * How far apart two rows start, in px: the row's own height plus whatever gap the list puts
1249
+ * between rows. Seeded from the tokens and replaced by the measurement, exactly as the
1250
+ * placement estimate is -- and for a window it matters more, because the error accumulates
1251
+ * once per row instead of once per panel.
1252
+ */
1253
+ protected readonly rowPitch: _angular_core.WritableSignal<number>;
1254
+ /**
1255
+ * The gap alone, as a signal, because `spacerHeight` needs it from inside a `computed` and the
1256
+ * cached `measuredOptionGap` beside it is a plain field -- a computed reading that would be
1257
+ * correct only by the accident of `rowPitch` changing in the same statement.
1258
+ */
1259
+ private readonly rowGap;
1260
+ /**
1261
+ * The scroller's real geometry, fed from `gog-scroll`'s own `(gogScroll)`.
1262
+ *
1263
+ * The plan called for a `ResizeObserver` on the scroller; it is not needed, because the
1264
+ * scroller already runs one and already coalesces scroll and resize into a single
1265
+ * rAF-batched emission carrying both numbers. A second observer would have measured the same
1266
+ * element one frame later.
1267
+ *
1268
+ * `height` is the viewport's `clientHeight`, never `--gog-*-panel-max-height`: that token is a
1269
+ * cap, and a panel with three options is three rows tall.
1270
+ */
1271
+ protected readonly panelViewport: _angular_core.WritableSignal<{
1272
+ scrollTop: number;
1273
+ height: number;
1274
+ }>;
1275
+ private readonly virtualWindow;
1276
+ /** Index into `visibleOptions()` of the row the keyboard is on, or -1 for none. */
1277
+ protected readonly activeOptionIndex: _angular_core.WritableSignal<number>;
1278
+ /** The slice of `visibleOptions()` actually stamped into the panel. */
1279
+ protected readonly optionWindow: Signal<_guildofgleks_ui_shared.GogVirtualRange>;
1280
+ /**
1281
+ * What the template loops over. Identical to `visibleOptions()` when not windowing, and the
1282
+ * same array instance, so nothing re-renders for the sake of a slice that changed nothing.
1283
+ */
1284
+ protected readonly renderedOptions: Signal<TOption[]>;
1285
+ /**
1286
+ * Filler above and below the rendered rows, in px.
1287
+ *
1288
+ * Spacers rather than absolute positioning: the rows stay flex children of the same container,
1289
+ * so every gap, selector and `:last-child` the component already relies on keeps working. See
1290
+ * `GogVirtualWindow`'s own note for why that trade is worth making for a one-column list.
1291
+ */
1292
+ protected readonly padBefore: Signal<number>;
1293
+ protected readonly padAfter: Signal<number>;
1294
+ /**
1295
+ * A spacer's own height, less the gap the flex column puts either side of it.
1296
+ *
1297
+ * A spacer is a flex child like a row, so a list that declares `gap` gets one *around the
1298
+ * spacer too* -- and the window's padding already accounts for every gap in the rows it stands
1299
+ * in for. Left uncorrected, an open panel is two gaps too tall and every rendered row sits one
1300
+ * gap lower than its index says. It is a constant, not an accumulating error, which is exactly
1301
+ * why it would have survived review: at `gog-multiselect`'s 4px nothing looks wrong, it is just
1302
+ * 4px wrong everywhere.
1303
+ *
1304
+ * `gog-select` and `gog-autocomplete` declare no row gap, so this subtracts nothing there. The
1305
+ * subtraction can never go negative on a spacer that exists: any non-zero padding is at least
1306
+ * one whole row, and a row is taller than the gap beside it.
1307
+ */
1308
+ private spacerHeight;
1309
+ /**
1310
+ * A windowed listbox holds twenty `role="option"` children and has to announce ten thousand.
1311
+ *
1312
+ * Set only while windowing. An unwindowed list has every option in the DOM, and the browser's
1313
+ * own count is then both correct and free -- restating it would be one more thing to keep true.
1314
+ */
1315
+ protected readonly ariaSetSize: Signal<number | null>;
1316
+ /** The real position of a rendered row in the full list, 1-based, or null when not windowing. */
1317
+ protected ariaPosInSet(renderedIndex: number): number | null;
1318
+ /** `(gogScroll)` on the panel's `gog-scroll`. */
1319
+ protected onPanelScroll(metrics: {
1320
+ scrollTop: number;
1321
+ clientHeight: number;
1322
+ }): void;
1323
+ /**
1324
+ * A row that scrolls out of the window is unmounted, and an unmounted element holding focus
1325
+ * drops it on `<body>` -- where an open panel has no keyboard at all: Escape does not close it
1326
+ * and the arrows scroll the page instead of the list.
1327
+ *
1328
+ * So a mouse scroll that would take the focused row away hands focus back to the trigger,
1329
+ * which is a state both Escape and ArrowDown work from. Checked here rather than in an effect
1330
+ * because this runs *before* the re-render, while the row still exists and can still be asked
1331
+ * whether it is the focused one -- after the unmount that question has no answer.
1332
+ *
1333
+ * This is the price of windowing that a plain list does not pay, and the reason it is opt-in.
1334
+ */
1335
+ private releaseFocusLeavingTheWindow;
1336
+ private onChangeFn;
1337
+ private onTouchedFn;
1338
+ constructor();
1339
+ /**
1340
+ * Binds the click-outside and reposition listeners only for as long as the panel is
1341
+ * open. Bound permanently — as host listeners were — every dropdown on the page runs a
1342
+ * handler on every document click and every scroll frame, whether or not it is showing
1343
+ * anything.
1344
+ */
1345
+ private bindWhileOpen;
1346
+ ngDoCheck(): void;
1347
+ writeValue(val: TValue | null): void;
1348
+ registerOnChange(fn: (val: TValue) => void): void;
1349
+ registerOnTouched(fn: () => void): void;
1350
+ setDisabledState(isDisabled: boolean): void;
1351
+ /** Bound to `(focus)` on the trigger — only drives the float-label floated state. */
1352
+ protected onFocusIn(): void;
1353
+ /** Bound to `(blur)` on the trigger — only drives the float-label floated state. */
1354
+ protected onFocusOut(): void;
1355
+ protected toggle(): void;
1356
+ protected open(): void;
1357
+ /**
1358
+ * Gives the window numbers to work from before anything has rendered.
1359
+ *
1360
+ * Without this the first frame has a viewport height of zero, which `GogVirtualWindow`
1361
+ * deliberately reads as "render everything" -- correct, and exactly the 10 000 rows the window
1362
+ * exists to avoid, stamped once before the scroller reports its real height a frame later. The
1363
+ * seed is the same panel-height estimate placement already uses, so no new arithmetic and no
1364
+ * new token.
1365
+ */
1366
+ private seedWindow;
1367
+ protected close(): void;
1368
+ /** Writes a new selection out to both the model and the attached form control. */
1369
+ protected commitValue(next: TValue): void;
1370
+ protected markTouched(): void;
1371
+ private closeIfClickedOutside;
1372
+ /**
1373
+ * Coalesces bursts of scroll/resize events into one reposition per frame. Placement
1374
+ * reads layout, so running it per event is what makes a scroll janky.
1375
+ */
1376
+ private scheduleReposition;
1377
+ /**
1378
+ * Reads one real row after the panel has rendered, and re-places if the token had lied.
1379
+ *
1380
+ * One frame late by construction -- the row has to exist -- so the very first open of an
1381
+ * instance can be placed from the estimate and corrected before the next paint. Every later
1382
+ * open starts from the measurement and is right immediately, which is why this caches rather
1383
+ * than measuring each time.
1384
+ *
1385
+ * Deliberately does **not** fall back to the token when no row is found: an empty list has no
1386
+ * row to measure and no rows to be wrong about, and overwriting a good measurement with the
1387
+ * token because the user filtered everything away would undo the fix.
1388
+ */
1389
+ private scheduleOptionMeasure;
1390
+ /** Jumps from the trigger into the option list on ArrowDown/ArrowUp while open. */
1391
+ protected onTriggerArrowKeydown(event: Event): void;
1392
+ protected onOptionKeydown(event: KeyboardEvent): void;
1393
+ /**
1394
+ * Moves the keyboard's index by one roving-focus key, skipping disabled options and wrapping,
1395
+ * then makes the DOM agree: scroll first if the target is outside the window, focus second.
1396
+ */
1397
+ private moveActiveOption;
1398
+ /**
1399
+ * Puts the keyboard on `index` and the focus with it.
1400
+ *
1401
+ * The wait is conditional on purpose: `scrollOffsetFor` returns null when the row is already
1402
+ * visible, which means it is already rendered and can be focused in this turn. Only a move
1403
+ * that actually changes the window has to wait for the render that stamps the row.
1404
+ */
1405
+ private focusOptionAt;
1406
+ private focusRenderedOption;
1407
+ protected focusTrigger(): void;
1408
+ /** Extra chrome stacked above the options (e.g. a select-all row), in px. */
1409
+ protected extraPanelHeight(): number;
1410
+ private enabledOptionElements;
1411
+ private attachOverlay;
1412
+ /**
1413
+ * Reads the spacing tokens that feed the height estimate. Done once per open instead of
1414
+ * on every scroll tick, because `getComputedStyle` forces a style recalculation and the
1415
+ * tokens cannot change while the panel is on screen.
1416
+ */
1417
+ private refreshPanelMetrics;
1418
+ /**
1419
+ * The panel's height, used to choose up/down and to cap `max-height`.
1420
+ *
1421
+ * Estimated on the very first open of an instance and exact from then on. Measuring needs a
1422
+ * rendered row and placement runs before the panel renders, so the first pass uses the row
1423
+ * height token; `measureOptionHeight` then reads a real row and re-places if it disagreed.
1424
+ * Every open after that starts from the measurement.
1425
+ *
1426
+ * A resolvable `dropdownMaxHeight` replaces the row-count arithmetic outright, since it is
1427
+ * exact rather than derived.
1428
+ */
1429
+ private estimatePanelHeight;
1430
+ /**
1431
+ * The trigger's own rect, not the whole component's — a label above it or an error
1432
+ * message below it sit in normal document flow and are not part of what the panel needs
1433
+ * to clear. This also keeps `appendToBody` placement consistent with the inline panel,
1434
+ * which is already positioned purely relative to the trigger via CSS.
1435
+ */
1436
+ private triggerRect;
1437
+ /** The stacking order the panel would have had if it were still inside the subtree. */
1438
+ private resolvePanelZIndex;
1439
+ private updatePlacement;
1440
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<GogDropdownBase<any, any>, never>;
1441
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<GogDropdownBase<any, any>, never, never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; "optionLabel": { "alias": "optionLabel"; "required": false; "isSignal": true; }; "optionValue": { "alias": "optionValue"; "required": false; "isSignal": true; }; "optionDisabled": { "alias": "optionDisabled"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "clearAriaLabel": { "alias": "clearAriaLabel"; "required": false; "isSignal": true; }; "minWidth": { "alias": "minWidth"; "required": false; "isSignal": true; }; "filter": { "alias": "filter"; "required": false; "isSignal": true; }; "filterPlaceholder": { "alias": "filterPlaceholder"; "required": false; "isSignal": true; }; "filterPosition": { "alias": "filterPosition"; "required": false; "isSignal": true; }; "filterEmptyMessage": { "alias": "filterEmptyMessage"; "required": false; "isSignal": true; }; "filterMatch": { "alias": "filterMatch"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "errorDisplay": { "alias": "errorDisplay"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "dropdownDirection": { "alias": "dropdownDirection"; "required": false; "isSignal": true; }; "dropdownZIndex": { "alias": "dropdownZIndex"; "required": false; "isSignal": true; }; "dropdownWidth": { "alias": "dropdownWidth"; "required": false; "isSignal": true; }; "dropdownMaxHeight": { "alias": "dropdownMaxHeight"; "required": false; "isSignal": true; }; "appendToBody": { "alias": "appendToBody"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "fullWidth": { "alias": "fullWidth"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "floatLabelShowPlaceholder": { "alias": "floatLabelShowPlaceholder"; "required": false; "isSignal": true; }; "ripple": { "alias": "ripple"; "required": false; "isSignal": true; }; }, {}, ["chevronSlot", "optionSlot"], never, true, never>;
1442
+ }
1443
+
1444
+ /**
1445
+ * Renders a template into `document.body` while keeping it wired to the declaring
1446
+ * component: the view is stamped with that component's style encapsulation and reads
1447
+ * its signals directly.
1448
+ *
1449
+ * That is the whole point of doing it this way rather than with a second, portal-only
1450
+ * component: one `<ng-template>` can serve both the inline and the appended-to-body
1451
+ * dropdown, so the option markup exists once and cannot drift between the two modes,
1452
+ * and selection state needs no manual field-syncing to stay in step.
1453
+ */
1454
+ declare class GogDropdownOverlay {
1455
+ private readonly appRef;
1456
+ private readonly document;
1457
+ private hostEl;
1458
+ private viewRef;
1459
+ constructor(appRef: ApplicationRef, document: Document);
1460
+ /** The `<body>` child holding the rendered panel, or null while detached. */
1461
+ get hostElement(): HTMLElement | null;
1462
+ get isAttached(): boolean;
1463
+ attach(template: TemplateRef<unknown>, themeSource?: Element | null): void;
1464
+ detach(): void;
1465
+ }
1466
+
1467
+ /**
1468
+ * Shared float-label state for the library's field-style controls.
1469
+ *
1470
+ * A plain class rather than a base class or directive, for the same reason as `GogErrorState`:
1471
+ * it has to serve `gog-inputfield` and `gog-textarea`, which share no base class, as well as
1472
+ * `GogDropdownBase`, which is one. Each consumer owns an instance and exposes whichever
1473
+ * members its template needs.
1474
+ *
1475
+ * The one thing each control must supply itself is `hasValue` — "this field has content" means
1476
+ * something different everywhere (a non-empty string, a non-null selection, a non-empty
1477
+ * selection array), which is exactly why this is composed in rather than implemented as a
1478
+ * directive sitting outside the component.
1479
+ */
1480
+ declare class GogFloatLabelState {
1481
+ private readonly variantInput;
1482
+ private readonly showPlaceholderInput;
1483
+ private readonly placeholder;
1484
+ private readonly isFocused;
1485
+ private readonly hasValue;
1486
+ private readonly config;
1487
+ /**
1488
+ * @param variantInput the control's own `floatLabel` input (`undefined` when unset)
1489
+ * @param showPlaceholderInput the control's own `floatLabelShowPlaceholder` input
1490
+ * @param placeholder the control's `placeholder` input
1491
+ * @param isFocused whether the control currently has focus
1492
+ * @param hasValue whether the control has a value — see the class note
1493
+ * @param config the injected `GOG_CONFIG`
1494
+ */
1495
+ constructor(variantInput: Signal<GogFloatLabelVariant | undefined>, showPlaceholderInput: Signal<boolean | undefined>, placeholder: Signal<string>, isFocused: Signal<boolean>, hasValue: Signal<boolean>, config: GogGlobalConfig);
1496
+ /** The resolved variant: instance input, else `GOG_CONFIG.floatLabel.variant`, else `'none'`. */
1497
+ readonly variant: Signal<GogFloatLabelVariant>;
1498
+ readonly showPlaceholder: Signal<boolean>;
1499
+ /** Whether a float label is in effect at all — `false` keeps the static label-above layout. */
1500
+ readonly isActive: Signal<boolean>;
1501
+ /** Whether the label is at its floated target rather than resting like a placeholder. */
1502
+ readonly isFloated: Signal<boolean>;
1503
+ /**
1504
+ * The placeholder the control should actually render. While a float label is active the
1505
+ * resting label already occupies that space, so the placeholder stays hidden unless the
1506
+ * consumer opted into `floatLabelShowPlaceholder` — and even then only once the label has
1507
+ * floated out of the way.
1508
+ */
1509
+ readonly effectivePlaceholder: Signal<string>;
1510
+ }
1511
+
1512
+ /**
1513
+ * Icons an app has registered, keyed by the name `gog-icon` will be asked for. Resolves to `{}`
1514
+ * — only the built-ins are available — until a `provideGogIcons(...)` call fills it in.
1515
+ *
1516
+ * Values are raw `<svg>` markup, injected with `bypassSecurityTrustHtml` exactly like the
1517
+ * built-ins. See `provideGogIcons` for what that means for you.
1518
+ */
1519
+ declare const GOG_ICONS: InjectionToken<Readonly<Record<string, string>>>;
1520
+ /**
1521
+ * Registers icons by name, so `<gog-icon name="cart" />` works for glyphs the library does not
1522
+ * ship. This is the supported way to use your own icon set: the alternative — a `TemplateRef`
1523
+ * per instance through the `template` input — costs a `<ng-template>` at every use site and is
1524
+ * meant for one-offs, not for an icon set.
1525
+ *
1526
+ * ```ts
1527
+ * // app.config.ts
1528
+ * providers: [
1529
+ * provideGogIcons({
1530
+ * cart: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">…</svg>',
1531
+ * user: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">…</svg>',
1532
+ * }),
1533
+ * ]
1534
+ * ```
1535
+ *
1536
+ * **A registered name overrides a built-in of the same name**, which is how you swap the
1537
+ * library's checkmark or chevron for your own without touching every component that renders one.
1538
+ *
1539
+ * **Providing this again further down the injector tree layers onto the parent's set** rather
1540
+ * than replacing it, matching `provideGogConfig`: a lazy feature can register the three icons
1541
+ * only it uses, and the app-wide set stays available inside it.
1542
+ *
1543
+ * ## What to put in the SVG
1544
+ *
1545
+ * Use `stroke="currentColor"` (or `fill="currentColor"`) and a `viewBox`, and leave the sizing
1546
+ * alone — `gog-icon`'s stylesheet drives width, height and stroke width from the
1547
+ * `--gog-icon-*` tokens, so an icon inherits size and colour from wherever it is used, the same
1548
+ * as a built-in.
1549
+ *
1550
+ * ## Security
1551
+ *
1552
+ * The markup is inserted with `DomSanitizer.bypassSecurityTrustHtml`, because Angular's HTML
1553
+ * sanitizer strips SVG and would leave you with nothing. That is safe for what this is for —
1554
+ * static icon markup you wrote or imported at build time — and unsafe for anything derived from
1555
+ * user input or fetched at runtime. **Never build a registered icon string from data you did
1556
+ * not author.** If you need remote icons, fetch them yourself, sanitize them with a real SVG
1557
+ * sanitizer, and register the result.
1558
+ */
1559
+ declare function provideGogIcons(icons: Readonly<Record<string, string>>): Provider;
1560
+
1561
+ /**
1562
+ * The glyphs the package ships. Kept as a closed union so they still autocomplete and so
1563
+ * `ICON_DEFS` below stays exhaustive — a `Record` over the open `GogIconName` would collapse
1564
+ * into an index signature and stop catching a missing definition.
1565
+ */
1566
+ type GogBuiltinIconName = 'check' | 'close' | 'chevron-up' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'calendar' | 'clock' | 'sort' | 'sort-up' | 'sort-down' | 'success' | 'error' | 'warning' | 'info' | 'checkbox' | 'checkbox-checked' | 'eye' | 'eye-off' | 'copy' | 'search' | 'plus' | 'minus' | 'trash' | 'pencil' | 'download' | 'upload' | 'refresh' | 'filter' | 'external-link' | 'menu' | 'more-horizontal' | 'more-vertical' | 'arrow-left' | 'arrow-right' | 'user' | 'settings' | 'lock' | 'mail' | 'star' | 'star-filled';
1567
+ /**
1568
+ * Any icon `gog-icon` can render: one of the built-ins, or a name registered through
1569
+ * `provideGogIcons(...)`. The `(string & {})` half keeps the built-in names in autocomplete
1570
+ * while letting a registered name through — an open union is the point, since the set of icons
1571
+ * an app uses is the app's business, not the library's.
1572
+ */
1573
+ type GogIconName = GogBuiltinIconName | (string & {});
1574
+ declare const ICON_DEFS: Record<GogBuiltinIconName, string>;
1575
+
1576
+ /**
1577
+ * Which writing direction a portaled overlay has to carry, if any.
1578
+ *
1579
+ * A dropdown panel or tooltip bubble is appended to `<body>`, which takes it out of whatever
1580
+ * subtree it was opened from. `dir` is inherited, so an overlay opened inside an RTL region of
1581
+ * an otherwise-LTR page would render LTR — text aligned the wrong way, the panel's own
1582
+ * `inset-inline-*` resolving against the wrong side. Copying the nearest scoped `dir` onto the
1583
+ * portal host fixes that, exactly as `scopedOverlayTheme` does for `data-theme`.
1584
+ *
1585
+ * **Only when the direction really is scoped.** When the nearest `[dir]` is the document
1586
+ * element — the ordinary case, a whole RTL app — the overlay already inherits it through
1587
+ * `<body>`, and re-stating it is noise on every panel in the app.
1588
+ *
1589
+ * Known limitation, shared with `scopedOverlayTheme`: a direction set through CSS
1590
+ * (`direction: rtl` in a stylesheet) rather than the `dir` attribute is not detected. Reading
1591
+ * `getComputedStyle().direction` would catch it, but that forces layout on every open for a
1592
+ * case the HTML spec itself discourages — `dir` is the attribute browsers, form controls and
1593
+ * assistive tech all key off.
1594
+ */
1595
+ declare function scopedOverlayDirection(directionSource: Element | null, documentElement: Element): 'ltr' | 'rtl' | null;
1596
+
1597
+ /**
1598
+ * Which `data-theme` an overlay rendered into `<body>` has to carry, if any.
1599
+ *
1600
+ * A panel or tooltip bubble is appended to `<body>`, which puts it outside whatever subtree it
1601
+ * was opened from. `data-theme` can be scoped to any subtree — several themes rendering side by
1602
+ * side is a documented use — so an overlay opened inside one of those has to be told which theme
1603
+ * it belongs to, or it silently picks up the document's instead.
1604
+ *
1605
+ * **But only when the theme really is scoped.** When the nearest themed ancestor is the document
1606
+ * element, copying the attribute is not merely redundant, it is actively wrong: the overlay
1607
+ * already inherits everything from `<html>` through `<body>`, and re-stating `data-theme` on it
1608
+ * makes it match `theme.css`'s derived layer (`:root, [data-theme]`) *locally*. That re-declares
1609
+ * every component token on the overlay itself, resolved against the plain preset palette — which
1610
+ * discards anything set on `<html>` that is not part of that preset. Custom properties written
1611
+ * inline on `:root` are the case that bites: a live theme editor sets them there, the page
1612
+ * follows, and every portal keeps rendering the un-edited theme.
1613
+ *
1614
+ * So: return the theme only for a genuinely scoped ancestor, and let inheritance do the work
1615
+ * otherwise.
1616
+ *
1617
+ * Known limitation, currently unreachable: a *scoped* theme that is itself being edited through
1618
+ * inline custom properties would still lose those on the overlay, since only the attribute is
1619
+ * carried across. Copying resolved values instead would mean reading ~1200 properties on every
1620
+ * open, which is not worth it for a case nothing does yet.
1621
+ */
1622
+ declare function scopedOverlayTheme(themeSource: Element | null, documentElement: Element): string | null;
1623
+
1624
+ /**
1625
+ * Off, so the ripple is purely additive: adding it to the library changed the appearance of
1626
+ * nothing until an app asks for it. Flipping this default would change how every button in every
1627
+ * consuming app looks, which is a release of its own, not a line in a feature commit.
1628
+ */
1629
+ declare const DEFAULT_RIPPLE = false;
1630
+ /**
1631
+ * Shared "does this control ripple" state, resolved the usual way — instance input, then
1632
+ * `GOG_CONFIG.ripple.enabled`, then off.
1633
+ *
1634
+ * A plain function rather than a class (`GogClearableState`'s shape) because there is exactly one
1635
+ * derived value and nothing to hold: every component that ripples writes the same two lines, and
1636
+ * this is what keeps the precedence identical across all nine of them instead of nine separate
1637
+ * `??` chains that can drift.
1638
+ *
1639
+ * The component then binds the *negation* onto its own inner element:
1640
+ *
1641
+ * ```html
1642
+ * <button class="gog-btn" gogRipple [rippleDisabled]="!rippleEnabled()">
1643
+ * ```
1644
+ *
1645
+ * `[gogRipple]` is always applied rather than toggled, because a directive cannot be added and
1646
+ * removed by a binding — and it costs nothing while disabled: `GogRippleDirective` attaches no
1647
+ * event listeners at all until `rippleDisabled` goes false.
1648
+ */
1649
+ declare function resolveRipple(rippleInput: Signal<boolean | undefined>, config: GogGlobalConfig): Signal<boolean>;
1650
+
1651
+ declare const VERTICAL_ARROWS: readonly ["ArrowDown", "ArrowUp"];
1652
+ declare const HORIZONTAL_ARROWS: readonly ["ArrowRight", "ArrowLeft"];
1653
+ declare const EDGE_KEYS: readonly ["Home", "End"];
1654
+ type RovingFocusKey = (typeof VERTICAL_ARROWS)[number] | (typeof HORIZONTAL_ARROWS)[number] | (typeof EDGE_KEYS)[number];
1655
+ /**
1656
+ * Whether `key` navigates a roving-tabindex list laid out along `orientation`.
1657
+ *
1658
+ * The orientation filter is the point: a horizontal tablist must leave `ArrowDown` alone so
1659
+ * the page still scrolls, and a vertical listbox must not steal `ArrowRight` from a caret
1660
+ * inside a text field. `Home`/`End` are accepted for both.
1661
+ */
1662
+ declare function isRovingFocusKey(key: string, orientation?: GogOrientation): key is RovingFocusKey;
1663
+ /**
1664
+ * The index `key` moves to from `currentIndex`, wrapping at both ends.
1665
+ *
1666
+ * `isEnabled` lets a caller keep disabled items in the list — which it must, since they still
1667
+ * occupy a position in the DOM — while navigation steps over them. Without it every index is a
1668
+ * target, which is the behaviour the dropdowns rely on (they pre-filter their own list).
1669
+ * Returns `currentIndex` when nothing else is reachable, so a group of one enabled item cannot
1670
+ * spin.
1671
+ */
1672
+ declare function nextRovingFocusIndex(key: RovingFocusKey, currentIndex: number, count: number, isEnabled?: (index: number) => boolean): number;
1673
+ /**
1674
+ * Arrow/Home/End navigation across a roving-tabindex-style list of focusable elements.
1675
+ * `event.currentTarget` must be one of `items`. Returns false (and leaves the event
1676
+ * untouched) for any other key, or when `items` doesn't contain the current target,
1677
+ * so callers can safely invoke this unconditionally from a keydown handler.
1678
+ *
1679
+ * Defaults to a vertical list with every item reachable — the shape the option lists and the
1680
+ * accordion were written against — so existing callers need no options object.
1681
+ */
1682
+ declare function handleRovingFocusKeydown(event: KeyboardEvent, items: readonly HTMLElement[], options?: {
1683
+ orientation?: GogOrientation;
1684
+ /** Items this returns true for are skipped rather than focused. */
1685
+ isDisabled?: (item: HTMLElement, index: number) => boolean;
1686
+ }): boolean;
1687
+
1688
+ /** Every `--gog-*` custom property the library declares or documents as an override point. */
1689
+ type GogTokenName = '--gog-accent-bright' | '--gog-accent-color' | '--gog-accent-dim' | '--gog-accent-pale' | '--gog-accent-text-color' | '--gog-accordion-accent-color' | '--gog-accordion-body-bg' | '--gog-accordion-body-color' | '--gog-accordion-body-font-family' | '--gog-accordion-body-font-size' | '--gog-accordion-body-lift' | '--gog-accordion-body-line-height' | '--gog-accordion-body-padding-bottom' | '--gog-accordion-body-padding-top' | '--gog-accordion-body-radius' | '--gog-accordion-body-transition-duration' | '--gog-accordion-border-color' | '--gog-accordion-border-style' | '--gog-accordion-border-width' | '--gog-accordion-chevron-font-size' | '--gog-accordion-chevron-line-height' | '--gog-accordion-chevron-size' | '--gog-accordion-chevron-transition-duration' | '--gog-accordion-content-gap' | '--gog-accordion-disabled-opacity' | '--gog-accordion-focus-ring-color' | '--gog-accordion-focus-ring-width' | '--gog-accordion-font-family' | '--gog-accordion-font-size' | '--gog-accordion-header-bg' | '--gog-accordion-header-gap' | '--gog-accordion-header-text-transform' | '--gog-accordion-hover-bg' | '--gog-accordion-hover-color' | '--gog-accordion-letter-spacing' | '--gog-accordion-lg-body-font-size' | '--gog-accordion-lg-body-line-height' | '--gog-accordion-lg-body-padding-bottom' | '--gog-accordion-lg-body-padding-top' | '--gog-accordion-lg-chevron-font-size' | '--gog-accordion-lg-chevron-size' | '--gog-accordion-lg-content-gap' | '--gog-accordion-lg-font-size' | '--gog-accordion-lg-letter-spacing' | '--gog-accordion-lg-padding-x' | '--gog-accordion-lg-padding-y' | '--gog-accordion-line-height' | '--gog-accordion-md-body-font-size' | '--gog-accordion-md-body-line-height' | '--gog-accordion-md-body-padding-bottom' | '--gog-accordion-md-body-padding-top' | '--gog-accordion-md-chevron-font-size' | '--gog-accordion-md-chevron-size' | '--gog-accordion-md-content-gap' | '--gog-accordion-md-font-size' | '--gog-accordion-md-letter-spacing' | '--gog-accordion-md-padding-x' | '--gog-accordion-md-padding-y' | '--gog-accordion-padding-x' | '--gog-accordion-padding-y' | '--gog-accordion-press-bg' | '--gog-accordion-radius' | '--gog-accordion-slg-body-font-size' | '--gog-accordion-slg-body-line-height' | '--gog-accordion-slg-body-padding-bottom' | '--gog-accordion-slg-body-padding-top' | '--gog-accordion-slg-chevron-font-size' | '--gog-accordion-slg-chevron-size' | '--gog-accordion-slg-content-gap' | '--gog-accordion-slg-font-size' | '--gog-accordion-slg-letter-spacing' | '--gog-accordion-slg-padding-x' | '--gog-accordion-slg-padding-y' | '--gog-accordion-sm-body-font-size' | '--gog-accordion-sm-body-line-height' | '--gog-accordion-sm-body-padding-bottom' | '--gog-accordion-sm-body-padding-top' | '--gog-accordion-sm-chevron-font-size' | '--gog-accordion-sm-chevron-size' | '--gog-accordion-sm-content-gap' | '--gog-accordion-sm-font-size' | '--gog-accordion-sm-letter-spacing' | '--gog-accordion-sm-padding-x' | '--gog-accordion-sm-padding-y' | '--gog-accordion-text-color' | '--gog-accordion-transition-duration' | '--gog-accordion-xsm-body-font-size' | '--gog-accordion-xsm-body-line-height' | '--gog-accordion-xsm-body-padding-bottom' | '--gog-accordion-xsm-body-padding-top' | '--gog-accordion-xsm-chevron-font-size' | '--gog-accordion-xsm-chevron-size' | '--gog-accordion-xsm-content-gap' | '--gog-accordion-xsm-font-size' | '--gog-accordion-xsm-letter-spacing' | '--gog-accordion-xsm-padding-x' | '--gog-accordion-xsm-padding-y' | '--gog-alert-accent-color' | '--gog-alert-bg' | '--gog-alert-body-font-size' | '--gog-alert-body-line-height' | '--gog-alert-border-color' | '--gog-alert-border-style' | '--gog-alert-border-width' | '--gog-alert-color' | '--gog-alert-danger-color' | '--gog-alert-edge-width' | '--gog-alert-font-family' | '--gog-alert-gap' | '--gog-alert-heading-color' | '--gog-alert-heading-font-size' | '--gog-alert-heading-font-weight' | '--gog-alert-heading-line-height' | '--gog-alert-icon-font-size' | '--gog-alert-icon-line-height' | '--gog-alert-info-color' | '--gog-alert-main-gap' | '--gog-alert-padding-x' | '--gog-alert-padding-y' | '--gog-alert-radius' | '--gog-alert-success-color' | '--gog-alert-warning-color' | '--gog-autocomplete-actions-gap' | '--gog-autocomplete-actions-inset' | '--gog-autocomplete-actions-reserve' | '--gog-autocomplete-bg' | '--gog-autocomplete-border-color' | '--gog-autocomplete-border-style' | '--gog-autocomplete-border-width' | '--gog-autocomplete-clear-color' | '--gog-autocomplete-clear-hover-color' | '--gog-autocomplete-clear-icon-ratio' | '--gog-autocomplete-color' | '--gog-autocomplete-disabled-opacity' | '--gog-autocomplete-empty-color' | '--gog-autocomplete-empty-font-size' | '--gog-autocomplete-empty-line-height' | '--gog-autocomplete-error-border-color' | '--gog-autocomplete-error-color' | '--gog-autocomplete-error-font-family' | '--gog-autocomplete-error-font-size' | '--gog-autocomplete-error-line-height' | '--gog-autocomplete-field-bg' | '--gog-autocomplete-float-label-in-top' | '--gog-autocomplete-float-label-on-bg' | '--gog-autocomplete-float-label-over-gap' | '--gog-autocomplete-float-label-over-reserve' | '--gog-autocomplete-float-label-reserve' | '--gog-autocomplete-focus-ring-color' | '--gog-autocomplete-focus-ring-offset' | '--gog-autocomplete-focus-ring-width' | '--gog-autocomplete-font-family' | '--gog-autocomplete-font-size' | '--gog-autocomplete-gap' | '--gog-autocomplete-hover-border-color' | '--gog-autocomplete-label-color' | '--gog-autocomplete-label-font-family' | '--gog-autocomplete-label-font-size' | '--gog-autocomplete-label-font-weight' | '--gog-autocomplete-label-letter-spacing' | '--gog-autocomplete-label-line-height' | '--gog-autocomplete-label-text-transform' | '--gog-autocomplete-line-height' | '--gog-autocomplete-min-width' | '--gog-autocomplete-option-color' | '--gog-autocomplete-option-gap' | '--gog-autocomplete-option-height' | '--gog-autocomplete-option-hover-bg' | '--gog-autocomplete-option-hover-color' | '--gog-autocomplete-option-padding' | '--gog-autocomplete-option-press-bg' | '--gog-autocomplete-option-radius' | '--gog-autocomplete-option-selected-bg' | '--gog-autocomplete-option-selected-color' | '--gog-autocomplete-options-padding' | '--gog-autocomplete-padding-x' | '--gog-autocomplete-padding-y' | '--gog-autocomplete-panel-bg' | '--gog-autocomplete-panel-border-color' | '--gog-autocomplete-panel-border-style' | '--gog-autocomplete-panel-border-width' | '--gog-autocomplete-panel-gap' | '--gog-autocomplete-panel-max-height' | '--gog-autocomplete-panel-max-width' | '--gog-autocomplete-panel-radius' | '--gog-autocomplete-panel-shadow' | '--gog-autocomplete-placeholder-color' | '--gog-autocomplete-radius' | '--gog-autocomplete-spinner-size' | '--gog-autocomplete-text-color' | '--gog-autocomplete-transition-duration' | '--gog-background-color' | '--gog-badge-bg' | '--gog-badge-border-color' | '--gog-badge-border-style' | '--gog-badge-border-width' | '--gog-badge-color' | '--gog-badge-danger-bg' | '--gog-badge-danger-color' | '--gog-badge-dot-size' | '--gog-badge-font-family' | '--gog-badge-font-size' | '--gog-badge-font-weight' | '--gog-badge-info-bg' | '--gog-badge-info-color' | '--gog-badge-line-height' | '--gog-badge-offset' | '--gog-badge-padding-inline' | '--gog-badge-radius' | '--gog-badge-size' | '--gog-badge-success-bg' | '--gog-badge-success-color' | '--gog-badge-warning-bg' | '--gog-badge-warning-color' | '--gog-badge-z' | '--gog-border-color' | '--gog-border-style' | '--gog-border-width' | '--gog-button-active-scale' | '--gog-button-bg' | '--gog-button-border' | '--gog-button-border-style' | '--gog-button-border-width' | '--gog-button-color' | '--gog-button-danger-fill' | '--gog-button-danger-fill-hover' | '--gog-button-danger-fill-press' | '--gog-button-danger-ink' | '--gog-button-danger-on-fill' | '--gog-button-danger-wash' | '--gog-button-disabled-opacity' | '--gog-button-focus-ring-color' | '--gog-button-focus-ring-offset' | '--gog-button-focus-ring-width' | '--gog-button-font-family' | '--gog-button-font-weight' | '--gog-button-gap' | '--gog-button-ghost-bg' | '--gog-button-ghost-border' | '--gog-button-ghost-color' | '--gog-button-ghost-hover-bg' | '--gog-button-ghost-hover-color' | '--gog-button-ghost-hover-shadow' | '--gog-button-ghost-press-bg' | '--gog-button-ghost-press-color' | '--gog-button-ghost-shadow' | '--gog-button-ghost-spinner-color' | '--gog-button-ghost-toggled-shadow' | '--gog-button-hover-bg' | '--gog-button-hover-color' | '--gog-button-hover-shadow' | '--gog-button-info-fill' | '--gog-button-info-fill-hover' | '--gog-button-info-fill-press' | '--gog-button-info-ink' | '--gog-button-info-on-fill' | '--gog-button-info-wash' | '--gog-button-letter-spacing' | '--gog-button-lg-font-size' | '--gog-button-lg-padding' | '--gog-button-line-height' | '--gog-button-loading-opacity' | '--gog-button-md-font-size' | '--gog-button-md-padding' | '--gog-button-outline-bg' | '--gog-button-outline-border' | '--gog-button-outline-color' | '--gog-button-outline-hover-bg' | '--gog-button-outline-hover-color' | '--gog-button-outline-hover-shadow' | '--gog-button-outline-press-bg' | '--gog-button-outline-press-color' | '--gog-button-outline-shadow' | '--gog-button-outline-spinner-color' | '--gog-button-outline-toggled-shadow' | '--gog-button-press-bg' | '--gog-button-press-color' | '--gog-button-primary-bg' | '--gog-button-primary-border' | '--gog-button-primary-color' | '--gog-button-primary-hover-bg' | '--gog-button-primary-hover-color' | '--gog-button-primary-hover-shadow' | '--gog-button-primary-press-bg' | '--gog-button-primary-press-color' | '--gog-button-primary-shadow' | '--gog-button-primary-spinner-color' | '--gog-button-primary-toggled-shadow' | '--gog-button-radius' | '--gog-button-secondary-bg' | '--gog-button-secondary-border' | '--gog-button-secondary-color' | '--gog-button-secondary-hover-bg' | '--gog-button-secondary-hover-color' | '--gog-button-secondary-hover-shadow' | '--gog-button-secondary-press-bg' | '--gog-button-secondary-press-color' | '--gog-button-secondary-shadow' | '--gog-button-secondary-spinner-color' | '--gog-button-secondary-toggled-shadow' | '--gog-button-shadow' | '--gog-button-slg-font-size' | '--gog-button-slg-padding' | '--gog-button-sm-font-size' | '--gog-button-sm-padding' | '--gog-button-spinner-color' | '--gog-button-spinner-max-size' | '--gog-button-success-fill' | '--gog-button-success-fill-hover' | '--gog-button-success-fill-press' | '--gog-button-success-ink' | '--gog-button-success-on-fill' | '--gog-button-success-wash' | '--gog-button-text-transform' | '--gog-button-toggle-bg' | '--gog-button-toggle-border-color' | '--gog-button-toggle-border-style' | '--gog-button-toggle-border-width' | '--gog-button-toggle-color' | '--gog-button-toggle-disabled-opacity' | '--gog-button-toggle-focus-ring-color' | '--gog-button-toggle-focus-ring-offset' | '--gog-button-toggle-focus-ring-width' | '--gog-button-toggle-font-family' | '--gog-button-toggle-font-size' | '--gog-button-toggle-font-weight' | '--gog-button-toggle-gap' | '--gog-button-toggle-hover-bg' | '--gog-button-toggle-hover-color' | '--gog-button-toggle-icon-size' | '--gog-button-toggle-letter-spacing' | '--gog-button-toggle-line-height' | '--gog-button-toggle-padding' | '--gog-button-toggle-press-bg' | '--gog-button-toggle-radius' | '--gog-button-toggle-rest-bg' | '--gog-button-toggle-rest-color' | '--gog-button-toggle-selected-bg' | '--gog-button-toggle-selected-border-color' | '--gog-button-toggle-selected-color' | '--gog-button-toggle-selected-press-bg' | '--gog-button-toggle-separated-gap' | '--gog-button-toggle-text-transform' | '--gog-button-toggle-transition-duration' | '--gog-button-toggled-ring-width' | '--gog-button-toggled-shadow' | '--gog-button-transition-duration' | '--gog-button-warning-fill' | '--gog-button-warning-fill-hover' | '--gog-button-warning-fill-press' | '--gog-button-warning-ink' | '--gog-button-warning-on-fill' | '--gog-button-warning-wash' | '--gog-button-xsm-font-size' | '--gog-button-xsm-padding' | '--gog-calendar-action-padding' | '--gog-calendar-color' | '--gog-calendar-day-bg' | '--gog-calendar-day-border-style' | '--gog-calendar-day-border-width' | '--gog-calendar-day-color' | '--gog-calendar-day-hover-bg' | '--gog-calendar-day-outside-color' | '--gog-calendar-day-radius' | '--gog-calendar-day-rest-bg' | '--gog-calendar-day-rest-color' | '--gog-calendar-day-size' | '--gog-calendar-disabled-opacity' | '--gog-calendar-divider-color' | '--gog-calendar-divider-style' | '--gog-calendar-divider-width' | '--gog-calendar-focus-ring-color' | '--gog-calendar-focus-ring-offset' | '--gog-calendar-focus-ring-width' | '--gog-calendar-font-family' | '--gog-calendar-footer-gap' | '--gog-calendar-header-gap' | '--gog-calendar-header-margin' | '--gog-calendar-lg-day-size' | '--gog-calendar-lg-font-size' | '--gog-calendar-line-height' | '--gog-calendar-max-width' | '--gog-calendar-md-day-size' | '--gog-calendar-md-font-size' | '--gog-calendar-months-gap' | '--gog-calendar-nav-bg' | '--gog-calendar-nav-color' | '--gog-calendar-nav-hover-bg' | '--gog-calendar-nav-hover-color' | '--gog-calendar-nav-icon-overlap' | '--gog-calendar-nav-icon-size' | '--gog-calendar-nav-radius' | '--gog-calendar-nav-size' | '--gog-calendar-padding' | '--gog-calendar-range-bg' | '--gog-calendar-range-color' | '--gog-calendar-selected-bg' | '--gog-calendar-selected-color' | '--gog-calendar-selected-font-weight' | '--gog-calendar-slg-day-size' | '--gog-calendar-slg-font-size' | '--gog-calendar-sm-day-size' | '--gog-calendar-sm-font-size' | '--gog-calendar-time-gap' | '--gog-calendar-time-input-bg' | '--gog-calendar-time-input-padding' | '--gog-calendar-time-input-width' | '--gog-calendar-time-margin' | '--gog-calendar-title-color' | '--gog-calendar-title-font-weight' | '--gog-calendar-today-border-color' | '--gog-calendar-today-font-weight' | '--gog-calendar-transition-duration' | '--gog-calendar-weekday-color' | '--gog-calendar-weekday-font-size' | '--gog-calendar-weekday-font-weight' | '--gog-calendar-weekday-line-height' | '--gog-calendar-weekday-padding' | '--gog-calendar-weekday-text-transform' | '--gog-calendar-xsm-day-size' | '--gog-calendar-xsm-font-size' | '--gog-card-bg' | '--gog-card-border-color' | '--gog-card-border-style' | '--gog-card-border-width' | '--gog-card-color' | '--gog-card-disabled-opacity' | '--gog-card-elevated-bg' | '--gog-card-elevated-border-color' | '--gog-card-elevated-shadow' | '--gog-card-filled-bg' | '--gog-card-filled-border-color' | '--gog-card-filled-shadow' | '--gog-card-focus-ring' | '--gog-card-focus-ring-offset' | '--gog-card-focus-ring-width' | '--gog-card-font-family' | '--gog-card-footer-border-color' | '--gog-card-footer-gap' | '--gog-card-footer-padding-top' | '--gog-card-gap' | '--gog-card-heading-color' | '--gog-card-heading-font-family' | '--gog-card-heading-font-size' | '--gog-card-heading-font-weight' | '--gog-card-heading-line-height' | '--gog-card-hover-border-color' | '--gog-card-hover-shadow' | '--gog-card-lg-gap' | '--gog-card-lg-padding-x' | '--gog-card-lg-padding-y' | '--gog-card-md-gap' | '--gog-card-md-padding-x' | '--gog-card-md-padding-y' | '--gog-card-outlined-bg' | '--gog-card-outlined-border-color' | '--gog-card-outlined-shadow' | '--gog-card-padding-x' | '--gog-card-padding-y' | '--gog-card-radius' | '--gog-card-shadow' | '--gog-card-slg-gap' | '--gog-card-slg-padding-x' | '--gog-card-slg-padding-y' | '--gog-card-sm-gap' | '--gog-card-sm-padding-x' | '--gog-card-sm-padding-y' | '--gog-card-transition-duration' | '--gog-card-xsm-gap' | '--gog-card-xsm-padding-x' | '--gog-card-xsm-padding-y' | '--gog-checkbox-bg' | '--gog-checkbox-border-color' | '--gog-checkbox-border-style' | '--gog-checkbox-border-width' | '--gog-checkbox-box-size' | '--gog-checkbox-checked-bg' | '--gog-checkbox-checked-border' | '--gog-checkbox-dash-height' | '--gog-checkbox-dash-radius' | '--gog-checkbox-dash-width-ratio' | '--gog-checkbox-disabled-opacity' | '--gog-checkbox-focus-ring' | '--gog-checkbox-focus-ring-offset' | '--gog-checkbox-focus-ring-width' | '--gog-checkbox-font-family' | '--gog-checkbox-gap' | '--gog-checkbox-icon-color' | '--gog-checkbox-icon-line-height' | '--gog-checkbox-icon-size' | '--gog-checkbox-label-color' | '--gog-checkbox-label-line-height' | '--gog-checkbox-label-size' | '--gog-checkbox-padding' | '--gog-checkbox-radius' | '--gog-checkbox-transition-duration' | '--gog-chip-avatar-inset-ratio' | '--gog-chip-avatar-size' | '--gog-chip-bg' | '--gog-chip-border' | '--gog-chip-border-style' | '--gog-chip-border-width' | '--gog-chip-color' | '--gog-chip-disabled-opacity' | '--gog-chip-focus-ring-color' | '--gog-chip-focus-ring-offset' | '--gog-chip-focus-ring-width' | '--gog-chip-font-family' | '--gog-chip-font-size' | '--gog-chip-font-weight' | '--gog-chip-gap' | '--gog-chip-hover-bg' | '--gog-chip-icon-size' | '--gog-chip-lg-avatar-size' | '--gog-chip-lg-font-size' | '--gog-chip-lg-gap' | '--gog-chip-lg-icon-size' | '--gog-chip-lg-padding-block' | '--gog-chip-lg-padding-inline' | '--gog-chip-lg-remove-size' | '--gog-chip-line-height' | '--gog-chip-md-avatar-size' | '--gog-chip-md-font-size' | '--gog-chip-md-gap' | '--gog-chip-md-icon-size' | '--gog-chip-md-padding-block' | '--gog-chip-md-padding-inline' | '--gog-chip-md-remove-size' | '--gog-chip-padding-block' | '--gog-chip-padding-inline' | '--gog-chip-pill-radius' | '--gog-chip-press-bg' | '--gog-chip-radius' | '--gog-chip-remove-color' | '--gog-chip-remove-hover-color' | '--gog-chip-remove-inset-ratio' | '--gog-chip-remove-scale' | '--gog-chip-remove-size' | '--gog-chip-selected-ring-width' | '--gog-chip-selected-shadow' | '--gog-chip-slg-avatar-size' | '--gog-chip-slg-font-size' | '--gog-chip-slg-gap' | '--gog-chip-slg-icon-size' | '--gog-chip-slg-padding-block' | '--gog-chip-slg-padding-inline' | '--gog-chip-slg-remove-size' | '--gog-chip-sm-avatar-size' | '--gog-chip-sm-font-size' | '--gog-chip-sm-gap' | '--gog-chip-sm-icon-size' | '--gog-chip-sm-padding-block' | '--gog-chip-sm-padding-inline' | '--gog-chip-sm-remove-size' | '--gog-chip-xsm-avatar-size' | '--gog-chip-xsm-font-size' | '--gog-chip-xsm-gap' | '--gog-chip-xsm-icon-size' | '--gog-chip-xsm-padding-block' | '--gog-chip-xsm-padding-inline' | '--gog-chip-xsm-remove-size' | '--gog-collapsible-disabled-opacity' | '--gog-collapsible-max-height' | '--gog-collapsible-transition-duration' | '--gog-confirmation-dialog-actions-gap' | '--gog-confirmation-dialog-actions-offset' | '--gog-confirmation-dialog-color' | '--gog-confirmation-dialog-description-color' | '--gog-confirmation-dialog-description-font-size' | '--gog-confirmation-dialog-description-line-height' | '--gog-confirmation-dialog-gap' | '--gog-confirmation-dialog-max-width' | '--gog-confirmation-dialog-min-width' | '--gog-confirmation-dialog-title-font-size' | '--gog-confirmation-dialog-title-line-height' | '--gog-control-border-style' | '--gog-control-border-width' | '--gog-control-boundary-color' | '--gog-control-checkbox-box-size-lg' | '--gog-control-checkbox-box-size-md' | '--gog-control-checkbox-box-size-slg' | '--gog-control-checkbox-box-size-sm' | '--gog-control-checkbox-box-size-xsm' | '--gog-control-checkbox-icon-size-lg' | '--gog-control-checkbox-icon-size-md' | '--gog-control-checkbox-icon-size-slg' | '--gog-control-checkbox-icon-size-sm' | '--gog-control-checkbox-icon-size-xsm' | '--gog-control-checkbox-label-size-lg' | '--gog-control-checkbox-label-size-md' | '--gog-control-checkbox-label-size-slg' | '--gog-control-checkbox-label-size-sm' | '--gog-control-checkbox-label-size-xsm' | '--gog-control-checkbox-padding' | '--gog-control-clear-icon-ratio' | '--gog-control-icon-offset' | '--gog-control-padding-x' | '--gog-control-padding-y' | '--gog-danger-color' | '--gog-danger-shade' | '--gog-danger-text-color' | '--gog-datepicker-actions-gap' | '--gog-datepicker-actions-inset' | '--gog-datepicker-actions-reserve' | '--gog-datepicker-bg' | '--gog-datepicker-border-color' | '--gog-datepicker-border-style' | '--gog-datepicker-border-width' | '--gog-datepicker-clear-color' | '--gog-datepicker-clear-icon-ratio' | '--gog-datepicker-color' | '--gog-datepicker-disabled-opacity' | '--gog-datepicker-error-border-color' | '--gog-datepicker-error-color' | '--gog-datepicker-error-font-family' | '--gog-datepicker-error-font-size' | '--gog-datepicker-error-line-height' | '--gog-datepicker-field-bg' | '--gog-datepicker-float-label-in-top' | '--gog-datepicker-float-label-on-bg' | '--gog-datepicker-float-label-over-gap' | '--gog-datepicker-float-label-over-reserve' | '--gog-datepicker-float-label-reserve' | '--gog-datepicker-focus-ring-color' | '--gog-datepicker-focus-ring-offset' | '--gog-datepicker-focus-ring-width' | '--gog-datepicker-font-family' | '--gog-datepicker-font-size' | '--gog-datepicker-gap' | '--gog-datepicker-hover-border-color' | '--gog-datepicker-icon-color' | '--gog-datepicker-icon-hover-color' | '--gog-datepicker-label-color' | '--gog-datepicker-label-font-family' | '--gog-datepicker-label-font-size' | '--gog-datepicker-label-letter-spacing' | '--gog-datepicker-label-line-height' | '--gog-datepicker-label-text-transform' | '--gog-datepicker-line-height' | '--gog-datepicker-min-width' | '--gog-datepicker-padding-x' | '--gog-datepicker-padding-y' | '--gog-datepicker-panel-bg' | '--gog-datepicker-panel-border-color' | '--gog-datepicker-panel-border-style' | '--gog-datepicker-panel-border-width' | '--gog-datepicker-panel-gap' | '--gog-datepicker-panel-radius' | '--gog-datepicker-panel-shadow' | '--gog-datepicker-panel-width' | '--gog-datepicker-placeholder-color' | '--gog-datepicker-radius' | '--gog-datepicker-text-color' | '--gog-datepicker-toggle-icon-size' | '--gog-datepicker-transition-duration' | '--gog-density' | '--gog-dialog-backdrop-bg' | '--gog-dialog-backdrop-blur' | '--gog-dialog-backdrop-fade-duration' | '--gog-dialog-backdrop-padding' | '--gog-dialog-bg' | '--gog-dialog-body-max-height' | '--gog-dialog-body-padding' | '--gog-dialog-border' | '--gog-dialog-border-style' | '--gog-dialog-border-width' | '--gog-dialog-close-color' | '--gog-dialog-close-focus-ring' | '--gog-dialog-close-focus-ring-offset' | '--gog-dialog-close-focus-ring-width' | '--gog-dialog-close-font-size' | '--gog-dialog-close-hover-bg' | '--gog-dialog-close-hover-border' | '--gog-dialog-close-hover-color' | '--gog-dialog-close-line-height' | '--gog-dialog-close-size' | '--gog-dialog-color' | '--gog-dialog-enter-distance' | '--gog-dialog-enter-duration' | '--gog-dialog-font-family' | '--gog-dialog-header-border-color' | '--gog-dialog-header-gap' | '--gog-dialog-header-padding' | '--gog-dialog-max-height' | '--gog-dialog-min-width' | '--gog-dialog-offset-x' | '--gog-dialog-offset-y' | '--gog-dialog-radius' | '--gog-dialog-shadow' | '--gog-dialog-title-font-size' | '--gog-dialog-title-line-height' | '--gog-disabled-opacity' | '--gog-divider-block-spacing' | '--gog-divider-color' | '--gog-divider-dashed-style' | '--gog-divider-dotted-style' | '--gog-divider-inline-spacing' | '--gog-divider-inset-size' | '--gog-divider-label-color' | '--gog-divider-label-font-family' | '--gog-divider-label-font-size' | '--gog-divider-label-font-weight' | '--gog-divider-label-gap' | '--gog-divider-label-line-height' | '--gog-divider-line-color' | '--gog-divider-line-thickness' | '--gog-divider-solid-style' | '--gog-divider-spacing' | '--gog-divider-thickness' | '--gog-divider-vertical-length' | '--gog-dropdown-z' | '--gog-duration-base' | '--gog-duration-fast' | '--gog-duration-slow' | '--gog-easing' | '--gog-elevated-surface-color' | '--gog-elevation-0' | '--gog-elevation-1' | '--gog-elevation-2' | '--gog-elevation-3' | '--gog-elevation-4' | '--gog-elevation-5' | '--gog-elevation-ambient-alpha' | '--gog-elevation-contact' | '--gog-elevation-contact-blur' | '--gog-elevation-highlight' | '--gog-elevation-highlight-alpha' | '--gog-elevation-highlight-ink' | '--gog-elevation-ink' | '--gog-elevation-key-alpha' | '--gog-elevation-key-blur' | '--gog-elevation-key-x' | '--gog-elevation-key-y' | '--gog-elevation-ring' | '--gog-elevation-ring-width' | '--gog-field-error-line-height' | '--gog-field-float-label-in-top' | '--gog-field-float-label-over-gap' | '--gog-field-float-label-over-reserve' | '--gog-field-float-label-reserve' | '--gog-field-icon-glyph' | '--gog-field-icon-glyph-sm' | '--gog-field-icon-glyph-xsm' | '--gog-field-label-line-height' | '--gog-field-lg-font-size' | '--gog-field-lg-icon-inset' | '--gog-field-lg-icon-offset' | '--gog-field-lg-padding-x' | '--gog-field-lg-padding-y' | '--gog-field-line-height' | '--gog-field-md-font-size' | '--gog-field-md-icon-inset' | '--gog-field-md-icon-offset' | '--gog-field-md-padding-x' | '--gog-field-md-padding-y' | '--gog-field-slg-font-size' | '--gog-field-slg-icon-inset' | '--gog-field-slg-icon-offset' | '--gog-field-slg-padding-x' | '--gog-field-slg-padding-y' | '--gog-field-sm-font-size' | '--gog-field-sm-icon-inset' | '--gog-field-sm-icon-offset' | '--gog-field-sm-padding-x' | '--gog-field-sm-padding-y' | '--gog-field-xsm-font-size' | '--gog-field-xsm-icon-inset' | '--gog-field-xsm-icon-offset' | '--gog-field-xsm-padding-x' | '--gog-field-xsm-padding-y' | '--gog-focus-ring-offset' | '--gog-focus-ring-width' | '--gog-font-body' | '--gog-font-heading' | '--gog-font-mono' | '--gog-font-weight-bold' | '--gog-font-weight-heavy' | '--gog-font-weight-medium' | '--gog-font-weight-semibold' | '--gog-hover-color' | '--gog-icon-fallback-size' | '--gog-icon-size' | '--gog-icon-stroke-width' | '--gog-info-color' | '--gog-info-shade' | '--gog-info-text-color' | '--gog-input-clear-icon-ratio' | '--gog-input-clear-inset' | '--gog-input-clear-line-height' | '--gog-input-clear-radius' | '--gog-input-disabled-opacity' | '--gog-input-error-color' | '--gog-input-error-font-size' | '--gog-input-error-line-height' | '--gog-input-error-offset' | '--gog-input-field-bg' | '--gog-input-field-border' | '--gog-input-field-border-style' | '--gog-input-field-border-width' | '--gog-input-field-color' | '--gog-input-float-label-in-top' | '--gog-input-float-label-on-bg' | '--gog-input-float-label-over-gap' | '--gog-input-float-label-over-reserve' | '--gog-input-float-label-reserve' | '--gog-input-focus-border' | '--gog-input-focus-glow' | '--gog-input-focus-ring' | '--gog-input-focus-ring-offset' | '--gog-input-focus-ring-width' | '--gog-input-font' | '--gog-input-font-family' | '--gog-input-gap' | '--gog-input-icon-action-radius' | '--gog-input-icon-color' | '--gog-input-icon-focus-ring-width' | '--gog-input-icon-hover-color' | '--gog-input-icon-line-height' | '--gog-input-label-color' | '--gog-input-label-font-family' | '--gog-input-label-font-size' | '--gog-input-label-letter-spacing' | '--gog-input-label-line-height' | '--gog-input-label-text-transform' | '--gog-input-padding-x' | '--gog-input-padding-y' | '--gog-input-placeholder-color' | '--gog-input-radius' | '--gog-input-spin-hover-bg' | '--gog-input-spin-width' | '--gog-input-transition-duration' | '--gog-letter-spacing' | '--gog-line-height-loose' | '--gog-line-height-none' | '--gog-line-height-normal' | '--gog-line-height-relaxed' | '--gog-line-height-snug' | '--gog-line-height-tight' | '--gog-menu-available-height' | '--gog-menu-bg' | '--gog-menu-border-color' | '--gog-menu-border-style' | '--gog-menu-border-width' | '--gog-menu-focus-ring' | '--gog-menu-focus-ring-width' | '--gog-menu-font-family' | '--gog-menu-gap' | '--gog-menu-item-color' | '--gog-menu-item-disabled-color' | '--gog-menu-item-disabled-opacity' | '--gog-menu-item-font-size' | '--gog-menu-item-gap' | '--gog-menu-item-hover-bg' | '--gog-menu-item-hover-color' | '--gog-menu-item-icon-size' | '--gog-menu-item-line-height' | '--gog-menu-item-padding' | '--gog-menu-item-press-bg' | '--gog-menu-item-radius' | '--gog-menu-max-height' | '--gog-menu-max-width' | '--gog-menu-min-width' | '--gog-menu-padding' | '--gog-menu-panel-gap' | '--gog-menu-radius' | '--gog-menu-shadow' | '--gog-menu-transition-duration' | '--gog-menu-z' | '--gog-multiselect-actions-gap' | '--gog-multiselect-actions-inset' | '--gog-multiselect-arrow-icon-ratio' | '--gog-multiselect-arrow-transition-duration' | '--gog-multiselect-border-color' | '--gog-multiselect-checkbox-border' | '--gog-multiselect-checkbox-checked-bg' | '--gog-multiselect-clear-icon-ratio' | '--gog-multiselect-clear-line-height' | '--gog-multiselect-clear-radius' | '--gog-multiselect-controls-gap' | '--gog-multiselect-controls-padding' | '--gog-multiselect-disabled-opacity' | '--gog-multiselect-error-color' | '--gog-multiselect-error-font-size' | '--gog-multiselect-error-line-height' | '--gog-multiselect-error-offset' | '--gog-multiselect-field-bg' | '--gog-multiselect-field-border' | '--gog-multiselect-field-border-style' | '--gog-multiselect-field-border-width' | '--gog-multiselect-field-color' | '--gog-multiselect-filter-border-color' | '--gog-multiselect-filter-border-style' | '--gog-multiselect-filter-border-width' | '--gog-multiselect-filter-empty-color' | '--gog-multiselect-filter-empty-padding' | '--gog-multiselect-filter-input-bg' | '--gog-multiselect-filter-input-border' | '--gog-multiselect-filter-input-color' | '--gog-multiselect-filter-input-padding-x' | '--gog-multiselect-filter-input-padding-y' | '--gog-multiselect-filter-input-radius' | '--gog-multiselect-filter-padding' | '--gog-multiselect-float-label-in-top' | '--gog-multiselect-float-label-on-bg' | '--gog-multiselect-float-label-over-gap' | '--gog-multiselect-float-label-over-reserve' | '--gog-multiselect-float-label-reserve' | '--gog-multiselect-focus-border' | '--gog-multiselect-focus-glow' | '--gog-multiselect-focus-ring' | '--gog-multiselect-focus-ring-offset' | '--gog-multiselect-focus-ring-width' | '--gog-multiselect-font-family' | '--gog-multiselect-font-size' | '--gog-multiselect-gap' | '--gog-multiselect-label-color' | '--gog-multiselect-label-font-family' | '--gog-multiselect-label-font-size' | '--gog-multiselect-label-letter-spacing' | '--gog-multiselect-label-line-height' | '--gog-multiselect-label-text-transform' | '--gog-multiselect-mark-icon-ratio' | '--gog-multiselect-mark-size-ratio' | '--gog-multiselect-min-width' | '--gog-multiselect-option-color' | '--gog-multiselect-option-disabled-opacity' | '--gog-multiselect-option-gap' | '--gog-multiselect-option-gap-inline' | '--gog-multiselect-option-height' | '--gog-multiselect-option-hover-bg' | '--gog-multiselect-option-press-bg' | '--gog-multiselect-option-radius' | '--gog-multiselect-option-transition-duration' | '--gog-multiselect-options-padding' | '--gog-multiselect-overflow-color' | '--gog-multiselect-overflow-font-size' | '--gog-multiselect-overflow-gap' | '--gog-multiselect-overflow-line-height' | '--gog-multiselect-padding-x' | '--gog-multiselect-padding-y' | '--gog-multiselect-panel-bg' | '--gog-multiselect-panel-border' | '--gog-multiselect-panel-gap' | '--gog-multiselect-panel-max-height' | '--gog-multiselect-panel-max-width' | '--gog-multiselect-panel-radius' | '--gog-multiselect-panel-shadow' | '--gog-multiselect-placeholder-color' | '--gog-multiselect-radius' | '--gog-multiselect-transition-duration' | '--gog-multiselect-value-color' | '--gog-muted-text-color' | '--gog-paginator-ellipsis-color' | '--gog-paginator-ellipsis-font-family' | '--gog-paginator-ellipsis-font-size' | '--gog-paginator-ellipsis-line-height' | '--gog-paginator-ellipsis-min-width' | '--gog-paginator-gap' | '--gog-paginator-page-size-min-width' | '--gog-panel-bg' | '--gog-panel-border-color' | '--gog-panel-border-style' | '--gog-panel-border-width' | '--gog-panel-chevron-size' | '--gog-panel-color' | '--gog-panel-disabled-opacity' | '--gog-panel-elevated-bg' | '--gog-panel-elevated-border-color' | '--gog-panel-filled-bg' | '--gog-panel-filled-border-color' | '--gog-panel-filled-shadow' | '--gog-panel-focus-ring' | '--gog-panel-focus-ring-offset' | '--gog-panel-focus-ring-width' | '--gog-panel-font-family' | '--gog-panel-footer-border-color' | '--gog-panel-footer-gap' | '--gog-panel-footer-padding-top' | '--gog-panel-gap' | '--gog-panel-header-gap' | '--gog-panel-heading-color' | '--gog-panel-heading-font-family' | '--gog-panel-heading-font-size' | '--gog-panel-heading-font-weight' | '--gog-panel-heading-line-height' | '--gog-panel-lg-gap' | '--gog-panel-lg-padding-x' | '--gog-panel-lg-padding-y' | '--gog-panel-md-gap' | '--gog-panel-md-padding-x' | '--gog-panel-md-padding-y' | '--gog-panel-outlined-bg' | '--gog-panel-outlined-border-color' | '--gog-panel-outlined-shadow' | '--gog-panel-padding-x' | '--gog-panel-padding-y' | '--gog-panel-radius' | '--gog-panel-shadow' | '--gog-panel-slg-gap' | '--gog-panel-slg-padding-x' | '--gog-panel-slg-padding-y' | '--gog-panel-sm-gap' | '--gog-panel-sm-padding-x' | '--gog-panel-sm-padding-y' | '--gog-panel-toggle-color' | '--gog-panel-toggle-hover-bg' | '--gog-panel-toggle-radius' | '--gog-panel-toggle-size' | '--gog-panel-transition-duration' | '--gog-panel-xsm-gap' | '--gog-panel-xsm-padding-x' | '--gog-panel-xsm-padding-y' | '--gog-primary-color' | '--gog-progressbar-accent-bg' | '--gog-progressbar-accent-buffer-bg' | '--gog-progressbar-buffer-bg' | '--gog-progressbar-danger-bg' | '--gog-progressbar-danger-buffer-bg' | '--gog-progressbar-edge-backing-color' | '--gog-progressbar-edge-color' | '--gog-progressbar-edge-width' | '--gog-progressbar-fill-bg' | '--gog-progressbar-height' | '--gog-progressbar-indeterminate-duration' | '--gog-progressbar-indeterminate-easing' | '--gog-progressbar-info-bg' | '--gog-progressbar-info-buffer-bg' | '--gog-progressbar-lg-height' | '--gog-progressbar-md-height' | '--gog-progressbar-radius' | '--gog-progressbar-slg-height' | '--gog-progressbar-sm-height' | '--gog-progressbar-stripe-color' | '--gog-progressbar-stripe-size' | '--gog-progressbar-success-bg' | '--gog-progressbar-success-buffer-bg' | '--gog-progressbar-track-base-bg' | '--gog-progressbar-track-bg' | '--gog-progressbar-transition-duration' | '--gog-progressbar-value-color' | '--gog-progressbar-value-font-family' | '--gog-progressbar-value-font-size' | '--gog-progressbar-value-gap' | '--gog-progressbar-value-line-height' | '--gog-progressbar-value-min-width' | '--gog-progressbar-warning-bg' | '--gog-progressbar-warning-buffer-bg' | '--gog-progressbar-xsm-height' | '--gog-radio-bg' | '--gog-radio-border-color' | '--gog-radio-border-style' | '--gog-radio-border-width' | '--gog-radio-box-size' | '--gog-radio-checked-bg' | '--gog-radio-checked-border' | '--gog-radio-disabled-opacity' | '--gog-radio-dot-color' | '--gog-radio-dot-size-ratio' | '--gog-radio-error-color' | '--gog-radio-error-font-size' | '--gog-radio-error-line-height' | '--gog-radio-focus-ring' | '--gog-radio-focus-ring-offset' | '--gog-radio-focus-ring-width' | '--gog-radio-font-family' | '--gog-radio-gap' | '--gog-radio-group-gap' | '--gog-radio-group-label-color' | '--gog-radio-group-label-size' | '--gog-radio-group-option-gap' | '--gog-radio-group-option-gap-horizontal' | '--gog-radio-label-color' | '--gog-radio-label-line-height' | '--gog-radio-label-size' | '--gog-radio-padding' | '--gog-radio-transition-duration' | '--gog-radius' | '--gog-ripple-color' | '--gog-ripple-easing' | '--gog-ripple-enter-duration' | '--gog-ripple-exit-duration' | '--gog-ripple-opacity' | '--gog-scroll-corner-bg' | '--gog-scroll-fade-duration' | '--gog-scroll-focus-ring' | '--gog-scroll-focus-ring-width' | '--gog-scroll-normal-thumb-hit-padding' | '--gog-scroll-normal-thumb-min-size' | '--gog-scroll-normal-track-width' | '--gog-scroll-thin-thumb-hit-padding' | '--gog-scroll-thin-thumb-min-size' | '--gog-scroll-thin-track-width' | '--gog-scroll-thumb-active-bg' | '--gog-scroll-thumb-bg' | '--gog-scroll-thumb-hover-bg' | '--gog-scroll-thumb-inset' | '--gog-scroll-thumb-radius' | '--gog-scroll-track-bg' | '--gog-scroll-track-radius' | '--gog-secondary-color' | '--gog-select-chevron-color' | '--gog-select-chevron-icon-ratio' | '--gog-select-chevron-inset' | '--gog-select-clear-color' | '--gog-select-clear-gap' | '--gog-select-clear-hover-color' | '--gog-select-clear-icon-ratio' | '--gog-select-clear-line-height' | '--gog-select-clear-radius' | '--gog-select-control-font' | '--gog-select-control-gap' | '--gog-select-control-padding-x' | '--gog-select-control-padding-y' | '--gog-select-disabled-opacity' | '--gog-select-error-color' | '--gog-select-error-font-size' | '--gog-select-error-line-height' | '--gog-select-field-bg' | '--gog-select-field-border' | '--gog-select-field-border-style' | '--gog-select-field-border-width' | '--gog-select-field-color' | '--gog-select-filter-border-color' | '--gog-select-filter-border-style' | '--gog-select-filter-border-width' | '--gog-select-filter-empty-color' | '--gog-select-filter-empty-padding' | '--gog-select-filter-input-bg' | '--gog-select-filter-input-border' | '--gog-select-filter-input-color' | '--gog-select-filter-input-padding-x' | '--gog-select-filter-input-padding-y' | '--gog-select-filter-input-radius' | '--gog-select-filter-padding' | '--gog-select-float-label-in-top' | '--gog-select-float-label-on-bg' | '--gog-select-float-label-over-gap' | '--gog-select-float-label-over-reserve' | '--gog-select-float-label-reserve' | '--gog-select-focus-border' | '--gog-select-focus-glow' | '--gog-select-focus-ring' | '--gog-select-focus-ring-offset' | '--gog-select-focus-ring-width' | '--gog-select-font-family' | '--gog-select-gap' | '--gog-select-label-color' | '--gog-select-label-font-family' | '--gog-select-label-font-size' | '--gog-select-label-letter-spacing' | '--gog-select-label-line-height' | '--gog-select-label-text-transform' | '--gog-select-mark-icon-ratio' | '--gog-select-mark-size-ratio' | '--gog-select-min-width' | '--gog-select-option-color' | '--gog-select-option-disabled-opacity' | '--gog-select-option-gap' | '--gog-select-option-height' | '--gog-select-option-hover-bg' | '--gog-select-option-press-bg' | '--gog-select-option-radius' | '--gog-select-option-selected-color' | '--gog-select-option-transition-duration' | '--gog-select-options-padding' | '--gog-select-panel-bg' | '--gog-select-panel-gap' | '--gog-select-panel-max-height' | '--gog-select-panel-max-width' | '--gog-select-panel-radius' | '--gog-select-panel-shadow' | '--gog-select-placeholder-color' | '--gog-select-radius' | '--gog-select-transition-duration' | '--gog-skeleton-base' | '--gog-skeleton-circle-size-lg' | '--gog-skeleton-circle-size-md' | '--gog-skeleton-circle-size-slg' | '--gog-skeleton-circle-size-sm' | '--gog-skeleton-circle-size-xsm' | '--gog-skeleton-line-gap' | '--gog-skeleton-line-height-lg' | '--gog-skeleton-line-height-md' | '--gog-skeleton-line-height-slg' | '--gog-skeleton-line-height-sm' | '--gog-skeleton-line-height-xsm' | '--gog-skeleton-line-radius' | '--gog-skeleton-pulse-duration' | '--gog-skeleton-pulse-min-opacity' | '--gog-skeleton-radius' | '--gog-skeleton-rect-height-lg' | '--gog-skeleton-rect-height-md' | '--gog-skeleton-rect-height-slg' | '--gog-skeleton-rect-height-sm' | '--gog-skeleton-rect-height-xsm' | '--gog-skeleton-shine' | '--gog-skeleton-short-line-width' | '--gog-skeleton-square-radius' | '--gog-skeleton-wave-duration' | '--gog-slider-auto-width' | '--gog-slider-disabled-opacity' | '--gog-slider-error-color' | '--gog-slider-error-font-family' | '--gog-slider-error-font-size' | '--gog-slider-error-line-height' | '--gog-slider-fill-bg' | '--gog-slider-focus-ring' | '--gog-slider-focus-ring-width' | '--gog-slider-gap' | '--gog-slider-label-color' | '--gog-slider-label-font-family' | '--gog-slider-label-font-size' | '--gog-slider-label-letter-spacing' | '--gog-slider-label-line-height' | '--gog-slider-label-text-transform' | '--gog-slider-range-color' | '--gog-slider-range-font-size' | '--gog-slider-range-line-height' | '--gog-slider-thumb-bg' | '--gog-slider-thumb-border' | '--gog-slider-thumb-border-width' | '--gog-slider-thumb-glow-color' | '--gog-slider-thumb-glow-size' | '--gog-slider-thumb-radius' | '--gog-slider-thumb-size' | '--gog-slider-track-area-height' | '--gog-slider-track-bg' | '--gog-slider-track-border-color' | '--gog-slider-track-border-style' | '--gog-slider-track-border-width' | '--gog-slider-track-height' | '--gog-slider-track-radius' | '--gog-slider-value-color' | '--gog-slider-value-font-family' | '--gog-slider-value-font-size' | '--gog-slider-value-line-height' | '--gog-slider-value-min-width' | '--gog-slider-vertical-length' | '--gog-space-12' | '--gog-space-16' | '--gog-space-20' | '--gog-space-24' | '--gog-space-28' | '--gog-space-2xl' | '--gog-space-32' | '--gog-space-4' | '--gog-space-40' | '--gog-space-48' | '--gog-space-8' | '--gog-space-lg' | '--gog-space-md' | '--gog-space-sm' | '--gog-space-xs' | '--gog-spinner-arc-inner-color' | '--gog-spinner-arc-inner-dash' | '--gog-spinner-arc-inner-glow' | '--gog-spinner-arc-inner-opacity' | '--gog-spinner-arc-inner-pulse-opacity' | '--gog-spinner-arc-inner-stroke-compact' | '--gog-spinner-arc-outer-color' | '--gog-spinner-arc-outer-dash' | '--gog-spinner-arc-outer-glow' | '--gog-spinner-arc-outer-pulse-opacity' | '--gog-spinner-diamond-color' | '--gog-spinner-diamond-glow' | '--gog-spinner-diamond-opacity' | '--gog-spinner-glow-color' | '--gog-spinner-overlay-bg' | '--gog-spinner-overlay-blur' | '--gog-spinner-overlay-fade-duration' | '--gog-spinner-overlay-z' | '--gog-spinner-pulse-duration' | '--gog-spinner-ring-duration' | '--gog-spinner-ring-glow' | '--gog-spinner-ring-padding' | '--gog-spinner-rune-color' | '--gog-spinner-rune-font-family' | '--gog-spinner-rune-glow' | '--gog-spinner-rune-pulse-opacity' | '--gog-spinner-rune-size' | '--gog-spinner-size-lg' | '--gog-spinner-size-md' | '--gog-spinner-size-slg' | '--gog-spinner-size-sm' | '--gog-spinner-size-xsm' | '--gog-spinner-spin-duration' | '--gog-spinner-spin-slow-duration' | '--gog-spinner-ticks-duration' | '--gog-spinner-track-color' | '--gog-spinner-track-opacity' | '--gog-success-color' | '--gog-success-shade' | '--gog-success-text-color' | '--gog-surface-color' | '--gog-table-accent-bright' | '--gog-table-accent-color' | '--gog-table-border-color' | '--gog-table-border-style' | '--gog-table-border-width' | '--gog-table-empty-font-size' | '--gog-table-empty-line-height' | '--gog-table-empty-padding' | '--gog-table-focus-ring' | '--gog-table-focus-ring-width' | '--gog-table-font-family' | '--gog-table-footer-gap' | '--gog-table-footer-min-height' | '--gog-table-gap' | '--gog-table-header-bg' | '--gog-table-header-font-family' | '--gog-table-header-letter-spacing' | '--gog-table-header-text-transform' | '--gog-table-hover-bg' | '--gog-table-lg-padding-v' | '--gog-table-lg-td-font-size' | '--gog-table-lg-th-font-size' | '--gog-table-loading-opacity' | '--gog-table-loading-padding' | '--gog-table-md-padding-v' | '--gog-table-md-td-font-size' | '--gog-table-md-th-font-size' | '--gog-table-muted-color' | '--gog-table-num-col-width' | '--gog-table-num-font-size' | '--gog-table-num-line-height' | '--gog-table-numeric-font-family' | '--gog-table-padding-h' | '--gog-table-row-border-width' | '--gog-table-row-press-bg' | '--gog-table-row-transition-duration' | '--gog-table-select-col-width' | '--gog-table-selected-bg' | '--gog-table-slg-padding-v' | '--gog-table-slg-td-font-size' | '--gog-table-slg-th-font-size' | '--gog-table-sm-padding-v' | '--gog-table-sm-td-font-size' | '--gog-table-sm-th-font-size' | '--gog-table-sort-icon-opacity' | '--gog-table-sort-icon-size' | '--gog-table-sort-icon-width' | '--gog-table-surface' | '--gog-table-td-font-size' | '--gog-table-td-line-height' | '--gog-table-td-padding-v' | '--gog-table-text-color' | '--gog-table-th-font-size' | '--gog-table-th-inner-gap' | '--gog-table-th-line-height' | '--gog-table-th-padding-v' | '--gog-table-total-font-size' | '--gog-table-total-letter-spacing' | '--gog-table-total-line-height' | '--gog-table-total-text-transform' | '--gog-table-xsm-padding-v' | '--gog-table-xsm-td-font-size' | '--gog-table-xsm-th-font-size' | '--gog-tabs-active-color' | '--gog-tabs-disabled-opacity' | '--gog-tabs-focus-ring-color' | '--gog-tabs-focus-ring-offset' | '--gog-tabs-focus-ring-width' | '--gog-tabs-font-family' | '--gog-tabs-font-weight' | '--gog-tabs-gap' | '--gog-tabs-header-border-color' | '--gog-tabs-header-border-style' | '--gog-tabs-header-border-width' | '--gog-tabs-hover-color' | '--gog-tabs-icon-size' | '--gog-tabs-indicator-color' | '--gog-tabs-indicator-radius' | '--gog-tabs-indicator-thickness' | '--gog-tabs-letter-spacing' | '--gog-tabs-lg-font-size' | '--gog-tabs-lg-padding' | '--gog-tabs-line-height' | '--gog-tabs-md-font-size' | '--gog-tabs-md-padding' | '--gog-tabs-panel-color' | '--gog-tabs-panel-padding' | '--gog-tabs-press-bg' | '--gog-tabs-press-color' | '--gog-tabs-rest-bg' | '--gog-tabs-rest-color' | '--gog-tabs-slg-font-size' | '--gog-tabs-slg-padding' | '--gog-tabs-sm-font-size' | '--gog-tabs-sm-padding' | '--gog-tabs-tab-bg' | '--gog-tabs-tab-color' | '--gog-tabs-tab-font-size' | '--gog-tabs-tab-gap' | '--gog-tabs-tab-padding' | '--gog-tabs-text-transform' | '--gog-tabs-transition-duration' | '--gog-tabs-xsm-font-size' | '--gog-tabs-xsm-padding' | '--gog-tag-accent' | '--gog-tag-bg' | '--gog-tag-bg-base' | '--gog-tag-bg-mix' | '--gog-tag-border' | '--gog-tag-border-style' | '--gog-tag-border-width' | '--gog-tag-color' | '--gog-tag-color-base' | '--gog-tag-color-mix' | '--gog-tag-danger-color' | '--gog-tag-default-color' | '--gog-tag-font-family' | '--gog-tag-font-size' | '--gog-tag-font-weight' | '--gog-tag-gap' | '--gog-tag-icon-size' | '--gog-tag-info-color' | '--gog-tag-inner-border-width' | '--gog-tag-lg-font-size' | '--gog-tag-lg-gap' | '--gog-tag-lg-icon-size' | '--gog-tag-lg-padding-block' | '--gog-tag-lg-padding-inline' | '--gog-tag-line-height' | '--gog-tag-md-font-size' | '--gog-tag-md-gap' | '--gog-tag-md-icon-size' | '--gog-tag-md-padding-block' | '--gog-tag-md-padding-inline' | '--gog-tag-padding-block' | '--gog-tag-padding-inline' | '--gog-tag-pill-radius' | '--gog-tag-radius' | '--gog-tag-slg-font-size' | '--gog-tag-slg-gap' | '--gog-tag-slg-icon-size' | '--gog-tag-slg-padding-block' | '--gog-tag-slg-padding-inline' | '--gog-tag-sm-font-size' | '--gog-tag-sm-gap' | '--gog-tag-sm-icon-size' | '--gog-tag-sm-padding-block' | '--gog-tag-sm-padding-inline' | '--gog-tag-success-color' | '--gog-tag-warning-color' | '--gog-tag-xsm-font-size' | '--gog-tag-xsm-gap' | '--gog-tag-xsm-icon-size' | '--gog-tag-xsm-padding-block' | '--gog-tag-xsm-padding-inline' | '--gog-text-2xl' | '--gog-text-2xs' | '--gog-text-3xl' | '--gog-text-color' | '--gog-text-lg' | '--gog-text-md' | '--gog-text-slg' | '--gog-text-sm' | '--gog-text-transform' | '--gog-text-xl' | '--gog-text-xs' | '--gog-textarea-clear-icon-ratio' | '--gog-textarea-line-height' | '--gog-textarea-resize-grip-color' | '--gog-textarea-resize-grip-offset' | '--gog-textarea-resize-grip-opacity' | '--gog-textarea-resize-grip-size' | '--gog-textarea-resize-grip-stripe-gap' | '--gog-textarea-resize-grip-stripe-width' | '--gog-textarea-resize-inset-bottom' | '--gog-textarea-resize-inset-right' | '--gog-textarea-scrollbar-width' | '--gog-toast-accent-width' | '--gog-toast-action-font-size' | '--gog-toast-action-line-height' | '--gog-toast-action-padding' | '--gog-toast-actions-gap' | '--gog-toast-base-z' | '--gog-toast-bg' | '--gog-toast-border' | '--gog-toast-close-font-size' | '--gog-toast-close-line-height' | '--gog-toast-close-padding' | '--gog-toast-color' | '--gog-toast-content-gap' | '--gog-toast-enter-distance' | '--gog-toast-error-color' | '--gog-toast-font-family' | '--gog-toast-icon-color' | '--gog-toast-icon-line-height' | '--gog-toast-icon-size' | '--gog-toast-info-color' | '--gog-toast-main-gap' | '--gog-toast-max-width' | '--gog-toast-message-font-size' | '--gog-toast-message-line-height' | '--gog-toast-min-width' | '--gog-toast-padding' | '--gog-toast-progress-height' | '--gog-toast-progress-opacity' | '--gog-toast-radius' | '--gog-toast-shadow' | '--gog-toast-stack-expanded-gap' | '--gog-toast-stack-max-depth' | '--gog-toast-stack-min-opacity' | '--gog-toast-stack-opacity-step' | '--gog-toast-stack-padding' | '--gog-toast-stack-peek' | '--gog-toast-stack-scale-step' | '--gog-toast-success-color' | '--gog-toast-transition-duration' | '--gog-toast-warning-color' | '--gog-toast-z-index' | '--gog-toggle-border-color' | '--gog-toggle-border-style' | '--gog-toggle-border-width' | '--gog-toggle-disabled-opacity' | '--gog-toggle-focus-ring-color' | '--gog-toggle-focus-ring-offset' | '--gog-toggle-focus-ring-width' | '--gog-toggle-font-family' | '--gog-toggle-gap' | '--gog-toggle-label-color' | '--gog-toggle-label-line-height' | '--gog-toggle-lg-label-size' | '--gog-toggle-lg-state-font-size' | '--gog-toggle-lg-thumb-size' | '--gog-toggle-lg-track-height' | '--gog-toggle-lg-track-width' | '--gog-toggle-md-label-size' | '--gog-toggle-md-state-font-size' | '--gog-toggle-md-thumb-size' | '--gog-toggle-md-track-height' | '--gog-toggle-md-track-width' | '--gog-toggle-on-border-color' | '--gog-toggle-padding' | '--gog-toggle-radius' | '--gog-toggle-slg-label-size' | '--gog-toggle-slg-state-font-size' | '--gog-toggle-slg-thumb-size' | '--gog-toggle-slg-track-height' | '--gog-toggle-slg-track-width' | '--gog-toggle-sm-label-size' | '--gog-toggle-sm-state-font-size' | '--gog-toggle-sm-thumb-size' | '--gog-toggle-sm-track-height' | '--gog-toggle-sm-track-width' | '--gog-toggle-state-color' | '--gog-toggle-state-font-weight' | '--gog-toggle-state-letter-spacing' | '--gog-toggle-state-line-height' | '--gog-toggle-state-offset' | '--gog-toggle-state-padding-inline' | '--gog-toggle-state-thumb-gap' | '--gog-toggle-thumb-bg' | '--gog-toggle-thumb-inset' | '--gog-toggle-thumb-off-bg' | '--gog-toggle-thumb-on-bg' | '--gog-toggle-thumb-shadow' | '--gog-toggle-track-bg' | '--gog-toggle-track-off-bg' | '--gog-toggle-track-on-bg' | '--gog-toggle-transition-duration' | '--gog-toggle-xsm-label-size' | '--gog-toggle-xsm-state-font-size' | '--gog-toggle-xsm-thumb-size' | '--gog-toggle-xsm-track-height' | '--gog-toggle-xsm-track-width' | '--gog-tooltip-arrow-size' | '--gog-tooltip-bg' | '--gog-tooltip-border-color' | '--gog-tooltip-border-style' | '--gog-tooltip-border-width' | '--gog-tooltip-color' | '--gog-tooltip-font-family' | '--gog-tooltip-font-size' | '--gog-tooltip-gap' | '--gog-tooltip-line-height' | '--gog-tooltip-max-height' | '--gog-tooltip-max-width' | '--gog-tooltip-padding' | '--gog-tooltip-radius' | '--gog-tooltip-shadow' | '--gog-tooltip-transition-duration' | '--gog-tooltip-z' | '--gog-warning-color' | '--gog-warning-shade' | '--gog-warning-text-color' | '--gog-z-base';
1690
+ /** Which of the three layers a token belongs to — see the README's theming section. */
1691
+ type GogTokenLayer = 'foundation' | 'component' | 'instance';
1692
+ interface GogTokenGroup {
1693
+ /** The `── Section ──` heading the token sits under in theme.css. */
1694
+ readonly section: string;
1695
+ readonly layer: GogTokenLayer;
1696
+ readonly tokens: readonly GogTokenName[];
1697
+ }
1698
+ /**
1699
+ * The token catalogue, grouped as theme.css groups it. Exported so a theme editor or docs page
1700
+ * can enumerate the real tokens instead of keeping a hand-copied list that drifts.
1701
+ */
1702
+ declare const GOG_TOKEN_GROUPS: readonly GogTokenGroup[];
1703
+
1704
+ /**
1705
+ * Reading a `--gog-*` token's value from TypeScript, safely.
1706
+ *
1707
+ * **The trap these exist for.** `getComputedStyle(el).getPropertyValue('--x')` returns a custom
1708
+ * property's *specified* value, not a used one. A token declared
1709
+ * `calc(10px * var(--gog-density))` comes back as that whole string, and `Number.parseFloat` on
1710
+ * it returns `NaN` — which every caller in this library turned into its fallback, silently. No
1711
+ * error, no failing test, just a component quietly using the wrong number.
1712
+ *
1713
+ * That is not hypothetical. 21.7.0's density scale (`docs/themes.md` iteration 6) made 178
1714
+ * tokens `calc(<n>px * var(--gog-density))`; none of the three tokens read from TypeScript were
1715
+ * among them, but nothing stopped the next one from being. And a **consumer** can write
1716
+ * `--gog-scroll-thumb-min-size: calc(2rem + 4px)` in their own theme at any time, which no
1717
+ * repo-side check could ever catch.
1718
+ *
1719
+ * So these resolve rather than parse: the fast path still handles a plain `12px`, and anything
1720
+ * else is handed to the browser on a throwaway element, which also gets `rem`, `em`, `%` and
1721
+ * nested `var()` right for free. The probe is appended to the element the token was read from,
1722
+ * so relative units resolve against the same context the real value would.
1723
+ */
1724
+ /** Reads a length token in pixels. Returns `fallback` for an empty, unparseable or zero value. */
1725
+ declare function resolveLengthToken(el: HTMLElement, token: string, fallback: number): number;
1726
+ /**
1727
+ * Reads a unitless numeric token (a `z-index`). Same resolution path as lengths — `z-index`
1728
+ * takes an integer, so the browser computes `calc()` there too.
1729
+ */
1730
+ declare function resolveNumberToken(el: HTMLElement, token: string, fallback: number): number;
1731
+
1732
+ type GogTooltipSide = 'top' | 'bottom' | 'left' | 'right';
1733
+ /** Writing direction of the element a placement is resolved against. */
1734
+ type GogWritingDirection = 'ltr' | 'rtl';
1735
+ interface GogTooltipTargetRect {
1736
+ top: number;
1737
+ bottom: number;
1738
+ left: number;
1739
+ right: number;
1740
+ width: number;
1741
+ height: number;
1742
+ }
1743
+ interface GogTooltipSize {
1744
+ width: number;
1745
+ height: number;
1746
+ }
1747
+ interface GogTooltipViewport {
1748
+ width: number;
1749
+ height: number;
1750
+ }
1751
+ interface GogTooltipPlacement {
1752
+ side: GogTooltipSide;
1753
+ top: number;
1754
+ left: number;
1755
+ }
1756
+ /**
1757
+ * Picks which side the bubble renders on. `'auto'` tries top, bottom, then the two horizontal
1758
+ * sides — top-first matches the conventional tooltip default — and falls back to whichever
1759
+ * side has the most room if the bubble doesn't fully fit anywhere. An explicit side flips to
1760
+ * its opposite when it has no room but the opposite does, same as `resolveDropdownDirection`
1761
+ * does for up/down; unlike that helper, a request for a specific side is honoured as-is
1762
+ * (no flip) whenever it fits, since the caller asked for that side deliberately.
1763
+ *
1764
+ * **`direction` mirrors the horizontal preference only.** In RTL, `'auto'` prefers the left
1765
+ * side where LTR prefers the right, so a tooltip opens away from the text it belongs to in the
1766
+ * same way in both. An explicit `'left'`/`'right'` is *not* mirrored: those are physical words
1767
+ * in a physical API, and a consumer who wrote `position="right"` meant the right of the screen.
1768
+ * `'start'`/`'end'` would be the logical spelling, and there is deliberately no such value —
1769
+ * `'auto'` already does the right thing for a direction-aware layout.
1770
+ */
1771
+ declare function resolveTooltipSide(position: GogTooltipPosition, target: GogTooltipTargetRect, bubble: GogTooltipSize, viewport: GogTooltipViewport, gap?: number, viewportPadding?: number, direction?: GogWritingDirection): GogTooltipSide;
1772
+ /**
1773
+ * Resolves the bubble's side and its `position: fixed` top/left, centered on the target's
1774
+ * midpoint along the cross axis and clamped so it never renders past the viewport edge —
1775
+ * the centering can push it there for a target near a corner.
1776
+ */
1777
+ declare function resolveTooltipPlacement(position: GogTooltipPosition, target: GogTooltipTargetRect, bubble: GogTooltipSize, viewport: GogTooltipViewport, gap?: number, viewportPadding?: number, direction?: GogWritingDirection): GogTooltipPlacement;
1778
+
1779
+ /** The slice of a list that is worth rendering, as indices into the full list. */
1780
+ interface GogVirtualRange {
1781
+ /** First index to render, inclusive. */
1782
+ readonly start: number;
1783
+ /** One past the last index to render, so `slice(start, end)` is the window. */
1784
+ readonly end: number;
1785
+ }
1786
+ /** What `GogVirtualWindow` needs to do its arithmetic. Every input is a signal it reads. */
1787
+ interface GogVirtualWindowInputs {
1788
+ /** How many rows the list has in total — not how many are rendered. */
1789
+ readonly count: Signal<number>;
1790
+ /**
1791
+ * One row's height in px, measured rather than assumed.
1792
+ *
1793
+ * The library learned this the expensive way: `--gog-*-option-height` described itself as an
1794
+ * estimate and was wrong in all eleven shipped themes, low by up to 8.38px a row, while a
1795
+ * placement decision depended on it. A window is far less forgiving than a placement — the error
1796
+ * accumulates once per row — so this takes a number that came from `getBoundingClientRect`.
1797
+ */
1798
+ readonly rowHeight: Signal<number>;
1799
+ /** The scroller's visible height in px. Not the panel's max-height, which is a cap. */
1800
+ readonly viewportHeight: Signal<number>;
1801
+ /** How far the scroller is scrolled, in px. */
1802
+ readonly scrollTop: Signal<number>;
1803
+ /**
1804
+ * Rows rendered beyond each edge of the viewport, so a scroll does not expose blank space
1805
+ * before the next frame lands. Defaults to 4.
1806
+ */
1807
+ readonly overscan?: number;
1808
+ }
1809
+ /**
1810
+ * The arithmetic behind a windowed list, and nothing else.
1811
+ *
1812
+ * **No DOM, no template, no scroll listener.** The component that uses this owns its scroller —
1813
+ * the three dropdowns already own theirs (a `gog-scroll` inside the panel) and `gog-table` owns a
1814
+ * different one — so a primitive that grabbed an element would have to be told which, and would
1815
+ * still not know when that element moved. It reads signals and returns numbers; everything that
1816
+ * touches the page stays in the component.
1817
+ *
1818
+ * That is the same division `GogRippleController` made, for the reason `docs/ripple.md` records:
1819
+ * the engine lives beside the components rather than inside a directive, because the things that
1820
+ * need it cannot all reach a directive through `hostDirectives`.
1821
+ *
1822
+ * ```ts
1823
+ * private readonly window = new GogVirtualWindow({
1824
+ * count: computed(() => this.visibleOptions().length),
1825
+ * rowHeight: this.measuredRowHeight,
1826
+ * viewportHeight: this.panelHeight,
1827
+ * scrollTop: this.panelScrollTop,
1828
+ * });
1829
+ * // window.range() -> { start, end }
1830
+ * // window.padBefore() / window.padEnd() -> px of filler above and below the rendered slice
1831
+ * ```
1832
+ *
1833
+ * **Why padding rather than absolute positioning.** A spacer above and below the rendered rows
1834
+ * keeps the list in normal flow, so the rows stay `display: flex` children of the same container
1835
+ * and every selector, gap and `:last-child` a component already relies on keeps working. Absolute
1836
+ * positioning each row is the other common shape and it changes what the component's own CSS
1837
+ * means, which is a large price for a list that is one column wide.
1838
+ *
1839
+ * @see docs/virtualization.md — the plan, its measurements, and what still has to be got right in
1840
+ * the components that adopt this (ARIA counts, keyboard reach, panel height, filter resets).
1841
+ */
1842
+ declare class GogVirtualWindow {
1843
+ private readonly inputs;
1844
+ private readonly overscan;
1845
+ constructor(inputs: GogVirtualWindowInputs);
1846
+ /**
1847
+ * The total height the list would have if every row were rendered. What the scroller needs to
1848
+ * believe so its thumb is the right size and `scrollTop` spans the whole list.
1849
+ */
1850
+ readonly totalHeight: Signal<number>;
1851
+ /**
1852
+ * The slice worth rendering.
1853
+ *
1854
+ * **Degrades to the whole list rather than to nothing.** A row height of zero is what a caller
1855
+ * has before it has measured anything, and a window computed from it would be `{0, 0}` — an
1856
+ * empty panel that looks like a bug and hides the data. Rendering everything is the pre-window
1857
+ * behaviour, which is slow and correct; that is the right way round for a fallback.
1858
+ */
1859
+ readonly range: Signal<GogVirtualRange>;
1860
+ /** Filler above the rendered slice, in px, so the rows sit where their indices say. */
1861
+ readonly padBefore: Signal<number>;
1862
+ /** Filler below, in px. Derived from the total so rounding cannot leave a gap. */
1863
+ readonly padAfter: Signal<number>;
1864
+ /**
1865
+ * Where the scroller has to be for `index` to be fully visible, or `null` if it already is.
1866
+ *
1867
+ * This is what keyboard navigation needs: arrowing to a row outside the window is a scroll
1868
+ * first and a focus move second, because the element does not exist until the scroll has
1869
+ * re-rendered the slice. Returning `null` rather than the current position lets a caller skip
1870
+ * the scroll entirely, which matters because scrolling when nothing needs to move cancels a
1871
+ * user's own in-progress scroll in some browsers.
1872
+ */
1873
+ scrollOffsetFor(index: number): number | null;
1874
+ /** Guards against the shapes a caller can legitimately be in before it has measured anything. */
1875
+ private safeCount;
1876
+ private safeRowHeight;
1877
+ private safeViewportHeight;
1878
+ private safeScrollTop;
1879
+ }
1880
+
1881
+ /** What `GogVariableWindow` needs. Every input is a signal it reads. */
1882
+ interface GogVariableWindowInputs {
1883
+ /** How many rows the list has in total — not how many are rendered. */
1884
+ readonly count: Signal<number>;
1885
+ /**
1886
+ * The height in px to assume for a row that has never been measured.
1887
+ *
1888
+ * Seeded from the first row the caller measures rather than from a token: `gog-table`'s row
1889
+ * height is padding plus leading plus a border, and `docs/virtualization.md`'s iteration 0
1890
+ * measured the equivalent token wrong in all eleven shipped themes.
1891
+ */
1892
+ readonly estimatedRowHeight: Signal<number>;
1893
+ /** The scroller's visible height in px. Not a `max-height`, which is a cap. */
1894
+ readonly viewportHeight: Signal<number>;
1895
+ /** How far the scroller is scrolled, in px. */
1896
+ readonly scrollTop: Signal<number>;
1897
+ /**
1898
+ * Rows rendered beyond each edge of the viewport, so a scroll does not expose blank space
1899
+ * before the next frame lands. Defaults to 4.
1900
+ */
1901
+ readonly overscan?: number;
1902
+ }
1903
+ /**
1904
+ * The arithmetic behind a windowed list whose rows are **not** all the same height.
1905
+ *
1906
+ * `GogVirtualWindow` is the one to reach for wherever the rows are uniform — it is exact, it needs
1907
+ * no measurements, and a multiplication beats a binary search. This exists because `gog-table`
1908
+ * cannot use it, for a reason that is a fact about CSS rather than about this library:
1909
+ *
1910
+ * **A table row's height cannot be pinned.** `height` on a `<tr>` or a `<td>` is a *minimum* in
1911
+ * table layout, so a cell whose content wraps makes its row taller and nothing can stop it — one
1912
+ * cell taken from 40 to 600 characters measured 39px → 173.75px, under `table-layout: fixed`, with
1913
+ * the column width unchanged. A single-pitch window cannot describe that list.
1914
+ *
1915
+ * So this holds a height per row: the measured one where a row has ever been rendered, and an
1916
+ * estimate everywhere else. `range()` is then a binary search over the prefix sums rather than a
1917
+ * division.
1918
+ *
1919
+ * **Being an estimate is the whole difficulty**, and it lives in `applyMeasurements`, not here.
1920
+ * See its note: correcting a row *above* the viewport moves everything below it, under the reader,
1921
+ * while they scroll — so the correction has to be reported as a scroll delta and applied in the
1922
+ * same frame.
1923
+ *
1924
+ * @see docs/table-virtualization.md — the survey behind this, and what adopting it has to get right
1925
+ */
1926
+ declare class GogVariableWindow {
1927
+ private readonly inputs;
1928
+ private readonly overscan;
1929
+ /**
1930
+ * Measured heights by row index, `undefined` where a row has never been rendered.
1931
+ *
1932
+ * A sparse array rather than a `Map`: the index *is* the key, the reads are sequential, and the
1933
+ * prefix sum walks it start to finish either way.
1934
+ */
1935
+ private readonly measured;
1936
+ constructor(inputs: GogVariableWindowInputs);
1937
+ /**
1938
+ * Running total of row heights: `offsets[i]` is where row `i` starts, and `offsets[count]` is
1939
+ * the list's full height.
1940
+ *
1941
+ * Recomputed whole rather than patched. It is O(n) on a signal that changes only when a
1942
+ * measurement actually differs, and an incremental structure here would be a Fenwick tree
1943
+ * guarding a loop that costs a fraction of the layout it feeds.
1944
+ */
1945
+ private readonly offsets;
1946
+ /** What the scroller has to believe, so its thumb is the right size. */
1947
+ readonly totalHeight: Signal<number>;
1948
+ /**
1949
+ * The slice worth rendering.
1950
+ *
1951
+ * **Degrades to the whole list rather than to nothing**, the same rule `GogVirtualWindow`
1952
+ * follows and for the same reason: a caller that has not measured anything yet has an estimate
1953
+ * of zero, and a window computed from it renders an empty panel that reads as broken. Rendering
1954
+ * everything is the pre-window behaviour — slow, and correct.
1955
+ */
1956
+ readonly range: Signal<GogVirtualRange>;
1957
+ /** Filler above the rendered slice, in px, so the rows sit where their offsets say. */
1958
+ readonly padBefore: Signal<number>;
1959
+ /** Filler below, in px. Derived from the total so rounding cannot leave a gap. */
1960
+ readonly padAfter: Signal<number>;
1961
+ /**
1962
+ * Records what the rendered rows actually measured, and returns **how far the content above the
1963
+ * viewport moved** — which the caller must add to the scroller's `scrollTop`, in the same frame.
1964
+ *
1965
+ * This is the whole difficulty of a variable window, and it is not obvious from the arithmetic.
1966
+ * Every row starts as an estimate. The moment one is measured and disagrees, every row after it
1967
+ * shifts by the difference — including, when the corrected row is *above* the viewport, the rows
1968
+ * the reader is looking at. Scroll up into a region of taller-than-estimated rows and the
1969
+ * content jumps away from the pointer on every frame; the list appears to fight the scroll.
1970
+ *
1971
+ * Adding the delta back to `scrollTop` holds the visible rows still: the content moved down by
1972
+ * `delta`, so the viewport moves down by `delta` too and the same pixels stay under the reader.
1973
+ *
1974
+ * `heights[i]` is keyed by **real row index**, and a `0` or a negative is ignored rather than
1975
+ * stored — an unlaid-out row measures zero, and believing it would collapse the list.
1976
+ */
1977
+ applyMeasurements(heights: ReadonlyMap<number, number>): number;
1978
+ /**
1979
+ * Drops every measurement. For when the rows stop describing the same data — a new page, a new
1980
+ * sort, a filter — after which a cached height belongs to a row that is no longer there.
1981
+ */
1982
+ reset(): void;
1983
+ /** Where the scroller has to be for `index` to be fully visible, or `null` if it already is. */
1984
+ scrollOffsetFor(index: number): number | null;
1985
+ /**
1986
+ * The index of the row containing `position`, by binary search over the offsets.
1987
+ *
1988
+ * Returns the **last** index whose start is `<= position`, clamped to the list. A linear scan
1989
+ * would be fine at a thousand rows and is not at the hundreds of thousands this exists for, and
1990
+ * it runs on every scroll frame.
1991
+ */
1992
+ private indexAt;
1993
+ private safeCount;
1994
+ private safeEstimate;
1995
+ private safeViewportHeight;
1996
+ private safeScrollTop;
1997
+ }
1998
+
1999
+ export { DEFAULT_RIPPLE, GOG_CHECKABLE_CONTROL_PADDING, GOG_CHECKABLE_CONTROL_SIZE_MAP, GOG_CONFIG, GOG_DEPRECATIONS, GOG_ICONS, GOG_TOKEN_GROUPS, GogClearableState, GogDropdownBase, GogDropdownChevronDirective, GogDropdownOptionDirective, GogDropdownOverlay, GogErrorState, GogFloatLabelState, GogVariableWindow, GogVirtualWindow, ICON_DEFS, addDays, addMonths, addYears, buildMonthGrid, clampDate, copyTimeOnto, daysInMonth, formatDate, getByPath, handleRovingFocusKeydown, isAfterDay, isBeforeDay, isInRange, isRovingFocusKey, isSameDay, isSameMonth, isSameOptionValue, isWithinBounds, localeFirstDayOfWeek, monthNames, nextGogControlId, nextRovingFocusIndex, parseDate, provideGogConfig, provideGogIcons, readOption, resolveConfigured, resolveCssLengthPx, resolveDropdownDirection, resolveDropdownPlacement, resolveLengthToken, resolveNumberToken, resolveRipple, resolveTooltipPlacement, resolveTooltipSide, scopedOverlayDirection, scopedOverlayTheme, startOfDay, weekdayNames, withTime };
2000
+ export type { GogAlertLive, GogAriaHasPopup, GogBadgePosition, GogBuiltinIconName, GogButtonToggleAppearance, GogCheckableControlSizeConfig, GogDateRange, GogDateSelectionMode, GogDeprecation, GogDeprecationKind, GogDividerVariant, GogDropdownDirection, GogDropdownFilterPosition, GogDropdownOption, GogDropdownOptionContext, GogDropdownPlacement, GogDropdownTriggerRect, GogErrorDisplay, GogFloatLabelVariant, GogGlobalConfig, GogHourFormat, GogIconName, GogInputMode, GogInputType, GogOptionAccessor, GogOrientation, GogPaginatorRangeMode, GogProgressbarMode, GogProgressbarVariant, GogScrollAxis, GogScrollOverscrollBehavior, GogScrollSize, GogSeverity, GogSize, GogSkeletonAnimation, GogSkeletonShape, GogSliderOrientation, GogSliderRange, GogSpinnerVariant, GogSurfaceVariant, GogTabsAlign, GogTagShape, GogTagVariant, GogTextareaResize, GogTokenGroup, GogTokenLayer, GogTokenName, GogTooltipPlacement, GogTooltipPosition, GogTooltipSide, GogTooltipSize, GogTooltipTargetRect, GogTooltipViewport, GogVariableWindowInputs, GogVariant, GogVirtualRange, GogVirtualWindowInputs, GogWritingDirection, RovingFocusKey, ToastPosition };