@guildofgleks/ui 21.3.2 → 21.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, input, ChangeDetectionStrategy, Component, output, computed, DestroyRef, TemplateRef, Directive, model, contentChild, ElementRef, signal, effect, untracked, PLATFORM_ID, ApplicationRef, viewChild, afterNextRender, booleanAttribute, Renderer2, viewChildren, contentChildren, forwardRef, Injectable, Injector, afterRenderEffect, ViewContainerRef, linkedSignal } from '@angular/core';
2
+ import { InjectionToken, inject, input, ChangeDetectionStrategy, Component, output, computed, DestroyRef, booleanAttribute, Directive, isDevMode, TemplateRef, model, contentChild, ElementRef, signal, effect, untracked, PLATFORM_ID, ApplicationRef, viewChild, afterNextRender, Renderer2, viewChildren, contentChildren, forwardRef, Injectable, Injector, afterRenderEffect, ViewContainerRef, linkedSignal } from '@angular/core';
3
3
  import { Subject, timer } from 'rxjs';
4
4
  import { throttle } from 'rxjs/operators';
5
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@@ -118,7 +118,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
118
118
 
119
119
  const DEFAULT_DEBOUNCE = 300;
120
120
  /** Built-in default, used when neither the instance input nor `GOG_CONFIG` supplies one. */
121
- const DEFAULT_SIZE$9 = 'md';
121
+ const DEFAULT_SIZE$a = 'md';
122
122
  class ButtonComponent {
123
123
  variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
124
124
  /** Unset, falls back to `GOG_CONFIG.control.size`, then to `'md'`. */
@@ -157,7 +157,7 @@ class ButtonComponent {
157
157
  };
158
158
  globalConfig = inject(GOG_CONFIG);
159
159
  /** Instance input → `GOG_CONFIG` → the component's own default. See `resolveConfigured`. */
160
- resolvedSize = computed(() => resolveConfigured(this.size(), this.globalConfig.control?.size, DEFAULT_SIZE$9), ...(ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []));
160
+ resolvedSize = computed(() => resolveConfigured(this.size(), this.globalConfig.control?.size, DEFAULT_SIZE$a), ...(ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []));
161
161
  spinnerSize = computed(() => ButtonComponent.SPINNER_SIZE_BY_BUTTON_SIZE[this.resolvedSize()], ...(ngDevMode ? [{ debugName: "spinnerSize" }] : /* istanbul ignore next */ []));
162
162
  resolvedDebounce = computed(() => resolveConfigured(this.debounce(), this.globalConfig.button?.debounce, DEFAULT_DEBOUNCE), ...(ngDevMode ? [{ debugName: "resolvedDebounce" }] : /* istanbul ignore next */ []));
163
163
  /**
@@ -178,7 +178,7 @@ class ButtonComponent {
178
178
  this.click$.next(event);
179
179
  }
180
180
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
181
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ButtonComponent, isStandalone: true, selector: "gog-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { gogClick: "gogClick" }, host: { properties: { "class.gog-host--full-width": "fullWidth()" } }, ngImport: i0, template: "<button\r\n (click)=\"onClick($event)\"\r\n [attr.aria-busy]=\"loading() ? 'true' : null\"\r\n [attr.aria-disabled]=\"isDisabled() && !isNativeDisabled() ? 'true' : null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.disabled]=\"isNativeDisabled() ? true : null\"\r\n [class.gog-btn--ghost]=\"variant() === 'ghost'\"\r\n [class.gog-btn--loading]=\"loading()\"\r\n [class.gog-btn--outline]=\"variant() === 'outline'\"\r\n [class.gog-btn--primary]=\"variant() === 'primary'\"\r\n [class.gog-btn--secondary]=\"variant() === 'secondary'\"\r\n [class.gog-cursor-not-allowed]=\"isDisabled()\"\r\n [class.gog-cursor-pointer]=\"!isDisabled()\"\r\n [class.gog-cursor-wait]=\"loading()\"\r\n [type]=\"type()\"\r\n class=\"gog-btn gog-inline-center gog-contained-layout\"\r\n [class]=\"sizeClass()\"\r\n>\r\n @if (loading()) {\r\n <gog-spinner [size]=\"spinnerSize()\" aria-hidden=\"true\" class=\"gog-btn__spinner\" />\r\n }\r\n\r\n <span [class.gog-btn__content--hidden]=\"loading()\" class=\"gog-btn__content\">\r\n <ng-content></ng-content>\r\n </span>\r\n</button>\r\n", styles: [".gog-btn{--gog-spinner-color: var( --gog-btn-spinner-color, var(--gog-btn-variant-spinner-color, var(--gog-btn-primary-spinner-color)) );gap:var(--gog-btn-gap);border:var(--gog-btn-border-width) var(--gog-btn-border-style) var(--gog-btn-border, var(--gog-btn-variant-border, var(--gog-btn-primary-border)));border-radius:var(--gog-btn-radius);padding:var(--gog-btn-padding, var(--gog-btn-size-padding, var(--gog-btn-md-padding)));font-family:var(--gog-btn-font-family);font-weight:var(--gog-btn-font-weight);font-size:var(--gog-btn-font-size, var(--gog-btn-size-font-size, var(--gog-btn-md-font-size)));letter-spacing:var(--gog-btn-letter-spacing);text-transform:var(--gog-btn-text-transform);line-height:var(--gog-btn-line-height);background-color:var(--gog-btn-bg, var(--gog-btn-variant-bg, var(--gog-btn-primary-bg)));color:var(--gog-btn-color, var(--gog-btn-variant-color, var(--gog-btn-primary-color)));box-shadow:var(--gog-btn-shadow, var(--gog-btn-variant-shadow, var(--gog-btn-primary-shadow)));cursor:pointer;transition:background-color var(--gog-btn-transition-duration) var(--gog-easing),box-shadow var(--gog-btn-transition-duration) var(--gog-easing),color var(--gog-btn-transition-duration) var(--gog-easing)}.gog-btn:focus-visible{outline:var(--gog-btn-focus-ring-width) solid var(--gog-btn-hover-bg, var(--gog-btn-variant-hover-bg, var(--gog-btn-primary-hover-bg)));outline-offset:var(--gog-btn-focus-ring-offset)}.gog-btn:hover:not(:disabled){background-color:var(--gog-btn-hover-bg, var(--gog-btn-variant-hover-bg, var(--gog-btn-primary-hover-bg)));color:var(--gog-btn-hover-color, var(--gog-btn-variant-hover-color, var(--gog-btn-primary-hover-color)));box-shadow:var(--gog-btn-hover-shadow, var(--gog-btn-variant-hover-shadow, var(--gog-btn-primary-hover-shadow)))}.gog-btn:active:not(:disabled){transform:scale(var(--gog-btn-active-scale))}@media(prefers-reduced-motion:reduce){.gog-btn{transition:none}.gog-btn:active:not(:disabled){transform:none}}.gog-btn:disabled{opacity:var(--gog-btn-disabled-opacity);cursor:not-allowed}.gog-btn--primary{--gog-btn-variant-bg: var(--gog-btn-primary-bg);--gog-btn-variant-color: var(--gog-btn-primary-color);--gog-btn-variant-border: var(--gog-btn-primary-border);--gog-btn-variant-shadow: var(--gog-btn-primary-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-primary-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-primary-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-primary-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-primary-spinner-color)}.gog-btn--secondary{--gog-btn-variant-bg: var(--gog-btn-secondary-bg);--gog-btn-variant-color: var(--gog-btn-secondary-color);--gog-btn-variant-border: var(--gog-btn-secondary-border);--gog-btn-variant-shadow: var(--gog-btn-secondary-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-secondary-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-secondary-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-secondary-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-secondary-spinner-color)}.gog-btn--outline{--gog-btn-variant-bg: var(--gog-btn-outline-bg);--gog-btn-variant-color: var(--gog-btn-outline-color);--gog-btn-variant-border: var(--gog-btn-outline-border);--gog-btn-variant-shadow: var(--gog-btn-outline-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-outline-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-outline-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-outline-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-outline-spinner-color)}.gog-btn--ghost{--gog-btn-variant-bg: var(--gog-btn-ghost-bg);--gog-btn-variant-color: var(--gog-btn-ghost-color);--gog-btn-variant-border: var(--gog-btn-ghost-border);--gog-btn-variant-shadow: var(--gog-btn-ghost-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-ghost-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-ghost-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-ghost-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-ghost-spinner-color)}.gog-btn--xsm{--gog-btn-size-padding: var(--gog-btn-xsm-padding);--gog-btn-size-font-size: var(--gog-btn-xsm-font-size)}.gog-btn--sm{--gog-btn-size-padding: var(--gog-btn-sm-padding);--gog-btn-size-font-size: var(--gog-btn-sm-font-size)}.gog-btn--md{--gog-btn-size-padding: var(--gog-btn-md-padding);--gog-btn-size-font-size: var(--gog-btn-md-font-size)}.gog-btn--lg{--gog-btn-size-padding: var(--gog-btn-lg-padding);--gog-btn-size-font-size: var(--gog-btn-lg-font-size)}.gog-btn--slg{--gog-btn-size-padding: var(--gog-btn-slg-padding);--gog-btn-size-font-size: var(--gog-btn-slg-font-size)}:host(.gog-host--full-width){display:flex}:host(.gog-host--full-width) .gog-btn{width:100%}.gog-btn--loading{position:relative;pointer-events:none;opacity:var(--gog-btn-loading-opacity)}.gog-btn__content--hidden{visibility:hidden}.gog-btn__spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);max-width:var(--gog-btn-spinner-max-size);max-height:var(--gog-btn-spinner-max-size)}\n"], dependencies: [{ kind: "component", type: SpinnerComponent, selector: "gog-spinner", inputs: ["size", "overlay", "ariaLabel", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
181
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ButtonComponent, isStandalone: true, selector: "gog-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { gogClick: "gogClick" }, host: { properties: { "class.gog-host--full-width": "fullWidth()" } }, ngImport: i0, template: "<button\r\n (click)=\"onClick($event)\"\r\n [attr.aria-busy]=\"loading() ? 'true' : null\"\r\n [attr.aria-disabled]=\"isDisabled() && !isNativeDisabled() ? 'true' : null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.disabled]=\"isNativeDisabled() ? true : null\"\r\n [class.gog-btn--ghost]=\"variant() === 'ghost'\"\r\n [class.gog-btn--loading]=\"loading()\"\r\n [class.gog-btn--outline]=\"variant() === 'outline'\"\r\n [class.gog-btn--primary]=\"variant() === 'primary'\"\r\n [class.gog-btn--secondary]=\"variant() === 'secondary'\"\r\n [class.gog-cursor-not-allowed]=\"isDisabled()\"\r\n [class.gog-cursor-pointer]=\"!isDisabled()\"\r\n [class.gog-cursor-wait]=\"loading()\"\r\n [type]=\"type()\"\r\n class=\"gog-btn gog-inline-center gog-contained-layout\"\r\n [class]=\"sizeClass()\"\r\n>\r\n @if (loading()) {\r\n <gog-spinner [size]=\"spinnerSize()\" aria-hidden=\"true\" class=\"gog-btn__spinner\" />\r\n }\r\n\r\n <span [class.gog-btn__content--hidden]=\"loading()\" class=\"gog-btn__content\">\r\n <ng-content></ng-content>\r\n </span>\r\n</button>\r\n", styles: ["@charset \"UTF-8\";:host(.gog-host--full-width){display:flex}:host(.gog-host--full-width) .gog-btn{width:100%}\n"], dependencies: [{ kind: "component", type: SpinnerComponent, selector: "gog-spinner", inputs: ["size", "overlay", "ariaLabel", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
182
182
  }
183
183
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ButtonComponent, decorators: [{
184
184
  type: Component,
@@ -186,9 +186,87 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
186
186
  // Drives the :host(.gog-host--full-width) rules in the stylesheet — without this
187
187
  // binding the `fullWidth` input has no visible effect.
188
188
  '[class.gog-host--full-width]': 'fullWidth()',
189
- }, template: "<button\r\n (click)=\"onClick($event)\"\r\n [attr.aria-busy]=\"loading() ? 'true' : null\"\r\n [attr.aria-disabled]=\"isDisabled() && !isNativeDisabled() ? 'true' : null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.disabled]=\"isNativeDisabled() ? true : null\"\r\n [class.gog-btn--ghost]=\"variant() === 'ghost'\"\r\n [class.gog-btn--loading]=\"loading()\"\r\n [class.gog-btn--outline]=\"variant() === 'outline'\"\r\n [class.gog-btn--primary]=\"variant() === 'primary'\"\r\n [class.gog-btn--secondary]=\"variant() === 'secondary'\"\r\n [class.gog-cursor-not-allowed]=\"isDisabled()\"\r\n [class.gog-cursor-pointer]=\"!isDisabled()\"\r\n [class.gog-cursor-wait]=\"loading()\"\r\n [type]=\"type()\"\r\n class=\"gog-btn gog-inline-center gog-contained-layout\"\r\n [class]=\"sizeClass()\"\r\n>\r\n @if (loading()) {\r\n <gog-spinner [size]=\"spinnerSize()\" aria-hidden=\"true\" class=\"gog-btn__spinner\" />\r\n }\r\n\r\n <span [class.gog-btn__content--hidden]=\"loading()\" class=\"gog-btn__content\">\r\n <ng-content></ng-content>\r\n </span>\r\n</button>\r\n", styles: [".gog-btn{--gog-spinner-color: var( --gog-btn-spinner-color, var(--gog-btn-variant-spinner-color, var(--gog-btn-primary-spinner-color)) );gap:var(--gog-btn-gap);border:var(--gog-btn-border-width) var(--gog-btn-border-style) var(--gog-btn-border, var(--gog-btn-variant-border, var(--gog-btn-primary-border)));border-radius:var(--gog-btn-radius);padding:var(--gog-btn-padding, var(--gog-btn-size-padding, var(--gog-btn-md-padding)));font-family:var(--gog-btn-font-family);font-weight:var(--gog-btn-font-weight);font-size:var(--gog-btn-font-size, var(--gog-btn-size-font-size, var(--gog-btn-md-font-size)));letter-spacing:var(--gog-btn-letter-spacing);text-transform:var(--gog-btn-text-transform);line-height:var(--gog-btn-line-height);background-color:var(--gog-btn-bg, var(--gog-btn-variant-bg, var(--gog-btn-primary-bg)));color:var(--gog-btn-color, var(--gog-btn-variant-color, var(--gog-btn-primary-color)));box-shadow:var(--gog-btn-shadow, var(--gog-btn-variant-shadow, var(--gog-btn-primary-shadow)));cursor:pointer;transition:background-color var(--gog-btn-transition-duration) var(--gog-easing),box-shadow var(--gog-btn-transition-duration) var(--gog-easing),color var(--gog-btn-transition-duration) var(--gog-easing)}.gog-btn:focus-visible{outline:var(--gog-btn-focus-ring-width) solid var(--gog-btn-hover-bg, var(--gog-btn-variant-hover-bg, var(--gog-btn-primary-hover-bg)));outline-offset:var(--gog-btn-focus-ring-offset)}.gog-btn:hover:not(:disabled){background-color:var(--gog-btn-hover-bg, var(--gog-btn-variant-hover-bg, var(--gog-btn-primary-hover-bg)));color:var(--gog-btn-hover-color, var(--gog-btn-variant-hover-color, var(--gog-btn-primary-hover-color)));box-shadow:var(--gog-btn-hover-shadow, var(--gog-btn-variant-hover-shadow, var(--gog-btn-primary-hover-shadow)))}.gog-btn:active:not(:disabled){transform:scale(var(--gog-btn-active-scale))}@media(prefers-reduced-motion:reduce){.gog-btn{transition:none}.gog-btn:active:not(:disabled){transform:none}}.gog-btn:disabled{opacity:var(--gog-btn-disabled-opacity);cursor:not-allowed}.gog-btn--primary{--gog-btn-variant-bg: var(--gog-btn-primary-bg);--gog-btn-variant-color: var(--gog-btn-primary-color);--gog-btn-variant-border: var(--gog-btn-primary-border);--gog-btn-variant-shadow: var(--gog-btn-primary-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-primary-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-primary-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-primary-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-primary-spinner-color)}.gog-btn--secondary{--gog-btn-variant-bg: var(--gog-btn-secondary-bg);--gog-btn-variant-color: var(--gog-btn-secondary-color);--gog-btn-variant-border: var(--gog-btn-secondary-border);--gog-btn-variant-shadow: var(--gog-btn-secondary-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-secondary-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-secondary-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-secondary-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-secondary-spinner-color)}.gog-btn--outline{--gog-btn-variant-bg: var(--gog-btn-outline-bg);--gog-btn-variant-color: var(--gog-btn-outline-color);--gog-btn-variant-border: var(--gog-btn-outline-border);--gog-btn-variant-shadow: var(--gog-btn-outline-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-outline-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-outline-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-outline-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-outline-spinner-color)}.gog-btn--ghost{--gog-btn-variant-bg: var(--gog-btn-ghost-bg);--gog-btn-variant-color: var(--gog-btn-ghost-color);--gog-btn-variant-border: var(--gog-btn-ghost-border);--gog-btn-variant-shadow: var(--gog-btn-ghost-shadow);--gog-btn-variant-hover-bg: var(--gog-btn-ghost-hover-bg);--gog-btn-variant-hover-color: var(--gog-btn-ghost-hover-color);--gog-btn-variant-hover-shadow: var(--gog-btn-ghost-hover-shadow);--gog-btn-variant-spinner-color: var(--gog-btn-ghost-spinner-color)}.gog-btn--xsm{--gog-btn-size-padding: var(--gog-btn-xsm-padding);--gog-btn-size-font-size: var(--gog-btn-xsm-font-size)}.gog-btn--sm{--gog-btn-size-padding: var(--gog-btn-sm-padding);--gog-btn-size-font-size: var(--gog-btn-sm-font-size)}.gog-btn--md{--gog-btn-size-padding: var(--gog-btn-md-padding);--gog-btn-size-font-size: var(--gog-btn-md-font-size)}.gog-btn--lg{--gog-btn-size-padding: var(--gog-btn-lg-padding);--gog-btn-size-font-size: var(--gog-btn-lg-font-size)}.gog-btn--slg{--gog-btn-size-padding: var(--gog-btn-slg-padding);--gog-btn-size-font-size: var(--gog-btn-slg-font-size)}:host(.gog-host--full-width){display:flex}:host(.gog-host--full-width) .gog-btn{width:100%}.gog-btn--loading{position:relative;pointer-events:none;opacity:var(--gog-btn-loading-opacity)}.gog-btn__content--hidden{visibility:hidden}.gog-btn__spinner{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);max-width:var(--gog-btn-spinner-max-size);max-height:var(--gog-btn-spinner-max-size)}\n"] }]
189
+ }, template: "<button\r\n (click)=\"onClick($event)\"\r\n [attr.aria-busy]=\"loading() ? 'true' : null\"\r\n [attr.aria-disabled]=\"isDisabled() && !isNativeDisabled() ? 'true' : null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.disabled]=\"isNativeDisabled() ? true : null\"\r\n [class.gog-btn--ghost]=\"variant() === 'ghost'\"\r\n [class.gog-btn--loading]=\"loading()\"\r\n [class.gog-btn--outline]=\"variant() === 'outline'\"\r\n [class.gog-btn--primary]=\"variant() === 'primary'\"\r\n [class.gog-btn--secondary]=\"variant() === 'secondary'\"\r\n [class.gog-cursor-not-allowed]=\"isDisabled()\"\r\n [class.gog-cursor-pointer]=\"!isDisabled()\"\r\n [class.gog-cursor-wait]=\"loading()\"\r\n [type]=\"type()\"\r\n class=\"gog-btn gog-inline-center gog-contained-layout\"\r\n [class]=\"sizeClass()\"\r\n>\r\n @if (loading()) {\r\n <gog-spinner [size]=\"spinnerSize()\" aria-hidden=\"true\" class=\"gog-btn__spinner\" />\r\n }\r\n\r\n <span [class.gog-btn__content--hidden]=\"loading()\" class=\"gog-btn__content\">\r\n <ng-content></ng-content>\r\n </span>\r\n</button>\r\n", styles: ["@charset \"UTF-8\";:host(.gog-host--full-width){display:flex}:host(.gog-host--full-width) .gog-btn{width:100%}\n"] }]
190
190
  }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], debounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounce", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], gogClick: [{ type: i0.Output, args: ["gogClick"] }] } });
191
191
 
192
+ /** Built-in default, used when neither the instance input nor `GOG_CONFIG` supplies one. */
193
+ const DEFAULT_SIZE$9 = 'md';
194
+ /**
195
+ * Makes a consumer's own `<a>` or `<button>` look like a `gog-button`.
196
+ *
197
+ * ```html
198
+ * <a gogButton routerLink="/pricing">See pricing</a>
199
+ * <a gogButton variant="ghost" href="https://example.com" target="_blank" rel="noreferrer">Docs</a>
200
+ * <button gogButton variant="outline" size="sm" type="submit">Save</button>
201
+ * ```
202
+ *
203
+ * ## Why this exists next to `gog-button`
204
+ *
205
+ * `gog-button` renders its own `<button>`, so it can never *be* a link — and making it one would
206
+ * mean brokering the router's entire input surface (`routerLink`, `routerLinkActive`,
207
+ * `queryParams`, `fragment`, `state`, …) through a component that would then have to depend on
208
+ * `@angular/router`. This package has four peer dependencies and no router, and a navigation
209
+ * button is not worth a fifth.
210
+ *
211
+ * Inverting it costs nothing: the consumer keeps their own element, so `routerLink`, `href`,
212
+ * `target`, `download`, `type="submit"`, `disabled` and every future directive keep working
213
+ * because they were never taken away. This is the "headless primitive" axis of
214
+ * `api-design.instructions.md` — expose the behaviour, not another input.
215
+ *
216
+ * ## Which to use
217
+ *
218
+ * Use `gog-button` for a button that *does* something in the page — it adds `loading` with a
219
+ * centred spinner, `debounce` click throttling and the `gogClick` output, none of which a bare
220
+ * element can provide. Use `[gogButton]` when the element must be a link, or when you need to
221
+ * keep directives of your own on it.
222
+ *
223
+ * ## Accessibility
224
+ *
225
+ * The element stays yours, so its semantics stay correct by construction: a link is a link and a
226
+ * button is a button. Two things this deliberately does **not** do:
227
+ *
228
+ * - It does not add `disabled` handling to an `<a>`. There is no such thing — a disabled link is
229
+ * just a link. Remove the `href` or render a real `<button>`.
230
+ * - It does not fake a loading state. `gog-button`'s spinner is a projected child; a directive
231
+ * cannot add one without taking over the element's content.
232
+ */
233
+ class GogButtonDirective {
234
+ variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
235
+ /** Unset, falls back to `GOG_CONFIG.control.size`, then to `'md'` — as on `gog-button`. */
236
+ size = input(undefined, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
237
+ /**
238
+ * Stretches the element to its container's width. A bare attribute is enough:
239
+ * `<a gogButton fullWidth>`.
240
+ */
241
+ fullWidth = input(false, { ...(ngDevMode ? { debugName: "fullWidth" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
242
+ globalConfig = inject(GOG_CONFIG);
243
+ resolvedSize = computed(() => resolveConfigured(this.size(), this.globalConfig.control?.size, DEFAULT_SIZE$9), ...(ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []));
244
+ variantClass = computed(() => `gog-btn--${this.variant()}`, ...(ngDevMode ? [{ debugName: "variantClass" }] : /* istanbul ignore next */ []));
245
+ /**
246
+ * Unlike `gog-button`, this emits a class for `'md'` too. The component can leave the default
247
+ * size unclassed because its own stylesheet bottoms out at `--gog-btn-md-*`; here the class is
248
+ * also what a consumer reads in devtools to see which size is applied, and a silently absent
249
+ * one reads as "no size resolved".
250
+ */
251
+ sizeClass = computed(() => `gog-btn--${this.resolvedSize()}`, ...(ngDevMode ? [{ debugName: "sizeClass" }] : /* istanbul ignore next */ []));
252
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: GogButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
253
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.17", type: GogButtonDirective, isStandalone: true, selector: "a[gogButton], button[gogButton]", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "variantClass() + \" \" + sizeClass()", "class.gog-btn--full-width": "fullWidth()" }, classAttribute: "gog-btn gog-inline-center gog-contained-layout" }, ngImport: i0 });
254
+ }
255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: GogButtonDirective, decorators: [{
256
+ type: Directive,
257
+ args: [{
258
+ // Restricted to `a` and `button` rather than a bare `[gogButton]`: on a `<div>` or `<span>` the
259
+ // result looks like a button and is invisible to the keyboard and to assistive tech, and that
260
+ // is exactly the mistake this directive would otherwise make easy.
261
+ selector: 'a[gogButton], button[gogButton]',
262
+ host: {
263
+ class: 'gog-btn gog-inline-center gog-contained-layout',
264
+ '[class]': 'variantClass() + " " + sizeClass()',
265
+ '[class.gog-btn--full-width]': 'fullWidth()',
266
+ },
267
+ }]
268
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }] } });
269
+
192
270
  const VERTICAL_ARROWS = ['ArrowDown', 'ArrowUp'];
193
271
  const HORIZONTAL_ARROWS = ['ArrowRight', 'ArrowLeft'];
194
272
  const EDGE_KEYS = ['Home', 'End'];
@@ -273,6 +351,31 @@ function handleRovingFocusKeydown(event, items, options = {}) {
273
351
  return true;
274
352
  }
275
353
 
354
+ /*
355
+ * The glyphs are from **Lucide** (https://lucide.dev), ISC licensed:
356
+ *
357
+ * Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of Feather
358
+ * (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.
359
+ *
360
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with or
361
+ * without fee is hereby granted, provided that the above copyright notice and this permission
362
+ * notice appear in all copies.
363
+ *
364
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO
365
+ * THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT
366
+ * SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR
367
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
368
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
369
+ * OR PERFORMANCE OF THIS SOFTWARE.
370
+ *
371
+ * They are inlined rather than pulled from `lucide` so the package keeps zero runtime
372
+ * dependencies. Anything added here must be a Lucide glyph too: a 24×24 grid, `stroke-width`
373
+ * 2, round caps and joins. Mixing in a set drawn for a different weight (Heroicons is drawn for
374
+ * 1.5) shows up immediately as uneven visual mass in a row of icons.
375
+ *
376
+ * An app that wants a different set does not need a fork — `provideGogIcons` overrides any of
377
+ * these by name.
378
+ */
276
379
  const ICON_DEFS = {
277
380
  check: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-check-icon lucide-check"><path d="M20 6 9 17l-5-5"/></svg>`,
278
381
  close: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-x-icon lucide-x"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>`,
@@ -294,38 +397,150 @@ const ICON_DEFS = {
294
397
  eye: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-eye-icon lucide-eye"><path d="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/><circle cx="12" cy="12" r="3"/></svg>`,
295
398
  'eye-off': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-eye-off-icon lucide-eye-off"><path d="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/><path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/><path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/><path d="m2 2 20 20"/></svg>`,
296
399
  copy: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy-icon lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>`,
400
+ /* ── Actions ─────────────────────────────────────────────────────────────── */
401
+ search: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>`,
402
+ plus: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-plus"><path d="M5 12h14"/><path d="M12 5v14"/></svg>`,
403
+ minus: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-minus"><path d="M5 12h14"/></svg>`,
404
+ trash: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-trash-2"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>`,
405
+ pencil: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-pencil"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></svg>`,
406
+ download: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-download"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>`,
407
+ upload: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-upload"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></svg>`,
408
+ refresh: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-cw"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg>`,
409
+ filter: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-filter"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>`,
410
+ 'external-link': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link"><path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/></svg>`,
411
+ /* ── Navigation & chrome ─────────────────────────────────────────────────── */
412
+ menu: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-menu"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg>`,
413
+ 'more-horizontal': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-ellipsis"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg>`,
414
+ 'more-vertical': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-ellipsis-vertical"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>`,
415
+ 'arrow-left': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-left"><path d="m12 19-7-7 7-7"/><path d="M19 12H5"/></svg>`,
416
+ 'arrow-right': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-right"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>`,
417
+ /* ── Objects & state ─────────────────────────────────────────────────────── */
418
+ user: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-user"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>`,
419
+ settings: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-settings"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>`,
420
+ lock: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-lock"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>`,
421
+ mail: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mail"><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>`,
422
+ star: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-star"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>`,
423
+ 'star-filled': `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-star"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" fill="currentColor"/></svg>`,
297
424
  };
298
425
 
426
+ /**
427
+ * Icons an app has registered, keyed by the name `gog-icon` will be asked for. Resolves to `{}`
428
+ * — only the built-ins are available — until a `provideGogIcons(...)` call fills it in.
429
+ *
430
+ * Values are raw `<svg>` markup, injected with `bypassSecurityTrustHtml` exactly like the
431
+ * built-ins. See `provideGogIcons` for what that means for you.
432
+ */
433
+ const GOG_ICONS = new InjectionToken('GOG_ICONS', {
434
+ providedIn: 'root',
435
+ factory: () => ({}),
436
+ });
437
+ /**
438
+ * Registers icons by name, so `<gog-icon name="cart" />` works for glyphs the library does not
439
+ * ship. This is the supported way to use your own icon set: the alternative — a `TemplateRef`
440
+ * per instance through the `template` input — costs a `<ng-template>` at every use site and is
441
+ * meant for one-offs, not for an icon set.
442
+ *
443
+ * ```ts
444
+ * // app.config.ts
445
+ * providers: [
446
+ * provideGogIcons({
447
+ * cart: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">…</svg>',
448
+ * user: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">…</svg>',
449
+ * }),
450
+ * ]
451
+ * ```
452
+ *
453
+ * **A registered name overrides a built-in of the same name**, which is how you swap the
454
+ * library's checkmark or chevron for your own without touching every component that renders one.
455
+ *
456
+ * **Providing this again further down the injector tree layers onto the parent's set** rather
457
+ * than replacing it, matching `provideGogConfig`: a lazy feature can register the three icons
458
+ * only it uses, and the app-wide set stays available inside it.
459
+ *
460
+ * ## What to put in the SVG
461
+ *
462
+ * Use `stroke="currentColor"` (or `fill="currentColor"`) and a `viewBox`, and leave the sizing
463
+ * alone — `gog-icon`'s stylesheet drives width, height and stroke width from the
464
+ * `--gog-icon-*` tokens, so an icon inherits size and colour from wherever it is used, the same
465
+ * as a built-in.
466
+ *
467
+ * ## Security
468
+ *
469
+ * The markup is inserted with `DomSanitizer.bypassSecurityTrustHtml`, because Angular's HTML
470
+ * sanitizer strips SVG and would leave you with nothing. That is safe for what this is for —
471
+ * static icon markup you wrote or imported at build time — and unsafe for anything derived from
472
+ * user input or fetched at runtime. **Never build a registered icon string from data you did
473
+ * not author.** If you need remote icons, fetch them yourself, sanitize them with a real SVG
474
+ * sanitizer, and register the result.
475
+ */
476
+ function provideGogIcons(icons) {
477
+ return {
478
+ provide: GOG_ICONS,
479
+ // skipSelf so this reads the *parent* injector's set rather than recursing into the provider
480
+ // being defined here; optional because at the root there is no parent providing it.
481
+ useFactory: () => ({
482
+ ...(inject(GOG_ICONS, { skipSelf: true, optional: true }) ?? {}),
483
+ ...icons,
484
+ }),
485
+ };
486
+ }
487
+
488
+ /**
489
+ * Names already warned about, so a missing icon rendered in a `@for` logs once rather than once
490
+ * per row. Module-level because the point is one message per name per page, not per component.
491
+ */
492
+ const warnedNames = new Set();
299
493
  class IconComponent {
300
494
  sanitizer = inject(DomSanitizer);
495
+ /** App-registered icons; overrides a built-in of the same name. See `provideGogIcons`. */
496
+ registered = inject(GOG_ICONS);
497
+ /** A built-in name, or one registered through `provideGogIcons(...)`. */
301
498
  name = input('close', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
302
499
  template = input(null, ...(ngDevMode ? [{ debugName: "template" }] : /* istanbul ignore next */ []));
303
500
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
304
501
  ariaHidden = input(true, ...(ngDevMode ? [{ debugName: "ariaHidden" }] : /* istanbul ignore next */ []));
305
502
  ariaLabel = computed(() => this.ariaHidden() ? null : this.title() || this.name(), ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
306
- iconSvg = computed(() => this.sanitizer.bypassSecurityTrustHtml(ICON_DEFS[this.name()]), ...(ngDevMode ? [{ debugName: "iconSvg" }] : /* istanbul ignore next */ []));
503
+ /**
504
+ * The markup to render, or `null` when the name resolves to nothing.
505
+ *
506
+ * An unknown name renders **nothing** and warns in dev mode — it never throws. An icon is
507
+ * decoration: taking an app down mid-render over a typo in a glyph name would be a far worse
508
+ * failure than the missing glyph, and the warning is what gets the typo fixed.
509
+ */
510
+ iconSvg = computed(() => {
511
+ const name = this.name();
512
+ const markup = this.registered[name] ?? ICON_DEFS[name];
513
+ if (!markup) {
514
+ if (isDevMode() && !warnedNames.has(name)) {
515
+ warnedNames.add(name);
516
+ console.warn(`[gog-icon] No icon named "${name}". Register it with provideGogIcons({ '${name}': '<svg…>' }), or use one of the built-ins.`);
517
+ }
518
+ return null;
519
+ }
520
+ return this.sanitizer.bypassSecurityTrustHtml(markup);
521
+ }, ...(ngDevMode ? [{ debugName: "iconSvg" }] : /* istanbul ignore next */ []));
307
522
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
308
523
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: IconComponent, isStandalone: true, selector: "gog-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, ariaHidden: { classPropertyName: "ariaHidden", publicName: "ariaHidden", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-hidden": "ariaHidden() ? \"true\" : null", "attr.aria-label": "ariaHidden() ? null : ariaLabel()" }, classAttribute: "gog-icon" }, ngImport: i0, template: `
309
524
  @if (template(); as iconTpl) {
310
525
  <ng-container *ngTemplateOutlet="iconTpl" />
311
- } @else {
312
- <span [innerHTML]="iconSvg()"></span>
526
+ } @else if (iconSvg(); as svg) {
527
+ <span [innerHTML]="svg"></span>
313
528
  }
314
- `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;line-height:0}:host ::ng-deep svg{width:var(--gog-icon-size, var(--gog-icon-fallback-size));height:var(--gog-icon-size, var(--gog-icon-fallback-size));display:block;color:currentColor}:host ::ng-deep svg path,:host ::ng-deep svg circle,:host ::ng-deep svg rect{stroke-width:var(--gog-icon-stroke-width)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
529
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;line-height:0}:host ::ng-deep svg{width:var(--gog-icon-size, var(--gog-icon-fallback-size));height:var(--gog-icon-size, var(--gog-icon-fallback-size));display:block;color:currentColor}:host ::ng-deep svg path,:host ::ng-deep svg circle,:host ::ng-deep svg rect,:host ::ng-deep svg ellipse,:host ::ng-deep svg line,:host ::ng-deep svg polyline,:host ::ng-deep svg polygon{stroke-width:var(--gog-icon-stroke-width)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
315
530
  }
316
531
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: IconComponent, decorators: [{
317
532
  type: Component,
318
533
  args: [{ selector: 'gog-icon', imports: [NgTemplateOutlet], template: `
319
534
  @if (template(); as iconTpl) {
320
535
  <ng-container *ngTemplateOutlet="iconTpl" />
321
- } @else {
322
- <span [innerHTML]="iconSvg()"></span>
536
+ } @else if (iconSvg(); as svg) {
537
+ <span [innerHTML]="svg"></span>
323
538
  }
324
539
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
325
540
  class: 'gog-icon',
326
541
  '[attr.aria-hidden]': 'ariaHidden() ? "true" : null',
327
542
  '[attr.aria-label]': 'ariaHidden() ? null : ariaLabel()',
328
- }, styles: [":host{display:inline-flex;align-items:center;justify-content:center;line-height:0}:host ::ng-deep svg{width:var(--gog-icon-size, var(--gog-icon-fallback-size));height:var(--gog-icon-size, var(--gog-icon-fallback-size));display:block;color:currentColor}:host ::ng-deep svg path,:host ::ng-deep svg circle,:host ::ng-deep svg rect{stroke-width:var(--gog-icon-stroke-width)}\n"] }]
543
+ }, styles: [":host{display:inline-flex;align-items:center;justify-content:center;line-height:0}:host ::ng-deep svg{width:var(--gog-icon-size, var(--gog-icon-fallback-size));height:var(--gog-icon-size, var(--gog-icon-fallback-size));display:block;color:currentColor}:host ::ng-deep svg path,:host ::ng-deep svg circle,:host ::ng-deep svg rect,:host ::ng-deep svg ellipse,:host ::ng-deep svg line,:host ::ng-deep svg polyline,:host ::ng-deep svg polygon{stroke-width:var(--gog-icon-stroke-width)}\n"] }]
329
544
  }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], ariaHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaHidden", required: false }] }] } });
330
545
 
331
546
  class SkeletonComponent {
@@ -621,6 +836,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
621
836
  }]
622
837
  }] });
623
838
 
839
+ /**
840
+ * Which `data-theme` an overlay rendered into `<body>` has to carry, if any.
841
+ *
842
+ * A panel or tooltip bubble is appended to `<body>`, which puts it outside whatever subtree it
843
+ * was opened from. `data-theme` can be scoped to any subtree — several themes rendering side by
844
+ * side is a documented use — so an overlay opened inside one of those has to be told which theme
845
+ * it belongs to, or it silently picks up the document's instead.
846
+ *
847
+ * **But only when the theme really is scoped.** When the nearest themed ancestor is the document
848
+ * element, copying the attribute is not merely redundant, it is actively wrong: the overlay
849
+ * already inherits everything from `<html>` through `<body>`, and re-stating `data-theme` on it
850
+ * makes it match `theme.css`'s derived layer (`:root, [data-theme]`) *locally*. That re-declares
851
+ * every component token on the overlay itself, resolved against the plain preset palette — which
852
+ * discards anything set on `<html>` that is not part of that preset. Custom properties written
853
+ * inline on `:root` are the case that bites: a live theme editor sets them there, the page
854
+ * follows, and every portal keeps rendering the un-edited theme.
855
+ *
856
+ * So: return the theme only for a genuinely scoped ancestor, and let inheritance do the work
857
+ * otherwise.
858
+ *
859
+ * Known limitation, currently unreachable: a *scoped* theme that is itself being edited through
860
+ * inline custom properties would still lose those on the overlay, since only the attribute is
861
+ * carried across. Copying resolved values instead would mean reading ~1200 properties on every
862
+ * open, which is not worth it for a case nothing does yet.
863
+ */
864
+ function scopedOverlayTheme(themeSource, documentElement) {
865
+ const themedAncestor = themeSource?.closest('[data-theme]');
866
+ if (!themedAncestor || themedAncestor === documentElement)
867
+ return null;
868
+ return themedAncestor.getAttribute('data-theme');
869
+ }
870
+
624
871
  /**
625
872
  * Renders a template into `document.body` while keeping it wired to the declaring
626
873
  * component: the view is stamped with that component's style encapsulation and reads
@@ -651,11 +898,9 @@ class GogDropdownOverlay {
651
898
  this.detach();
652
899
  this.hostEl = this.document.createElement('div');
653
900
  this.hostEl.classList.add('gog-overlay-host');
654
- // `data-theme` can be scoped to any subtree, not just `:root` (see the themes
655
- // showcase page), so the host has to copy it from wherever the trigger actually
656
- // sits rather than assume the document-wide theme applies.
657
- const themedAncestor = themeSource?.closest('[data-theme]');
658
- const theme = themedAncestor?.getAttribute('data-theme');
901
+ // Only for a genuinely scoped theme see `scopedOverlayTheme` for why copying it when the
902
+ // theme sits on `<html>` breaks live-edited themes.
903
+ const theme = scopedOverlayTheme(themeSource, this.document.documentElement);
659
904
  if (theme) {
660
905
  this.hostEl.setAttribute('data-theme', theme);
661
906
  }
@@ -3244,7 +3489,7 @@ const DEFAULT_LOCALE$1 = 'en-US';
3244
3489
  * input nor `GOG_CONFIG.labels` supplies one. Kept as one object so `resolvedLabels` stays a
3245
3490
  * single `computed` instead of nine, and so the set is obvious at a glance.
3246
3491
  */
3247
- const DEFAULT_LABELS$2 = {
3492
+ const DEFAULT_LABELS$3 = {
3248
3493
  today: 'Today',
3249
3494
  thisMonth: 'This month',
3250
3495
  previousMonth: 'Previous month',
@@ -3338,15 +3583,15 @@ class CalendarComponent {
3338
3583
  resolvedLabels = computed(() => {
3339
3584
  const configured = this.globalConfig.labels ?? {};
3340
3585
  return {
3341
- today: resolveConfigured(this.todayLabel(), configured.today, DEFAULT_LABELS$2.today),
3342
- thisMonth: resolveConfigured(this.thisMonthLabel(), configured.thisMonth, DEFAULT_LABELS$2.thisMonth),
3343
- previousMonth: resolveConfigured(this.previousMonthLabel(), configured.previousMonth, DEFAULT_LABELS$2.previousMonth),
3344
- nextMonth: resolveConfigured(this.nextMonthLabel(), configured.nextMonth, DEFAULT_LABELS$2.nextMonth),
3345
- previousYear: resolveConfigured(this.previousYearLabel(), configured.previousYear, DEFAULT_LABELS$2.previousYear),
3346
- nextYear: resolveConfigured(this.nextYearLabel(), configured.nextYear, DEFAULT_LABELS$2.nextYear),
3347
- hours: resolveConfigured(this.hoursLabel(), configured.hours, DEFAULT_LABELS$2.hours),
3348
- minutes: resolveConfigured(this.minutesLabel(), configured.minutes, DEFAULT_LABELS$2.minutes),
3349
- seconds: resolveConfigured(this.secondsLabel(), configured.seconds, DEFAULT_LABELS$2.seconds),
3586
+ today: resolveConfigured(this.todayLabel(), configured.today, DEFAULT_LABELS$3.today),
3587
+ thisMonth: resolveConfigured(this.thisMonthLabel(), configured.thisMonth, DEFAULT_LABELS$3.thisMonth),
3588
+ previousMonth: resolveConfigured(this.previousMonthLabel(), configured.previousMonth, DEFAULT_LABELS$3.previousMonth),
3589
+ nextMonth: resolveConfigured(this.nextMonthLabel(), configured.nextMonth, DEFAULT_LABELS$3.nextMonth),
3590
+ previousYear: resolveConfigured(this.previousYearLabel(), configured.previousYear, DEFAULT_LABELS$3.previousYear),
3591
+ nextYear: resolveConfigured(this.nextYearLabel(), configured.nextYear, DEFAULT_LABELS$3.nextYear),
3592
+ hours: resolveConfigured(this.hoursLabel(), configured.hours, DEFAULT_LABELS$3.hours),
3593
+ minutes: resolveConfigured(this.minutesLabel(), configured.minutes, DEFAULT_LABELS$3.minutes),
3594
+ seconds: resolveConfigured(this.secondsLabel(), configured.seconds, DEFAULT_LABELS$3.seconds),
3350
3595
  };
3351
3596
  }, ...(ngDevMode ? [{ debugName: "resolvedLabels" }] : /* istanbul ignore next */ []));
3352
3597
  /** First of the leftmost visible month. */
@@ -4958,7 +5203,7 @@ function toAnnouncement(toast) {
4958
5203
  const DEFAULT_SIZE$1 = 'md';
4959
5204
  const DEFAULT_ERROR_DISPLAY$2 = 'manual';
4960
5205
  const DEFAULT_SHOW_SPIN_BUTTONS = true;
4961
- const DEFAULT_LABELS$1 = {
5206
+ const DEFAULT_LABELS$2 = {
4962
5207
  clear: 'Clear',
4963
5208
  increment: 'Increment',
4964
5209
  decrement: 'Decrement',
@@ -5156,9 +5401,9 @@ class InputfieldComponent {
5156
5401
  */
5157
5402
  sizeClass = computed(() => this.resolvedSize() === 'md' ? '' : `gog-input-wrapper--${this.resolvedSize()}`, ...(ngDevMode ? [{ debugName: "sizeClass" }] : /* istanbul ignore next */ []));
5158
5403
  /** Instance input → `GOG_CONFIG.labels` → the built-in English default. */
5159
- resolvedClearLabel = computed(() => resolveConfigured(this.clearAriaLabel(), this.globalConfig.labels?.clear, DEFAULT_LABELS$1.clear), ...(ngDevMode ? [{ debugName: "resolvedClearLabel" }] : /* istanbul ignore next */ []));
5160
- resolvedIncrementLabel = computed(() => resolveConfigured(this.incrementLabel(), this.globalConfig.labels?.increment, DEFAULT_LABELS$1.increment), ...(ngDevMode ? [{ debugName: "resolvedIncrementLabel" }] : /* istanbul ignore next */ []));
5161
- resolvedDecrementLabel = computed(() => resolveConfigured(this.decrementLabel(), this.globalConfig.labels?.decrement, DEFAULT_LABELS$1.decrement), ...(ngDevMode ? [{ debugName: "resolvedDecrementLabel" }] : /* istanbul ignore next */ []));
5404
+ resolvedClearLabel = computed(() => resolveConfigured(this.clearAriaLabel(), this.globalConfig.labels?.clear, DEFAULT_LABELS$2.clear), ...(ngDevMode ? [{ debugName: "resolvedClearLabel" }] : /* istanbul ignore next */ []));
5405
+ resolvedIncrementLabel = computed(() => resolveConfigured(this.incrementLabel(), this.globalConfig.labels?.increment, DEFAULT_LABELS$2.increment), ...(ngDevMode ? [{ debugName: "resolvedIncrementLabel" }] : /* istanbul ignore next */ []));
5406
+ resolvedDecrementLabel = computed(() => resolveConfigured(this.decrementLabel(), this.globalConfig.labels?.decrement, DEFAULT_LABELS$2.decrement), ...(ngDevMode ? [{ debugName: "resolvedDecrementLabel" }] : /* istanbul ignore next */ []));
5162
5407
  resolvedShowSpinButtons = computed(() => resolveConfigured(this.showSpinButtons(), this.globalConfig.inputfield?.showSpinButtons, DEFAULT_SHOW_SPIN_BUTTONS), ...(ngDevMode ? [{ debugName: "resolvedShowSpinButtons" }] : /* istanbul ignore next */ []));
5163
5408
  isDisabled = computed(() => this.disabled() || this.cvaDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
5164
5409
  /** Disabled and read-only both refuse edits; the affordances that offer one key off this. */
@@ -5224,8 +5469,8 @@ class InputfieldComponent {
5224
5469
  if (!this.isPasswordField())
5225
5470
  return this.iconEndLabel();
5226
5471
  return this.passwordVisible()
5227
- ? resolveConfigured(this.hidePasswordLabel(), this.globalConfig.labels?.hidePassword, DEFAULT_LABELS$1.hidePassword)
5228
- : resolveConfigured(this.showPasswordLabel(), this.globalConfig.labels?.showPassword, DEFAULT_LABELS$1.showPassword);
5472
+ ? resolveConfigured(this.hidePasswordLabel(), this.globalConfig.labels?.hidePassword, DEFAULT_LABELS$2.hidePassword)
5473
+ : resolveConfigured(this.showPasswordLabel(), this.globalConfig.labels?.showPassword, DEFAULT_LABELS$2.showPassword);
5229
5474
  }, ...(ngDevMode ? [{ debugName: "effectiveIconEndLabel" }] : /* istanbul ignore next */ []));
5230
5475
  hasIconEnd = computed(() => this.showClear() ||
5231
5476
  !!this.addonEnd() ||
@@ -5788,11 +6033,8 @@ class GogTooltipOverlay {
5788
6033
  this.detach();
5789
6034
  this.componentRef = this.viewContainerRef.createComponent(GogTooltipBubbleComponent);
5790
6035
  const el = this.componentRef.location.nativeElement;
5791
- // See GogDropdownOverlay.attach data-theme can be scoped to any subtree, not just
5792
- // :root, so it has to be copied from the trigger's nearest themed ancestor rather than
5793
- // assumed from the document.
5794
- const themedAncestor = themeSource?.closest('[data-theme]');
5795
- const theme = themedAncestor?.getAttribute('data-theme');
6036
+ // Only for a genuinely scoped theme see `scopedOverlayTheme`.
6037
+ const theme = scopedOverlayTheme(themeSource, this.document.documentElement);
5796
6038
  if (theme) {
5797
6039
  el.setAttribute('data-theme', theme);
5798
6040
  }
@@ -6571,10 +6813,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
6571
6813
  }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], showThumb: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThumb", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], errorDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorDisplay", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], range: [{ type: i0.Input, args: [{ isSignal: true, alias: "range", required: false }] }], startAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAriaLabel", required: false }] }], endAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "endAriaLabel", required: false }] }], startDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "startDisabled", required: false }] }], endDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "endDisabled", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], rangeValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeValue", required: false }] }, { type: i0.Output, args: ["rangeValueChange"] }] } });
6572
6814
 
6573
6815
  /** Built-in defaults, used when neither the instance input nor `GOG_CONFIG.labels` supplies one. */
6574
- const DEFAULT_LABELS = {
6816
+ const DEFAULT_PAGE_SIZE = 10;
6817
+ const DEFAULT_PAGE_SIZE_OPTIONS = [10, 20, 30, 40, 50];
6818
+ /** Off by default: a paginator that silently grew a control would change every existing layout. */
6819
+ const DEFAULT_SHOW_PAGE_SIZE_SELECT = false;
6820
+ const DEFAULT_LABELS$1 = {
6575
6821
  pagination: 'Pagination',
6576
6822
  previousPage: 'Previous page',
6577
6823
  nextPage: 'Next page',
6824
+ rowsPerPage: 'Rows per page',
6578
6825
  page: (page, isCurrent) => isCurrent ? `Page ${page}, current page` : `Go to page ${page}`,
6579
6826
  };
6580
6827
  class PaginatorComponent {
@@ -6585,7 +6832,35 @@ class PaginatorComponent {
6585
6832
  * buttons instead.
6586
6833
  */
6587
6834
  fullWidth = input(true, ...(ngDevMode ? [{ debugName: "fullWidth" }] : /* istanbul ignore next */ []));
6835
+ /**
6836
+ * How many pages there are. Ignored when `totalRecords` is given — see there.
6837
+ */
6588
6838
  totalPages = input(1, ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
6839
+ /**
6840
+ * How many rows exist in total. Given this, the paginator computes the page count itself from
6841
+ * `pageSize`, which is what removes the `computed(() => Math.ceil(total / size))` a consumer
6842
+ * would otherwise have to write and keep in sync with the select below.
6843
+ *
6844
+ * `null` (the default) keeps the old contract: you tell it `totalPages` directly.
6845
+ */
6846
+ totalRecords = input(null, ...(ngDevMode ? [{ debugName: "totalRecords" }] : /* istanbul ignore next */ []));
6847
+ /**
6848
+ * Rows per page. Two-way bindable — `[(pageSize)]="size"` — which is the whole point once
6849
+ * `showPageSizeSelect` is on: the select writes back through this, and nothing has to be
6850
+ * ferried between components by hand. `gog-table` binds its own `pageSize` model straight to
6851
+ * this one.
6852
+ */
6853
+ pageSize = model(DEFAULT_PAGE_SIZE, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
6854
+ /**
6855
+ * Whether to offer the rows-per-page select. Unset, falls back to
6856
+ * `GOG_CONFIG.paginator.showPageSizeSelect`, then to `false`.
6857
+ */
6858
+ showPageSizeSelect = input(undefined, ...(ngDevMode ? [{ debugName: "showPageSizeSelect" }] : /* istanbul ignore next */ []));
6859
+ /**
6860
+ * The choices the select offers. Unset, falls back to
6861
+ * `GOG_CONFIG.paginator.pageSizeOptions`, then to `[10, 20, 30, 40, 50]`.
6862
+ */
6863
+ pageSizeOptions = input(undefined, ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
6589
6864
  /**
6590
6865
  * `window` (default): a fixed number of page buttons (`visiblePages`) that slides to keep
6591
6866
  * the current page centered, clamped at the edges — no ellipsis, no pinned boundaries
@@ -6612,34 +6887,58 @@ class PaginatorComponent {
6612
6887
  ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
6613
6888
  globalConfig = inject(GOG_CONFIG);
6614
6889
  /** Instance input → `GOG_CONFIG.labels` → the built-in English default. */
6615
- resolvedAriaLabel = computed(() => resolveConfigured(this.ariaLabel(), this.globalConfig.labels?.pagination, DEFAULT_LABELS.pagination), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
6890
+ resolvedAriaLabel = computed(() => resolveConfigured(this.ariaLabel(), this.globalConfig.labels?.pagination, DEFAULT_LABELS$1.pagination), ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
6616
6891
  /**
6617
6892
  * The two step buttons. Config-only: unlike the `<nav>` name, these say the same thing on
6618
6893
  * every paginator in an app, so a per-instance input would be dead weight.
6619
6894
  */
6620
- resolvedPreviousLabel = computed(() => resolveConfigured(undefined, this.globalConfig.labels?.previousPage, DEFAULT_LABELS.previousPage), ...(ngDevMode ? [{ debugName: "resolvedPreviousLabel" }] : /* istanbul ignore next */ []));
6621
- resolvedNextLabel = computed(() => resolveConfigured(undefined, this.globalConfig.labels?.nextPage, DEFAULT_LABELS.nextPage), ...(ngDevMode ? [{ debugName: "resolvedNextLabel" }] : /* istanbul ignore next */ []));
6895
+ resolvedPreviousLabel = computed(() => resolveConfigured(undefined, this.globalConfig.labels?.previousPage, DEFAULT_LABELS$1.previousPage), ...(ngDevMode ? [{ debugName: "resolvedPreviousLabel" }] : /* istanbul ignore next */ []));
6896
+ resolvedNextLabel = computed(() => resolveConfigured(undefined, this.globalConfig.labels?.nextPage, DEFAULT_LABELS$1.nextPage), ...(ngDevMode ? [{ debugName: "resolvedNextLabel" }] : /* istanbul ignore next */ []));
6622
6897
  /**
6623
6898
  * Names one page button. A method rather than a `computed`, since it takes the page number —
6624
6899
  * the formatter itself is resolved once and only re-read when the config object changes.
6625
6900
  */
6626
6901
  pageLabel(page) {
6627
- const format = this.globalConfig.labels?.page ?? DEFAULT_LABELS.page;
6902
+ const format = this.globalConfig.labels?.page ?? DEFAULT_LABELS$1.page;
6628
6903
  return format(page, page === this.page());
6629
6904
  }
6905
+ resolvedShowPageSizeSelect = computed(() => resolveConfigured(this.showPageSizeSelect(), this.globalConfig.paginator?.showPageSizeSelect, DEFAULT_SHOW_PAGE_SIZE_SELECT), ...(ngDevMode ? [{ debugName: "resolvedShowPageSizeSelect" }] : /* istanbul ignore next */ []));
6906
+ resolvedRowsPerPageLabel = computed(() => resolveConfigured(undefined, this.globalConfig.labels?.rowsPerPage, DEFAULT_LABELS$1.rowsPerPage), ...(ngDevMode ? [{ debugName: "resolvedRowsPerPageLabel" }] : /* istanbul ignore next */ []));
6907
+ /**
6908
+ * The select takes `{ id, name }` objects because that is `GogDropdownOption`'s default shape —
6909
+ * `optionLabel`/`optionValue` accessors for a list of plain numbers would be more API than the
6910
+ * mapping saves. The current `pageSize` is included even when it is not one of the offered
6911
+ * options, so a programmatic `[pageSize]="15"` shows 15 rather than an empty trigger.
6912
+ */
6913
+ resolvedPageSizeOptions = computed(() => {
6914
+ const options = resolveConfigured(this.pageSizeOptions(), this.globalConfig.paginator?.pageSizeOptions, DEFAULT_PAGE_SIZE_OPTIONS);
6915
+ const current = this.pageSize();
6916
+ const all = options.includes(current) ? options : [...options, current].sort((a, b) => a - b);
6917
+ return all.map((size) => ({ id: size, name: String(size) }));
6918
+ }, ...(ngDevMode ? [{ debugName: "resolvedPageSizeOptions" }] : /* istanbul ignore next */ []));
6919
+ /**
6920
+ * `totalRecords` when supplied, `totalPages` otherwise — every internal read goes through this
6921
+ * so the two inputs cannot disagree anywhere.
6922
+ */
6923
+ resolvedTotalPages = computed(() => {
6924
+ const records = this.totalRecords();
6925
+ if (records === null)
6926
+ return Math.max(1, this.totalPages());
6927
+ return Math.max(1, Math.ceil(Math.max(0, records) / Math.max(1, this.pageSize())));
6928
+ }, ...(ngDevMode ? [{ debugName: "resolvedTotalPages" }] : /* istanbul ignore next */ []));
6630
6929
  pageNumbers = computed(() => {
6631
- const total = Math.max(1, this.totalPages());
6930
+ const total = this.resolvedTotalPages();
6632
6931
  const current = this.page();
6633
6932
  return this.rangeMode() === 'ellipsis'
6634
6933
  ? this.ellipsisRange(total, current)
6635
6934
  : this.windowRange(total, current);
6636
6935
  }, ...(ngDevMode ? [{ debugName: "pageNumbers" }] : /* istanbul ignore next */ []));
6637
6936
  constructor() {
6638
- // Self-clamps whenever `totalPages` shrinks below the current page (or a consumer
6937
+ // Self-clamps whenever the page count shrinks below the current page (or a consumer
6639
6938
  // passes an out-of-range value directly), so every consumer gets correct bounds for
6640
6939
  // free instead of reimplementing this per usage.
6641
6940
  effect(() => {
6642
- const total = Math.max(1, this.totalPages());
6941
+ const total = this.resolvedTotalPages();
6643
6942
  const current = this.page();
6644
6943
  if (current > total) {
6645
6944
  this.page.set(total);
@@ -6648,6 +6947,26 @@ class PaginatorComponent {
6648
6947
  this.page.set(1);
6649
6948
  }
6650
6949
  });
6950
+ /*
6951
+ * A new page size invalidates the current page: "page 5" of 10-row pages is not "page 5" of
6952
+ * 50-row ones, and clamping alone would leave the user somewhere they did not ask to be.
6953
+ * Back to page 1, which is the only position that means the same thing at every size.
6954
+ * `untracked` so this reacts to the size and not to its own write.
6955
+ */
6956
+ let previousSize = null;
6957
+ effect(() => {
6958
+ const size = this.pageSize();
6959
+ // Guarded on an actual change, not on the effect running: the first run must leave an
6960
+ // initial `[page]="3"` alone, and re-running for an unrelated dependency must not snap the
6961
+ // user back to page 1.
6962
+ if (previousSize !== null && previousSize !== size) {
6963
+ untracked(() => {
6964
+ if (this.page() !== 1)
6965
+ this.page.set(1);
6966
+ });
6967
+ }
6968
+ previousSize = size;
6969
+ });
6651
6970
  }
6652
6971
  windowRange(total, current) {
6653
6972
  const windowSize = Math.min(Math.max(1, this.visiblePages()), total);
@@ -6685,7 +7004,7 @@ class PaginatorComponent {
6685
7004
  return typeof value === 'number';
6686
7005
  }
6687
7006
  goTo(target) {
6688
- if (this.disabled() || target < 1 || target > this.totalPages())
7007
+ if (this.disabled() || target < 1 || target > this.resolvedTotalPages())
6689
7008
  return;
6690
7009
  this.page.set(target);
6691
7010
  }
@@ -6695,12 +7014,16 @@ class PaginatorComponent {
6695
7014
  next() {
6696
7015
  this.goTo(this.page() + 1);
6697
7016
  }
7017
+ onPageSizeChange(size) {
7018
+ if (size !== null)
7019
+ this.pageSize.set(size);
7020
+ }
6698
7021
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PaginatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6699
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PaginatorComponent, isStandalone: true, selector: "gog-paginator", inputs: { page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, totalPages: { classPropertyName: "totalPages", publicName: "totalPages", isSignal: true, isRequired: false, transformFunction: null }, rangeMode: { classPropertyName: "rangeMode", publicName: "rangeMode", isSignal: true, isRequired: false, transformFunction: null }, visiblePages: { classPropertyName: "visiblePages", publicName: "visiblePages", isSignal: true, isRequired: false, transformFunction: null }, showFirstPage: { classPropertyName: "showFirstPage", publicName: "showFirstPage", isSignal: true, isRequired: false, transformFunction: null }, showLastPage: { classPropertyName: "showLastPage", publicName: "showLastPage", isSignal: true, isRequired: false, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange" }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "resolvedAriaLabel()", "class.gog-host--auto-width": "!fullWidth()" }, classAttribute: "gog-paginator" }, ngImport: i0, template: "<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === 1\"\r\n [ariaLabel]=\"resolvedPreviousLabel()\"\r\n (gogClick)=\"prev()\"\r\n >\u2039</gog-button\r\n>\r\n\r\n@for (item of pageNumbers(); track $index) {\r\n @if (isNumber(item)) {\r\n <gog-button\r\n [size]=\"size()\"\r\n [variant]=\"item === page() ? 'primary' : 'ghost'\"\r\n [disabled]=\"disabled()\"\r\n [ariaLabel]=\"pageLabel(item)\"\r\n (gogClick)=\"goTo(item)\"\r\n >{{ item }}</gog-button\r\n >\r\n } @else {\r\n <span class=\"gog-paginator__ellipsis\">\u2026</span>\r\n }\r\n}\r\n\r\n<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === totalPages()\"\r\n [ariaLabel]=\"resolvedNextLabel()\"\r\n (gogClick)=\"next()\"\r\n >\u203A</gog-button\r\n>\r\n", styles: [":host{display:flex;align-items:center;gap:var(--gog-paginator-gap);flex-wrap:wrap}:host(.gog-host--auto-width){width:fit-content}.gog-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:var(--gog-paginator-ellipsis-min-width);color:var(--gog-paginator-ellipsis-color);font-family:var(--gog-paginator-ellipsis-font-family);font-size:var(--gog-paginator-ellipsis-font-size);-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gog-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "loading", "debounce", "ariaLabel"], outputs: ["gogClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7022
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PaginatorComponent, isStandalone: true, selector: "gog-paginator", inputs: { page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, totalPages: { classPropertyName: "totalPages", publicName: "totalPages", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, showPageSizeSelect: { classPropertyName: "showPageSizeSelect", publicName: "showPageSizeSelect", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, rangeMode: { classPropertyName: "rangeMode", publicName: "rangeMode", isSignal: true, isRequired: false, transformFunction: null }, visiblePages: { classPropertyName: "visiblePages", publicName: "visiblePages", isSignal: true, isRequired: false, transformFunction: null }, showFirstPage: { classPropertyName: "showFirstPage", publicName: "showFirstPage", isSignal: true, isRequired: false, transformFunction: null }, showLastPage: { classPropertyName: "showLastPage", publicName: "showLastPage", isSignal: true, isRequired: false, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", pageSize: "pageSizeChange" }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "resolvedAriaLabel()", "class.gog-host--auto-width": "!fullWidth()" }, classAttribute: "gog-paginator" }, ngImport: i0, template: "<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === 1\"\r\n [ariaLabel]=\"resolvedPreviousLabel()\"\r\n (gogClick)=\"prev()\"\r\n >\u2039</gog-button\r\n>\r\n\r\n@for (item of pageNumbers(); track $index) {\r\n @if (isNumber(item)) {\r\n <gog-button\r\n [size]=\"size()\"\r\n [variant]=\"item === page() ? 'primary' : 'ghost'\"\r\n [disabled]=\"disabled()\"\r\n [ariaLabel]=\"pageLabel(item)\"\r\n (gogClick)=\"goTo(item)\"\r\n >{{ item }}</gog-button\r\n >\r\n } @else {\r\n <span class=\"gog-paginator__ellipsis\">\u2026</span>\r\n }\r\n}\r\n\r\n<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === resolvedTotalPages()\"\r\n [ariaLabel]=\"resolvedNextLabel()\"\r\n (gogClick)=\"next()\"\r\n >\u203A</gog-button\r\n>\r\n\r\n@if (resolvedShowPageSizeSelect()) {\r\n <!--\r\n Bound with `[(pageSize)]`'s writable half, so choosing a size writes straight back through the\r\n model the consumer bound \u2014 there is no intermediate state to keep in sync. `fullWidth` off so\r\n the select sizes to its content instead of stretching the paginator row.\r\n\r\n A plain `@if`, not `@defer`, and that was measured rather than assumed: `@defer` does move\r\n `SelectComponent` out of this component's static `dependencies` and into\r\n `deferBlockDependencies`, but ng-packagr flattens the whole library into one FESM, so the\r\n deferred reference compiles to `Promise.resolve().then(() => select_component)` \u2014 a binding in\r\n the *same module*, not a dynamic `import()`. With no import boundary there is nothing for a\r\n bundler to split on and nothing it may drop, so the consumer ships exactly the same bytes,\r\n minus a placeholder and an SSR pop-in. Making this genuinely lazy needs secondary entry\r\n points (`@guildofgleks/ui/select`), which is a packaging decision, not a template one.\r\n -->\r\n <gog-select\r\n class=\"gog-paginator__page-size\"\r\n [options]=\"resolvedPageSizeOptions()\"\r\n [value]=\"pageSize()\"\r\n [disabled]=\"disabled()\"\r\n [fullWidth]=\"false\"\r\n [size]=\"size()\"\r\n [ariaLabel]=\"resolvedRowsPerPageLabel()\"\r\n (valueChange)=\"onPageSizeChange($event)\"\r\n />\r\n}\r\n", styles: [":host{display:flex;align-items:center;gap:var(--gog-paginator-gap);flex-wrap:wrap}:host(.gog-host--auto-width){width:fit-content}.gog-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:var(--gog-paginator-ellipsis-min-width);color:var(--gog-paginator-ellipsis-color);font-family:var(--gog-paginator-ellipsis-font-family);font-size:var(--gog-paginator-ellipsis-font-size);-webkit-user-select:none;user-select:none}.gog-paginator__page-size{margin-inline-start:auto;min-width:var(--gog-paginator-page-size-min-width)}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gog-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "loading", "debounce", "ariaLabel"], outputs: ["gogClick"] }, { kind: "component", type: SelectComponent, selector: "gog-select", inputs: ["inputId", "value"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6700
7023
  }
6701
7024
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PaginatorComponent, decorators: [{
6702
7025
  type: Component,
6703
- args: [{ selector: 'gog-paginator', imports: [ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
7026
+ args: [{ selector: 'gog-paginator', imports: [ButtonComponent, SelectComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
6704
7027
  class: 'gog-paginator',
6705
7028
  role: 'navigation',
6706
7029
  '[attr.aria-label]': 'resolvedAriaLabel()',
@@ -6709,8 +7032,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
6709
7032
  // full-width class: this control is full width by default, so the class only
6710
7033
  // appears once a consumer opts *out* of that.
6711
7034
  '[class.gog-host--auto-width]': '!fullWidth()',
6712
- }, template: "<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === 1\"\r\n [ariaLabel]=\"resolvedPreviousLabel()\"\r\n (gogClick)=\"prev()\"\r\n >\u2039</gog-button\r\n>\r\n\r\n@for (item of pageNumbers(); track $index) {\r\n @if (isNumber(item)) {\r\n <gog-button\r\n [size]=\"size()\"\r\n [variant]=\"item === page() ? 'primary' : 'ghost'\"\r\n [disabled]=\"disabled()\"\r\n [ariaLabel]=\"pageLabel(item)\"\r\n (gogClick)=\"goTo(item)\"\r\n >{{ item }}</gog-button\r\n >\r\n } @else {\r\n <span class=\"gog-paginator__ellipsis\">\u2026</span>\r\n }\r\n}\r\n\r\n<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === totalPages()\"\r\n [ariaLabel]=\"resolvedNextLabel()\"\r\n (gogClick)=\"next()\"\r\n >\u203A</gog-button\r\n>\r\n", styles: [":host{display:flex;align-items:center;gap:var(--gog-paginator-gap);flex-wrap:wrap}:host(.gog-host--auto-width){width:fit-content}.gog-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:var(--gog-paginator-ellipsis-min-width);color:var(--gog-paginator-ellipsis-color);font-family:var(--gog-paginator-ellipsis-font-family);font-size:var(--gog-paginator-ellipsis-font-size);-webkit-user-select:none;user-select:none}\n"] }]
6713
- }], ctorParameters: () => [], propDecorators: { page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], totalPages: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalPages", required: false }] }], rangeMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeMode", required: false }] }], visiblePages: [{ type: i0.Input, args: [{ isSignal: true, alias: "visiblePages", required: false }] }], showFirstPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFirstPage", required: false }] }], showLastPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLastPage", required: false }] }], siblingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingCount", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
7035
+ }, template: "<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === 1\"\r\n [ariaLabel]=\"resolvedPreviousLabel()\"\r\n (gogClick)=\"prev()\"\r\n >\u2039</gog-button\r\n>\r\n\r\n@for (item of pageNumbers(); track $index) {\r\n @if (isNumber(item)) {\r\n <gog-button\r\n [size]=\"size()\"\r\n [variant]=\"item === page() ? 'primary' : 'ghost'\"\r\n [disabled]=\"disabled()\"\r\n [ariaLabel]=\"pageLabel(item)\"\r\n (gogClick)=\"goTo(item)\"\r\n >{{ item }}</gog-button\r\n >\r\n } @else {\r\n <span class=\"gog-paginator__ellipsis\">\u2026</span>\r\n }\r\n}\r\n\r\n<gog-button\r\n variant=\"ghost\"\r\n [size]=\"size()\"\r\n [disabled]=\"disabled() || page() === resolvedTotalPages()\"\r\n [ariaLabel]=\"resolvedNextLabel()\"\r\n (gogClick)=\"next()\"\r\n >\u203A</gog-button\r\n>\r\n\r\n@if (resolvedShowPageSizeSelect()) {\r\n <!--\r\n Bound with `[(pageSize)]`'s writable half, so choosing a size writes straight back through the\r\n model the consumer bound \u2014 there is no intermediate state to keep in sync. `fullWidth` off so\r\n the select sizes to its content instead of stretching the paginator row.\r\n\r\n A plain `@if`, not `@defer`, and that was measured rather than assumed: `@defer` does move\r\n `SelectComponent` out of this component's static `dependencies` and into\r\n `deferBlockDependencies`, but ng-packagr flattens the whole library into one FESM, so the\r\n deferred reference compiles to `Promise.resolve().then(() => select_component)` \u2014 a binding in\r\n the *same module*, not a dynamic `import()`. With no import boundary there is nothing for a\r\n bundler to split on and nothing it may drop, so the consumer ships exactly the same bytes,\r\n minus a placeholder and an SSR pop-in. Making this genuinely lazy needs secondary entry\r\n points (`@guildofgleks/ui/select`), which is a packaging decision, not a template one.\r\n -->\r\n <gog-select\r\n class=\"gog-paginator__page-size\"\r\n [options]=\"resolvedPageSizeOptions()\"\r\n [value]=\"pageSize()\"\r\n [disabled]=\"disabled()\"\r\n [fullWidth]=\"false\"\r\n [size]=\"size()\"\r\n [ariaLabel]=\"resolvedRowsPerPageLabel()\"\r\n (valueChange)=\"onPageSizeChange($event)\"\r\n />\r\n}\r\n", styles: [":host{display:flex;align-items:center;gap:var(--gog-paginator-gap);flex-wrap:wrap}:host(.gog-host--auto-width){width:fit-content}.gog-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:var(--gog-paginator-ellipsis-min-width);color:var(--gog-paginator-ellipsis-color);font-family:var(--gog-paginator-ellipsis-font-family);font-size:var(--gog-paginator-ellipsis-font-size);-webkit-user-select:none;user-select:none}.gog-paginator__page-size{margin-inline-start:auto;min-width:var(--gog-paginator-page-size-min-width)}\n"] }]
7036
+ }], ctorParameters: () => [], propDecorators: { page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], totalPages: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalPages", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], showPageSizeSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPageSizeSelect", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], rangeMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeMode", required: false }] }], visiblePages: [{ type: i0.Input, args: [{ isSignal: true, alias: "visiblePages", required: false }] }], showFirstPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFirstPage", required: false }] }], showLastPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLastPage", required: false }] }], siblingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingCount", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
6714
7037
 
6715
7038
  class SpinnerOverlayComponent {
6716
7039
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
@@ -6864,6 +7187,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
6864
7187
  }]
6865
7188
  }], propDecorators: { template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }] } });
6866
7189
 
7190
+ /** Built-in defaults, used when `GOG_CONFIG.labels` doesn't supply one. */
7191
+ const DEFAULT_LABELS = {
7192
+ total: 'Total',
7193
+ pagination: 'Table pagination',
7194
+ selectRow: 'Select row',
7195
+ selectAllRows: 'Select all rows on this page',
7196
+ };
6867
7197
  class TableComponent {
6868
7198
  /**
6869
7199
  * The single size modifier, replacing one `[class.gog-table--<size>]` binding per size.
@@ -6876,8 +7206,96 @@ class TableComponent {
6876
7206
  * its columns' content instead.
6877
7207
  */
6878
7208
  fullWidth = input(true, ...(ngDevMode ? [{ debugName: "fullWidth" }] : /* istanbul ignore next */ []));
6879
- /** 0 = no pagination */
6880
- pageSize = input(0, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
7209
+ /**
7210
+ * Rows per page; `0` (the default) means no pagination at all.
7211
+ *
7212
+ * A **`model`**, not an input, so `[pageSize]="20"` still works exactly as before *and*
7213
+ * `[(pageSize)]="size"` becomes possible. That is what lets `showPageSizeSelect` work without
7214
+ * any wiring: the table binds this model straight to its own paginator's `pageSize`, the
7215
+ * select writes back through it, and a consumer who wants to observe or persist the choice
7216
+ * binds two-way. Nothing is ferried between the two components by hand.
7217
+ *
7218
+ * In `lazy` mode a change here is a refetch signal, same as `gogPageChange` — bind
7219
+ * `[(pageSize)]` and reload from it. Changing the size always returns to page 1.
7220
+ */
7221
+ pageSize = model(0, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
7222
+ /**
7223
+ * Whether the paginator offers a rows-per-page select. Forwarded straight to `gog-paginator`;
7224
+ * unset, it falls back to `GOG_CONFIG.paginator.showPageSizeSelect`, then to `false`.
7225
+ */
7226
+ showPageSizeSelect = input(undefined, ...(ngDevMode ? [{ debugName: "showPageSizeSelect" }] : /* istanbul ignore next */ []));
7227
+ /**
7228
+ * The sizes that select offers. Forwarded to `gog-paginator`; unset, falls back to
7229
+ * `GOG_CONFIG.paginator.pageSizeOptions`, then to `[10, 20, 30, 40, 50]`.
7230
+ */
7231
+ pageSizeOptions = input(undefined, ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
7232
+ /**
7233
+ * Hands sorting and paging to the server.
7234
+ *
7235
+ * Off (the default), the table owns the whole data set: it sorts and slices `value` itself, and
7236
+ * `totalPages` comes from `value.length`. On, `value` is **the current page, already sorted** —
7237
+ * the table renders it as given and never re-orders or re-slices it. Supply `totalRecords` so
7238
+ * the paginator knows how many pages exist, and refetch in response to `gogSortChange` /
7239
+ * `gogPageChange`.
7240
+ *
7241
+ * ```html
7242
+ * <gog-table
7243
+ * [value]="page()"
7244
+ * [lazy]="true"
7245
+ * [totalRecords]="total()"
7246
+ * [pageSize]="20"
7247
+ * [loading]="loading()"
7248
+ * (gogSortChange)="sort.set($event); reload()"
7249
+ * (gogPageChange)="page$.set($event); reload()"
7250
+ * />
7251
+ * ```
7252
+ */
7253
+ lazy = input(false, ...(ngDevMode ? [{ debugName: "lazy" }] : /* istanbul ignore next */ []));
7254
+ /**
7255
+ * How many rows exist on the server, across all pages. `lazy` only — without it the table
7256
+ * cannot know how many pages to offer, and pagination is disabled. Ignored when `lazy` is off,
7257
+ * where `value.length` is the truth.
7258
+ */
7259
+ totalRecords = input(null, ...(ngDevMode ? [{ debugName: "totalRecords" }] : /* istanbul ignore next */ []));
7260
+ /**
7261
+ * Makes rows focusable and styles them as clickable, for a table whose rows navigate or open
7262
+ * something. `gogRowClick` fires on a plain click regardless; this is what makes that
7263
+ * affordance **discoverable and reachable by keyboard** (Enter and Space activate the focused
7264
+ * row), which a bare `(gogRowClick)` on a `<tr>` is not.
7265
+ *
7266
+ * If the row's action is better expressed as a control — a link to a detail page, a delete
7267
+ * button — put that in a cell instead. This is for the whole-row-is-the-target case.
7268
+ */
7269
+ interactiveRows = input(false, ...(ngDevMode ? [{ debugName: "interactiveRows" }] : /* istanbul ignore next */ []));
7270
+ /**
7271
+ * Turns on row selection. `'single'` keeps at most one row selected, `'multiple'` any number.
7272
+ *
7273
+ * The selection itself is always a `T[]` (`[(selection)]`), including in `'single'` mode where
7274
+ * it holds zero or one row — one shape rather than a `T | T[] | null` union the consumer has to
7275
+ * narrow on every read.
7276
+ */
7277
+ selectionMode = input('none', ...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
7278
+ /**
7279
+ * Two-way bindable selected rows: `[(selection)]="selected"`.
7280
+ *
7281
+ * Rows are matched by `dataKey` when one is set, and by object identity otherwise — so with no
7282
+ * `dataKey`, a refetch that produces new objects drops the selection. In `lazy` mode that is
7283
+ * almost always the wrong behaviour: set `dataKey`.
7284
+ */
7285
+ selection = model([], ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
7286
+ /**
7287
+ * Field name (or dot-path) uniquely identifying a row — `'id'` in most data sets.
7288
+ *
7289
+ * Used for selection identity and, when set, as the `@for` track key, which is what lets the
7290
+ * DOM survive a re-fetch of the same page instead of being torn down and rebuilt.
7291
+ */
7292
+ dataKey = input('', ...(ngDevMode ? [{ debugName: "dataKey" }] : /* istanbul ignore next */ []));
7293
+ /**
7294
+ * Whether the checkbox column renders. On by default once `selectionMode` is set; turn it off
7295
+ * for a table that selects by clicking the row itself, and pair it with `interactiveRows` so
7296
+ * that stays reachable by keyboard.
7297
+ */
7298
+ showSelectionColumn = input(true, ...(ngDevMode ? [{ debugName: "showSelectionColumn" }] : /* istanbul ignore next */ []));
6881
7299
  showRowNumbers = input(true, ...(ngDevMode ? [{ debugName: "showRowNumbers" }] : /* istanbul ignore next */ []));
6882
7300
  showTotal = input(false, ...(ngDevMode ? [{ debugName: "showTotal" }] : /* istanbul ignore next */ []));
6883
7301
  emptyPlaceholder = input('-', ...(ngDevMode ? [{ debugName: "emptyPlaceholder" }] : /* istanbul ignore next */ []));
@@ -6893,10 +7311,30 @@ class TableComponent {
6893
7311
  stickyHeader = input(false, ...(ngDevMode ? [{ debugName: "stickyHeader" }] : /* istanbul ignore next */ []));
6894
7312
  /** Row density: lg (default) / md (compact) / sm (dense) */
6895
7313
  size = input('lg', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
7314
+ /**
7315
+ * Fires when a header cell changes the sort — including the third click that clears it, which
7316
+ * emits `{ field: '', direction: null }`. In `lazy` mode this is the refetch signal; the table
7317
+ * has already reset to page 1 by the time it fires.
7318
+ */
7319
+ gogSortChange = output();
7320
+ /**
7321
+ * Fires when the page changes, with the new 1-based page. Only ever fires for a *user* action
7322
+ * or a clamp — not for the initial render.
7323
+ */
7324
+ gogPageChange = output();
7325
+ /** Fires when a row is clicked, or activated with Enter/Space when `interactiveRows` is on. */
7326
+ gogRowClick = output();
6896
7327
  columns = contentChildren(GogColumn, ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
6897
7328
  templates = contentChildren(TemplateDirective, ...(ngDevMode ? [{ debugName: "templates" }] : /* istanbul ignore next */ []));
6898
7329
  sortState = signal({ field: '', direction: null }, ...(ngDevMode ? [{ debugName: "sortState" }] : /* istanbul ignore next */ []));
7330
+ /**
7331
+ * In `lazy` mode `value` is the server's answer — already sorted, already the right page — so
7332
+ * both this and `visibleRows` become pass-throughs. Re-sorting it locally would reorder one
7333
+ * page against a global ordering, which looks like corruption rather than a bug.
7334
+ */
6899
7335
  sortedData = computed(() => {
7336
+ if (this.lazy())
7337
+ return this.value();
6900
7338
  const { field, direction } = this.sortState();
6901
7339
  const rows = [...this.value()];
6902
7340
  if (!field || !direction)
@@ -6917,11 +7355,16 @@ class TableComponent {
6917
7355
  return direction === 'asc' ? cmp : -cmp;
6918
7356
  });
6919
7357
  }, ...(ngDevMode ? [{ debugName: "sortedData" }] : /* istanbul ignore next */ []));
7358
+ /**
7359
+ * How many rows the paginator is dividing. `value.length` normally; `totalRecords` in `lazy`
7360
+ * mode, where `value` is only the current page. Also what `showTotal` reports.
7361
+ */
7362
+ rowCount = computed(() => this.lazy() ? Math.max(0, this.totalRecords() ?? 0) : this.value().length, ...(ngDevMode ? [{ debugName: "rowCount" }] : /* istanbul ignore next */ []));
6920
7363
  totalPages = computed(() => {
6921
7364
  const size = this.pageSize();
6922
7365
  if (!size)
6923
7366
  return 1;
6924
- return Math.max(1, Math.ceil(this.sortedData().length / size));
7367
+ return Math.max(1, Math.ceil(this.rowCount() / size));
6925
7368
  }, ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
6926
7369
  /**
6927
7370
  * Resets to page 1 whenever the sort changes (a new sort re-orders the whole data set,
@@ -6930,22 +7373,128 @@ class TableComponent {
6930
7373
  * wherever the paginator navigated to. `gog-paginator`'s own `page` model additionally
6931
7374
  * self-clamps against `totalPages` on its own, so this only has to handle the reset case.
6932
7375
  */
6933
- currentPage = linkedSignal({ ...(ngDevMode ? { debugName: "currentPage" } : /* istanbul ignore next */ {}), source: () => ({ total: this.totalPages(), sortState: this.sortState() }),
7376
+ currentPage = linkedSignal({ ...(ngDevMode ? { debugName: "currentPage" } : /* istanbul ignore next */ {}), source: () => ({
7377
+ total: this.totalPages(),
7378
+ sortState: this.sortState(),
7379
+ pageSize: this.pageSize(),
7380
+ }),
6934
7381
  computation: (src, previous) => {
6935
- if (!previous || previous.source.sortState !== src.sortState)
7382
+ if (!previous)
7383
+ return 1;
7384
+ // A new sort re-orders everything, and a new page size redraws the boundaries — in both
7385
+ // cases the page the user was on no longer denotes the same rows.
7386
+ if (previous.source.sortState !== src.sortState)
7387
+ return 1;
7388
+ if (previous.source.pageSize !== src.pageSize)
6936
7389
  return 1;
6937
7390
  return Math.min(Math.max(1, previous.value), src.total);
6938
7391
  } });
7392
+ /** In `lazy` mode the server already sliced the page — see `sortedData`. */
6939
7393
  visibleRows = computed(() => {
6940
7394
  const size = this.pageSize();
6941
- if (!size)
7395
+ if (this.lazy() || !size)
6942
7396
  return this.sortedData();
6943
7397
  const page = this.currentPage();
6944
7398
  const start = (page - 1) * size;
6945
7399
  return this.sortedData().slice(start, start + size);
6946
7400
  }, ...(ngDevMode ? [{ debugName: "visibleRows" }] : /* istanbul ignore next */ []));
6947
- hasPagination = computed(() => !this.loading() && this.pageSize() > 0 && this.totalPages() > 1, ...(ngDevMode ? [{ debugName: "hasPagination" }] : /* istanbul ignore next */ []));
6948
- emptyColspan = computed(() => this.columns().length + (this.showRowNumbers() ? 1 : 0), ...(ngDevMode ? [{ debugName: "emptyColspan" }] : /* istanbul ignore next */ []));
7401
+ /**
7402
+ * Resolved the same way `gog-paginator` resolves it, because the footer's own visibility
7403
+ * depends on it — see `hasPagination`.
7404
+ */
7405
+ showsPageSizeSelect = computed(() => resolveConfigured(this.showPageSizeSelect(), this.globalConfig.paginator?.showPageSizeSelect, false), ...(ngDevMode ? [{ debugName: "showsPageSizeSelect" }] : /* istanbul ignore next */ []));
7406
+ /**
7407
+ * Normally the paginator only earns its space once there is more than one page — but the
7408
+ * rows-per-page select lives inside it, and hiding the whole thing at one page would strand the
7409
+ * user on whatever size produced that single page with no way back to a smaller one.
7410
+ */
7411
+ hasPagination = computed(() => !this.loading() &&
7412
+ this.pageSize() > 0 &&
7413
+ (this.totalPages() > 1 || this.showsPageSizeSelect()), ...(ngDevMode ? [{ debugName: "hasPagination" }] : /* istanbul ignore next */ []));
7414
+ globalConfig = inject(GOG_CONFIG);
7415
+ /** `GOG_CONFIG.labels` → the built-in English defaults. No per-instance inputs: these name
7416
+ * table chrome, and an app that relabels them does so once. */
7417
+ resolvedLabels = computed(() => {
7418
+ const configured = this.globalConfig.labels ?? {};
7419
+ return {
7420
+ total: resolveConfigured(undefined, configured.total, DEFAULT_LABELS.total),
7421
+ pagination: resolveConfigured(undefined, configured.tablePagination, DEFAULT_LABELS.pagination),
7422
+ selectRow: resolveConfigured(undefined, configured.selectRow, DEFAULT_LABELS.selectRow),
7423
+ selectAllRows: resolveConfigured(undefined, configured.selectAllRows, DEFAULT_LABELS.selectAllRows),
7424
+ };
7425
+ }, ...(ngDevMode ? [{ debugName: "resolvedLabels" }] : /* istanbul ignore next */ []));
7426
+ hasSelection = computed(() => this.selectionMode() !== 'none', ...(ngDevMode ? [{ debugName: "hasSelection" }] : /* istanbul ignore next */ []));
7427
+ hasSelectionColumn = computed(() => this.hasSelection() && this.showSelectionColumn(), ...(ngDevMode ? [{ debugName: "hasSelectionColumn" }] : /* istanbul ignore next */ []));
7428
+ emptyColspan = computed(() => this.columns().length + (this.showRowNumbers() ? 1 : 0) + (this.hasSelectionColumn() ? 1 : 0), ...(ngDevMode ? [{ debugName: "emptyColspan" }] : /* istanbul ignore next */ []));
7429
+ /**
7430
+ * Identity for selection and `@for` tracking. `dataKey`'s value when set, the row object
7431
+ * otherwise — the object works for a static data set and breaks the moment rows are re-fetched,
7432
+ * which is exactly what `dataKey` is for.
7433
+ */
7434
+ rowKey(row) {
7435
+ const key = this.dataKey();
7436
+ return key ? getByPath(row, key) : row;
7437
+ }
7438
+ isSelected(row) {
7439
+ const key = this.rowKey(row);
7440
+ return this.selection().some((selected) => this.rowKey(selected) === key);
7441
+ }
7442
+ /** All rows on the current page are selected — drives the header checkbox. */
7443
+ allPageRowsSelected = computed(() => {
7444
+ const rows = this.visibleRows();
7445
+ return rows.length > 0 && rows.every((row) => this.isSelected(row));
7446
+ }, ...(ngDevMode ? [{ debugName: "allPageRowsSelected" }] : /* istanbul ignore next */ []));
7447
+ /** Some but not all — the header checkbox's indeterminate state. */
7448
+ somePageRowsSelected = computed(() => {
7449
+ const rows = this.visibleRows();
7450
+ return rows.some((row) => this.isSelected(row)) && !this.allPageRowsSelected();
7451
+ }, ...(ngDevMode ? [{ debugName: "somePageRowsSelected" }] : /* istanbul ignore next */ []));
7452
+ toggleRowSelection(row, selected) {
7453
+ if (this.selectionMode() === 'single') {
7454
+ this.selection.set(selected ? [row] : []);
7455
+ return;
7456
+ }
7457
+ const key = this.rowKey(row);
7458
+ const without = this.selection().filter((entry) => this.rowKey(entry) !== key);
7459
+ this.selection.set(selected ? [...without, row] : without);
7460
+ }
7461
+ /**
7462
+ * Header checkbox: selects or clears **the current page**, not the whole data set. Anything
7463
+ * else would be a lie in `lazy` mode, where the table has never seen the other pages — and
7464
+ * inconsistent between the two modes, which is worse than either behaviour alone.
7465
+ */
7466
+ toggleAllOnPage(selected) {
7467
+ const rows = this.visibleRows();
7468
+ const pageKeys = new Set(rows.map((row) => this.rowKey(row)));
7469
+ const offPage = this.selection().filter((entry) => !pageKeys.has(this.rowKey(entry)));
7470
+ this.selection.set(selected ? [...offPage, ...rows] : offPage);
7471
+ }
7472
+ constructor() {
7473
+ /*
7474
+ * `gogPageChange` for user navigation and clamps, but *not* for the reset that follows a new
7475
+ * sort: `currentPage` snapping back to 1 there is part of the sort, and a lazy consumer
7476
+ * refetching from both events would fire two requests for one user action. Detected by the
7477
+ * sort having changed in the same computation, and skipped.
7478
+ */
7479
+ let previous = null;
7480
+ effect(() => {
7481
+ const page = this.currentPage();
7482
+ const sort = this.sortState();
7483
+ const size = this.pageSize();
7484
+ const causedByOther = previous && (previous.sort !== sort || previous.size !== size);
7485
+ if (previous && previous.page !== page && !causedByOther) {
7486
+ this.gogPageChange.emit(page);
7487
+ }
7488
+ previous = { page, sort, size };
7489
+ });
7490
+ effect(() => {
7491
+ if (!isDevMode() || !this.lazy() || this.pageSize() <= 0)
7492
+ return;
7493
+ if (this.totalRecords() === null) {
7494
+ console.warn("[gog-table] `lazy` with a `pageSize` but no `totalRecords`: the table cannot know how many pages exist, so pagination stays hidden. Pass the server's total row count.");
7495
+ }
7496
+ });
7497
+ }
6949
7498
  /**
6950
7499
  * A `gogColumnBody` template declared inside the column wins; the string-keyed
6951
7500
  * `<ng-template template="field" type="body">` is the deprecated fallback.
@@ -6968,6 +7517,10 @@ class TableComponent {
6968
7517
  headerContext(col) {
6969
7518
  return { $implicit: col.header(), field: col.field() };
6970
7519
  }
7520
+ /**
7521
+ * Cycles the clicked column asc → desc → unsorted, and emits the result. The emit is last, so
7522
+ * a `lazy` consumer refetching from it already sees `currentPage` reset to 1.
7523
+ */
6971
7524
  toggleSort(col) {
6972
7525
  if (!col.sortable())
6973
7526
  return;
@@ -6982,6 +7535,20 @@ class TableComponent {
6982
7535
  else {
6983
7536
  this.sortState.set({ field: '', direction: null });
6984
7537
  }
7538
+ this.gogSortChange.emit(this.sortState());
7539
+ }
7540
+ /** Click, or Enter/Space on a focused row when `interactiveRows` is on. */
7541
+ emitRowClick(row, index, originalEvent) {
7542
+ this.gogRowClick.emit({ row, index, originalEvent });
7543
+ }
7544
+ /** Enter and Space activate the focused row; Space must not also scroll the page. */
7545
+ onRowKeydown(row, index, event) {
7546
+ if (!this.interactiveRows())
7547
+ return;
7548
+ if (event.key !== 'Enter' && event.key !== ' ')
7549
+ return;
7550
+ event.preventDefault();
7551
+ this.emitRowClick(row, index, event);
6985
7552
  }
6986
7553
  getSortDirection(field) {
6987
7554
  const s = this.sortState();
@@ -7039,16 +7606,23 @@ class TableComponent {
7039
7606
  return map;
7040
7607
  }, ...(ngDevMode ? [{ debugName: "headerTemplateMap" }] : /* istanbul ignore next */ []));
7041
7608
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7042
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TableComponent, isStandalone: true, selector: "gog-table", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, showRowNumbers: { classPropertyName: "showRowNumbers", publicName: "showRowNumbers", isSignal: true, isRequired: false, transformFunction: null }, showTotal: { classPropertyName: "showTotal", publicName: "showTotal", isSignal: true, isRequired: false, transformFunction: null }, emptyPlaceholder: { classPropertyName: "emptyPlaceholder", publicName: "emptyPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, paginatorPosition: { classPropertyName: "paginatorPosition", publicName: "paginatorPosition", isSignal: true, isRequired: false, transformFunction: null }, totalPosition: { classPropertyName: "totalPosition", publicName: "totalPosition", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showColumnBorders: { classPropertyName: "showColumnBorders", publicName: "showColumnBorders", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"block\"", "style.width": "fullWidth() ? \"100%\" : \"fit-content\"" }, classAttribute: "gog-table-host" }, queries: [{ propertyName: "columns", predicate: GogColumn, isSignal: true }, { propertyName: "templates", predicate: TemplateDirective, isSignal: true }], ngImport: i0, template: "<div class=\"gog-table-wrapper gog-contained-layout\">\r\n <gog-scroll axis=\"horizontal\" class=\"gog-table-scroll\">\r\n <table\r\n class=\"gog-table\"\r\n [class]=\"sizeClass()\"\r\n [class.gog-table--col-borders]=\"showColumnBorders()\"\r\n [class.gog-table--loading]=\"loading()\"\r\n [class.gog-table--sticky-header]=\"stickyHeader()\"\r\n [style.width]=\"fullWidth() ? '100%' : 'fit-content'\"\r\n >\r\n <colgroup>\r\n @if (showRowNumbers()) {\r\n <col class=\"gog-table__col--num\" />\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <col\r\n [style.width]=\"col.width() || null\"\r\n [style.min-width]=\"col.minWidth() || null\"\r\n [style.max-width]=\"col.maxWidth() || null\"\r\n />\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @if (showRowNumbers()) {\r\n <th class=\"gog-table__th gog-table__th--num\" scope=\"col\">#</th>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <th\r\n class=\"gog-table__th\"\r\n scope=\"col\"\r\n [class.gog-table__th--sortable]=\"col.sortable() && !loading()\"\r\n [class.gog-table__th--sorted]=\"getSortDirection(col.field())\"\r\n [attr.aria-sort]=\"getAriaSort(col.field())\"\r\n [attr.tabindex]=\"col.sortable() && !loading() ? 0 : null\"\r\n (click)=\"handleSortClick(col)\"\r\n (keydown.enter)=\"handleSortClick(col)\"\r\n (keydown.space)=\"handleSortClick(col); $event.preventDefault()\"\r\n >\r\n @if (getHeaderTemplate(col); as headerTpl) {\r\n <ng-container *ngTemplateOutlet=\"headerTpl; context: headerContext(col)\" />\r\n } @else {\r\n <span class=\"gog-table__th-inner\">\r\n {{ col.header() || col.field() }}\r\n @if (col.sortable() && !loading()) {\r\n <span class=\"gog-table__sort-icon\" aria-hidden=\"true\">\r\n @if (getSortDirection(col.field()) === 'asc') {\r\n <gog-icon name=\"sort-up\" />\r\n } @else if (getSortDirection(col.field()) === 'desc') {\r\n <gog-icon name=\"sort-down\" />\r\n } @else {\r\n <gog-icon name=\"sort\" />\r\n }\r\n </span>\r\n }\r\n </span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr>\r\n <td class=\"gog-table__loading-cell\" [attr.colspan]=\"emptyColspan()\">\r\n <gog-spinner size=\"md\" />\r\n </td>\r\n </tr>\r\n } @else if (visibleRows().length === 0) {\r\n <tr>\r\n <td class=\"gog-table__empty\" [attr.colspan]=\"emptyColspan()\">\u2014</td>\r\n </tr>\r\n } @else {\r\n @for (row of visibleRows(); track $index; let i = $index) {\r\n <tr class=\"gog-table__row\">\r\n @if (showRowNumbers()) {\r\n <td class=\"gog-table__td gog-table__td--num\">{{ globalRowIndex(i) }}</td>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <td class=\"gog-table__td\">\r\n @if (getBodyTemplate(col); as bodyTpl) {\r\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: bodyContext(row, col, i)\" />\r\n } @else {\r\n {{ formatCellValue(row, col.field()) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </gog-scroll>\r\n\r\n @if (hasPagination() || showTotal()) {\r\n <div class=\"gog-table__footer\">\r\n @if (showTotal()) {\r\n <span class=\"gog-table__total\" [style.grid-area]=\"totalGridArea()\">\r\n Total: {{ value().length }}\r\n </span>\r\n }\r\n\r\n @if (hasPagination()) {\r\n <gog-paginator\r\n class=\"gog-table__pagination\"\r\n [style.grid-area]=\"paginatorGridArea()\"\r\n [(page)]=\"currentPage\"\r\n [totalPages]=\"totalPages()\"\r\n rangeMode=\"ellipsis\"\r\n size=\"sm\"\r\n ariaLabel=\"Table pagination\"\r\n />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".gog-table-wrapper{display:flex;flex-direction:column;gap:var(--gog-table-gap);width:100%;overflow-anchor:none}.gog-table-scroll{width:100%}.gog-table{width:100%;border-collapse:collapse;border:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);background-color:var(--gog-table-surface);color:var(--gog-table-text-color);font-family:var(--gog-table-font-family);table-layout:fixed}.gog-table--slg{--gog-table-size-th-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-td-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-th-font-size: var(--gog-table-slg-th-font-size);--gog-table-size-td-font-size: var(--gog-table-slg-td-font-size)}.gog-table--md{--gog-table-size-th-padding-v: var(--gog-table-md-padding-v);--gog-table-size-td-padding-v: var(--gog-table-md-padding-v);--gog-table-size-th-font-size: var(--gog-table-md-th-font-size);--gog-table-size-td-font-size: var(--gog-table-md-td-font-size)}.gog-table--sm{--gog-table-size-th-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-th-font-size: var(--gog-table-sm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-sm-td-font-size)}.gog-table--xsm{--gog-table-size-th-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-th-font-size: var(--gog-table-xsm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-xsm-td-font-size)}.gog-table__col--num{width:var(--gog-table-num-col-width)}.gog-table__th{padding:var(--gog-table-th-padding-v, var(--gog-table-size-th-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);text-align:left;font-family:var(--gog-table-header-font-family);font-size:var(--gog-table-th-font-size, var(--gog-table-size-th-font-size, var(--gog-table-lg-th-font-size)));text-transform:var(--gog-table-header-text-transform);letter-spacing:var(--gog-table-header-letter-spacing);color:var(--gog-table-accent-color);background-color:var(--gog-table-surface);border-bottom:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);white-space:normal;overflow:hidden}.gog-table--sticky-header .gog-table__th{position:sticky;top:0;z-index:1}.gog-table__th--num{width:var(--gog-table-num-col-width);text-align:center;color:var(--gog-table-muted-color)}.gog-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.gog-table__th--sortable:focus-visible{outline:var(--gog-table-focus-ring-width) solid var(--gog-table-focus-ring);outline-offset:calc(var(--gog-table-focus-ring-width) * -1)}.gog-table__th--sortable:hover,.gog-table__th--sorted{color:var(--gog-table-accent-bright)}.gog-table__th-inner{display:inline-flex;align-items:center;gap:var(--gog-table-th-inner-gap);width:100%}.gog-table__sort-icon{display:inline-block;width:var(--gog-table-sort-icon-width);text-align:center;font-size:var(--gog-table-sort-icon-size);opacity:var(--gog-table-sort-icon-opacity);flex-shrink:0}.gog-table__th--sorted .gog-table__sort-icon{opacity:1}.gog-table__td{padding:var(--gog-table-td-padding-v, var(--gog-table-size-td-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);font-size:var(--gog-table-td-font-size, var(--gog-table-size-td-font-size, var(--gog-table-lg-td-font-size)));border-bottom:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color);vertical-align:middle;overflow-wrap:break-word;word-break:break-word;overflow:hidden}.gog-table__td--num{text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-num-font-size);font-family:var(--gog-table-numeric-font-family);width:var(--gog-table-num-col-width)}.gog-table__row:last-child .gog-table__td{border-bottom:none}.gog-table__row{transition:background-color var(--gog-table-row-transition-duration) var(--gog-easing)}.gog-table__row:hover{background-color:var(--gog-table-hover-bg)}.gog-table__empty{padding:var(--gog-table-empty-padding);text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-empty-font-size)}.gog-table--loading thead{opacity:var(--gog-table-loading-opacity);pointer-events:none}.gog-table__loading-cell{padding:var(--gog-table-loading-padding);text-align:center}.gog-table--col-borders .gog-table__th:not(:last-child),.gog-table--col-borders .gog-table__td:not(:last-child){border-right:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color)}.gog-table__footer{display:grid;grid-template-columns:1fr auto 1fr;grid-template-areas:\"left center right\";align-items:center;min-height:var(--gog-table-footer-min-height);gap:var(--gog-table-footer-gap)}.gog-table__total{font-size:var(--gog-table-total-font-size);color:var(--gog-table-muted-color);font-family:var(--gog-table-numeric-font-family);text-transform:var(--gog-table-total-text-transform);letter-spacing:var(--gog-table-total-letter-spacing)}.gog-table__total[style*=\"grid-area: right\"]{text-align:right}.gog-table__pagination[style*=\"grid-area: left\"]{justify-content:flex-start}.gog-table__pagination[style*=\"grid-area: center\"]{justify-content:center}.gog-table__pagination[style*=\"grid-area: right\"]{justify-content:flex-end}@media(prefers-reduced-motion:reduce){.gog-table__row{transition:none}}\n"], dependencies: [{ kind: "component", type: SpinnerComponent, selector: "gog-spinner", inputs: ["size", "overlay", "ariaLabel", "variant"] }, { kind: "component", type: PaginatorComponent, selector: "gog-paginator", inputs: ["page", "fullWidth", "totalPages", "rangeMode", "visiblePages", "showFirstPage", "showLastPage", "siblingCount", "size", "disabled", "ariaLabel"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "gog-icon", inputs: ["name", "template", "title", "ariaHidden"] }, { kind: "component", type: ScrollComponent, selector: "gog-scroll", inputs: ["axis", "size", "autoHide", "hideDelay", "reachThreshold", "focusable", "ariaLabel", "overscrollBehavior", "showTrack"], outputs: ["gogScroll", "gogReachStart", "gogReachEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7609
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: TableComponent, isStandalone: true, selector: "gog-table", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, showPageSizeSelect: { classPropertyName: "showPageSizeSelect", publicName: "showPageSizeSelect", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, interactiveRows: { classPropertyName: "interactiveRows", publicName: "interactiveRows", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, showSelectionColumn: { classPropertyName: "showSelectionColumn", publicName: "showSelectionColumn", isSignal: true, isRequired: false, transformFunction: null }, showRowNumbers: { classPropertyName: "showRowNumbers", publicName: "showRowNumbers", isSignal: true, isRequired: false, transformFunction: null }, showTotal: { classPropertyName: "showTotal", publicName: "showTotal", isSignal: true, isRequired: false, transformFunction: null }, emptyPlaceholder: { classPropertyName: "emptyPlaceholder", publicName: "emptyPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, paginatorPosition: { classPropertyName: "paginatorPosition", publicName: "paginatorPosition", isSignal: true, isRequired: false, transformFunction: null }, totalPosition: { classPropertyName: "totalPosition", publicName: "totalPosition", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, showColumnBorders: { classPropertyName: "showColumnBorders", publicName: "showColumnBorders", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageSize: "pageSizeChange", selection: "selectionChange", gogSortChange: "gogSortChange", gogPageChange: "gogPageChange", gogRowClick: "gogRowClick" }, host: { properties: { "style.display": "\"block\"", "style.width": "fullWidth() ? \"100%\" : \"fit-content\"" }, classAttribute: "gog-table-host" }, queries: [{ propertyName: "columns", predicate: GogColumn, isSignal: true }, { propertyName: "templates", predicate: TemplateDirective, isSignal: true }], ngImport: i0, template: "<div class=\"gog-table-wrapper gog-contained-layout\">\r\n <gog-scroll axis=\"horizontal\" class=\"gog-table-scroll\">\r\n <table\r\n class=\"gog-table\"\r\n [class]=\"sizeClass()\"\r\n [class.gog-table--col-borders]=\"showColumnBorders()\"\r\n [class.gog-table--loading]=\"loading()\"\r\n [class.gog-table--sticky-header]=\"stickyHeader()\"\r\n [style.width]=\"fullWidth() ? '100%' : 'fit-content'\"\r\n >\r\n <colgroup>\r\n @if (hasSelectionColumn()) {\r\n <col class=\"gog-table__col--select\" />\r\n }\r\n @if (showRowNumbers()) {\r\n <col class=\"gog-table__col--num\" />\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <col\r\n [style.width]=\"col.width() || null\"\r\n [style.min-width]=\"col.minWidth() || null\"\r\n [style.max-width]=\"col.maxWidth() || null\"\r\n />\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @if (hasSelectionColumn()) {\r\n <th class=\"gog-table__th gog-table__th--select\" scope=\"col\">\r\n <!--\r\n Only `multiple` gets a select-all: in `single` mode there is nothing to select\r\n all of, and a checkbox that can only ever check one row is a lie.\r\n -->\r\n @if (selectionMode() === 'multiple') {\r\n <gog-checkbox\r\n [checked]=\"allPageRowsSelected()\"\r\n [indeterminate]=\"somePageRowsSelected()\"\r\n [disabled]=\"loading() || visibleRows().length === 0\"\r\n [ariaLabel]=\"resolvedLabels().selectAllRows\"\r\n (checkedChange)=\"toggleAllOnPage($event)\"\r\n />\r\n }\r\n </th>\r\n }\r\n @if (showRowNumbers()) {\r\n <th class=\"gog-table__th gog-table__th--num\" scope=\"col\">#</th>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <th\r\n class=\"gog-table__th\"\r\n scope=\"col\"\r\n [class.gog-table__th--sortable]=\"col.sortable() && !loading()\"\r\n [class.gog-table__th--sorted]=\"getSortDirection(col.field())\"\r\n [attr.aria-sort]=\"getAriaSort(col.field())\"\r\n [attr.tabindex]=\"col.sortable() && !loading() ? 0 : null\"\r\n (click)=\"handleSortClick(col)\"\r\n (keydown.enter)=\"handleSortClick(col)\"\r\n (keydown.space)=\"handleSortClick(col); $event.preventDefault()\"\r\n >\r\n @if (getHeaderTemplate(col); as headerTpl) {\r\n <ng-container *ngTemplateOutlet=\"headerTpl; context: headerContext(col)\" />\r\n } @else {\r\n <span class=\"gog-table__th-inner\">\r\n {{ col.header() || col.field() }}\r\n @if (col.sortable() && !loading()) {\r\n <span class=\"gog-table__sort-icon\" aria-hidden=\"true\">\r\n @if (getSortDirection(col.field()) === 'asc') {\r\n <gog-icon name=\"sort-up\" />\r\n } @else if (getSortDirection(col.field()) === 'desc') {\r\n <gog-icon name=\"sort-down\" />\r\n } @else {\r\n <gog-icon name=\"sort\" />\r\n }\r\n </span>\r\n }\r\n </span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr>\r\n <td class=\"gog-table__loading-cell\" [attr.colspan]=\"emptyColspan()\">\r\n <gog-spinner size=\"md\" />\r\n </td>\r\n </tr>\r\n } @else if (visibleRows().length === 0) {\r\n <tr>\r\n <td class=\"gog-table__empty\" [attr.colspan]=\"emptyColspan()\">\u2014</td>\r\n </tr>\r\n } @else {\r\n @for (row of visibleRows(); track rowKey(row); let i = $index) {\r\n <tr\r\n class=\"gog-table__row\"\r\n [class.gog-table__row--interactive]=\"interactiveRows()\"\r\n [class.gog-table__row--selected]=\"isSelected(row)\"\r\n [attr.tabindex]=\"interactiveRows() ? 0 : null\"\r\n [attr.aria-selected]=\"hasSelection() ? isSelected(row) : null\"\r\n (click)=\"emitRowClick(row, i, $event)\"\r\n (keydown)=\"onRowKeydown(row, i, $event)\"\r\n >\r\n @if (hasSelectionColumn()) {\r\n <td class=\"gog-table__td gog-table__td--select\">\r\n <!--\r\n `$event.stopPropagation()` so ticking the box does not also count as a row\r\n click: with `interactiveRows` those are two different intents, and firing both\r\n from one gesture is how a \"select\" ends up navigating away.\r\n -->\r\n <gog-checkbox\r\n [checked]=\"isSelected(row)\"\r\n [ariaLabel]=\"resolvedLabels().selectRow\"\r\n (click)=\"$event.stopPropagation()\"\r\n (checkedChange)=\"toggleRowSelection(row, $event)\"\r\n />\r\n </td>\r\n }\r\n @if (showRowNumbers()) {\r\n <td class=\"gog-table__td gog-table__td--num\">{{ globalRowIndex(i) }}</td>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <td class=\"gog-table__td\">\r\n @if (getBodyTemplate(col); as bodyTpl) {\r\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: bodyContext(row, col, i)\" />\r\n } @else {\r\n {{ formatCellValue(row, col.field()) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </gog-scroll>\r\n\r\n @if (hasPagination() || showTotal()) {\r\n <div class=\"gog-table__footer\">\r\n @if (showTotal()) {\r\n <span class=\"gog-table__total\" [style.grid-area]=\"totalGridArea()\">\r\n {{ resolvedLabels().total }}: {{ rowCount() }}\r\n </span>\r\n }\r\n\r\n @if (hasPagination()) {\r\n <!--\r\n `[(pageSize)]` straight through to the table's own model: the rows-per-page select\r\n writes back here, and a consumer binding `[(pageSize)]` on the table sees it. No\r\n intermediate signal, in either direction.\r\n -->\r\n <gog-paginator\r\n class=\"gog-table__pagination\"\r\n [style.grid-area]=\"paginatorGridArea()\"\r\n [(page)]=\"currentPage\"\r\n [(pageSize)]=\"pageSize\"\r\n [totalPages]=\"totalPages()\"\r\n [showPageSizeSelect]=\"showPageSizeSelect()\"\r\n [pageSizeOptions]=\"pageSizeOptions()\"\r\n rangeMode=\"ellipsis\"\r\n size=\"sm\"\r\n [ariaLabel]=\"resolvedLabels().pagination\"\r\n />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.gog-table-wrapper{display:flex;flex-direction:column;gap:var(--gog-table-gap);width:100%;overflow-anchor:none}.gog-table-scroll{width:100%}.gog-table{width:100%;border-collapse:collapse;border:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);background-color:var(--gog-table-surface);color:var(--gog-table-text-color);font-family:var(--gog-table-font-family);table-layout:fixed}.gog-table--slg{--gog-table-size-th-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-td-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-th-font-size: var(--gog-table-slg-th-font-size);--gog-table-size-td-font-size: var(--gog-table-slg-td-font-size)}.gog-table--md{--gog-table-size-th-padding-v: var(--gog-table-md-padding-v);--gog-table-size-td-padding-v: var(--gog-table-md-padding-v);--gog-table-size-th-font-size: var(--gog-table-md-th-font-size);--gog-table-size-td-font-size: var(--gog-table-md-td-font-size)}.gog-table--sm{--gog-table-size-th-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-th-font-size: var(--gog-table-sm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-sm-td-font-size)}.gog-table--xsm{--gog-table-size-th-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-th-font-size: var(--gog-table-xsm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-xsm-td-font-size)}.gog-table__col--num{width:var(--gog-table-num-col-width)}.gog-table__th{padding:var(--gog-table-th-padding-v, var(--gog-table-size-th-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);text-align:left;font-family:var(--gog-table-header-font-family);font-size:var(--gog-table-th-font-size, var(--gog-table-size-th-font-size, var(--gog-table-lg-th-font-size)));text-transform:var(--gog-table-header-text-transform);letter-spacing:var(--gog-table-header-letter-spacing);color:var(--gog-table-accent-color);background-color:var(--gog-table-surface);border-bottom:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);white-space:normal;overflow:hidden}.gog-table--sticky-header .gog-table__th{position:sticky;top:0;z-index:1}.gog-table__th--num{width:var(--gog-table-num-col-width);text-align:center;color:var(--gog-table-muted-color)}.gog-table__th--select,.gog-table__td--select{width:var(--gog-table-select-col-width);text-align:center}.gog-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.gog-table__th--sortable:focus-visible{outline:var(--gog-table-focus-ring-width) solid var(--gog-table-focus-ring);outline-offset:calc(var(--gog-table-focus-ring-width) * -1)}.gog-table__th--sortable:hover,.gog-table__th--sorted{color:var(--gog-table-accent-bright)}.gog-table__th-inner{display:inline-flex;align-items:center;gap:var(--gog-table-th-inner-gap);width:100%}.gog-table__sort-icon{display:inline-block;width:var(--gog-table-sort-icon-width);text-align:center;font-size:var(--gog-table-sort-icon-size);opacity:var(--gog-table-sort-icon-opacity);flex-shrink:0}.gog-table__th--sorted .gog-table__sort-icon{opacity:1}.gog-table__td{padding:var(--gog-table-td-padding-v, var(--gog-table-size-td-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);font-size:var(--gog-table-td-font-size, var(--gog-table-size-td-font-size, var(--gog-table-lg-td-font-size)));border-bottom:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color);vertical-align:middle;overflow-wrap:break-word;word-break:break-word;overflow:hidden}.gog-table__td--num{text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-num-font-size);font-family:var(--gog-table-numeric-font-family);width:var(--gog-table-num-col-width)}.gog-table__row:last-child .gog-table__td{border-bottom:none}.gog-table__row{transition:background-color var(--gog-table-row-transition-duration) var(--gog-easing)}.gog-table__row--interactive{cursor:pointer}.gog-table__row--interactive:focus-visible{outline:var(--gog-table-focus-ring-width) solid var(--gog-table-focus-ring);outline-offset:calc(var(--gog-table-focus-ring-width) * -1)}.gog-table__row:hover{background-color:var(--gog-table-hover-bg)}.gog-table__row--selected,.gog-table__row--selected:hover{background-color:var(--gog-table-selected-bg)}.gog-table__empty{padding:var(--gog-table-empty-padding);text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-empty-font-size)}.gog-table--loading thead{opacity:var(--gog-table-loading-opacity);pointer-events:none}.gog-table__loading-cell{padding:var(--gog-table-loading-padding);text-align:center}.gog-table--col-borders .gog-table__th:not(:last-child),.gog-table--col-borders .gog-table__td:not(:last-child){border-right:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color)}.gog-table__footer{display:grid;grid-template-columns:1fr auto 1fr;grid-template-areas:\"left center right\";align-items:center;min-height:var(--gog-table-footer-min-height);gap:var(--gog-table-footer-gap)}.gog-table__total{font-size:var(--gog-table-total-font-size);color:var(--gog-table-muted-color);font-family:var(--gog-table-numeric-font-family);text-transform:var(--gog-table-total-text-transform);letter-spacing:var(--gog-table-total-letter-spacing)}.gog-table__total[style*=\"grid-area: right\"]{text-align:right}.gog-table__pagination[style*=\"grid-area: left\"]{justify-content:flex-start}.gog-table__pagination[style*=\"grid-area: center\"]{justify-content:center}.gog-table__pagination[style*=\"grid-area: right\"]{justify-content:flex-end}@media(prefers-reduced-motion:reduce){.gog-table__row{transition:none}}\n"], dependencies: [{ kind: "component", type: SpinnerComponent, selector: "gog-spinner", inputs: ["size", "overlay", "ariaLabel", "variant"] }, { kind: "component", type: PaginatorComponent, selector: "gog-paginator", inputs: ["page", "fullWidth", "totalPages", "totalRecords", "pageSize", "showPageSizeSelect", "pageSizeOptions", "rangeMode", "visiblePages", "showFirstPage", "showLastPage", "siblingCount", "size", "disabled", "ariaLabel"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconComponent, selector: "gog-icon", inputs: ["name", "template", "title", "ariaHidden"] }, { kind: "component", type: ScrollComponent, selector: "gog-scroll", inputs: ["axis", "size", "autoHide", "hideDelay", "reachThreshold", "focusable", "ariaLabel", "overscrollBehavior", "showTrack"], outputs: ["gogScroll", "gogReachStart", "gogReachEnd"] }, { kind: "component", type: CheckboxComponent, selector: "gog-checkbox", inputs: ["label", "ariaLabel", "size", "indeterminate", "disabled", "fullWidth", "checkIconTemplate", "checked"], outputs: ["checkedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7043
7610
  }
7044
7611
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TableComponent, decorators: [{
7045
7612
  type: Component,
7046
- args: [{ selector: 'gog-table', imports: [SpinnerComponent, PaginatorComponent, NgTemplateOutlet, IconComponent, ScrollComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
7613
+ args: [{ selector: 'gog-table', imports: [
7614
+ SpinnerComponent,
7615
+ PaginatorComponent,
7616
+ NgTemplateOutlet,
7617
+ IconComponent,
7618
+ ScrollComponent,
7619
+ CheckboxComponent,
7620
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
7047
7621
  class: 'gog-table-host',
7048
7622
  '[style.display]': '"block"',
7049
7623
  '[style.width]': 'fullWidth() ? "100%" : "fit-content"',
7050
- }, template: "<div class=\"gog-table-wrapper gog-contained-layout\">\r\n <gog-scroll axis=\"horizontal\" class=\"gog-table-scroll\">\r\n <table\r\n class=\"gog-table\"\r\n [class]=\"sizeClass()\"\r\n [class.gog-table--col-borders]=\"showColumnBorders()\"\r\n [class.gog-table--loading]=\"loading()\"\r\n [class.gog-table--sticky-header]=\"stickyHeader()\"\r\n [style.width]=\"fullWidth() ? '100%' : 'fit-content'\"\r\n >\r\n <colgroup>\r\n @if (showRowNumbers()) {\r\n <col class=\"gog-table__col--num\" />\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <col\r\n [style.width]=\"col.width() || null\"\r\n [style.min-width]=\"col.minWidth() || null\"\r\n [style.max-width]=\"col.maxWidth() || null\"\r\n />\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @if (showRowNumbers()) {\r\n <th class=\"gog-table__th gog-table__th--num\" scope=\"col\">#</th>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <th\r\n class=\"gog-table__th\"\r\n scope=\"col\"\r\n [class.gog-table__th--sortable]=\"col.sortable() && !loading()\"\r\n [class.gog-table__th--sorted]=\"getSortDirection(col.field())\"\r\n [attr.aria-sort]=\"getAriaSort(col.field())\"\r\n [attr.tabindex]=\"col.sortable() && !loading() ? 0 : null\"\r\n (click)=\"handleSortClick(col)\"\r\n (keydown.enter)=\"handleSortClick(col)\"\r\n (keydown.space)=\"handleSortClick(col); $event.preventDefault()\"\r\n >\r\n @if (getHeaderTemplate(col); as headerTpl) {\r\n <ng-container *ngTemplateOutlet=\"headerTpl; context: headerContext(col)\" />\r\n } @else {\r\n <span class=\"gog-table__th-inner\">\r\n {{ col.header() || col.field() }}\r\n @if (col.sortable() && !loading()) {\r\n <span class=\"gog-table__sort-icon\" aria-hidden=\"true\">\r\n @if (getSortDirection(col.field()) === 'asc') {\r\n <gog-icon name=\"sort-up\" />\r\n } @else if (getSortDirection(col.field()) === 'desc') {\r\n <gog-icon name=\"sort-down\" />\r\n } @else {\r\n <gog-icon name=\"sort\" />\r\n }\r\n </span>\r\n }\r\n </span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr>\r\n <td class=\"gog-table__loading-cell\" [attr.colspan]=\"emptyColspan()\">\r\n <gog-spinner size=\"md\" />\r\n </td>\r\n </tr>\r\n } @else if (visibleRows().length === 0) {\r\n <tr>\r\n <td class=\"gog-table__empty\" [attr.colspan]=\"emptyColspan()\">\u2014</td>\r\n </tr>\r\n } @else {\r\n @for (row of visibleRows(); track $index; let i = $index) {\r\n <tr class=\"gog-table__row\">\r\n @if (showRowNumbers()) {\r\n <td class=\"gog-table__td gog-table__td--num\">{{ globalRowIndex(i) }}</td>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <td class=\"gog-table__td\">\r\n @if (getBodyTemplate(col); as bodyTpl) {\r\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: bodyContext(row, col, i)\" />\r\n } @else {\r\n {{ formatCellValue(row, col.field()) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </gog-scroll>\r\n\r\n @if (hasPagination() || showTotal()) {\r\n <div class=\"gog-table__footer\">\r\n @if (showTotal()) {\r\n <span class=\"gog-table__total\" [style.grid-area]=\"totalGridArea()\">\r\n Total: {{ value().length }}\r\n </span>\r\n }\r\n\r\n @if (hasPagination()) {\r\n <gog-paginator\r\n class=\"gog-table__pagination\"\r\n [style.grid-area]=\"paginatorGridArea()\"\r\n [(page)]=\"currentPage\"\r\n [totalPages]=\"totalPages()\"\r\n rangeMode=\"ellipsis\"\r\n size=\"sm\"\r\n ariaLabel=\"Table pagination\"\r\n />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".gog-table-wrapper{display:flex;flex-direction:column;gap:var(--gog-table-gap);width:100%;overflow-anchor:none}.gog-table-scroll{width:100%}.gog-table{width:100%;border-collapse:collapse;border:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);background-color:var(--gog-table-surface);color:var(--gog-table-text-color);font-family:var(--gog-table-font-family);table-layout:fixed}.gog-table--slg{--gog-table-size-th-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-td-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-th-font-size: var(--gog-table-slg-th-font-size);--gog-table-size-td-font-size: var(--gog-table-slg-td-font-size)}.gog-table--md{--gog-table-size-th-padding-v: var(--gog-table-md-padding-v);--gog-table-size-td-padding-v: var(--gog-table-md-padding-v);--gog-table-size-th-font-size: var(--gog-table-md-th-font-size);--gog-table-size-td-font-size: var(--gog-table-md-td-font-size)}.gog-table--sm{--gog-table-size-th-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-th-font-size: var(--gog-table-sm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-sm-td-font-size)}.gog-table--xsm{--gog-table-size-th-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-th-font-size: var(--gog-table-xsm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-xsm-td-font-size)}.gog-table__col--num{width:var(--gog-table-num-col-width)}.gog-table__th{padding:var(--gog-table-th-padding-v, var(--gog-table-size-th-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);text-align:left;font-family:var(--gog-table-header-font-family);font-size:var(--gog-table-th-font-size, var(--gog-table-size-th-font-size, var(--gog-table-lg-th-font-size)));text-transform:var(--gog-table-header-text-transform);letter-spacing:var(--gog-table-header-letter-spacing);color:var(--gog-table-accent-color);background-color:var(--gog-table-surface);border-bottom:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);white-space:normal;overflow:hidden}.gog-table--sticky-header .gog-table__th{position:sticky;top:0;z-index:1}.gog-table__th--num{width:var(--gog-table-num-col-width);text-align:center;color:var(--gog-table-muted-color)}.gog-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.gog-table__th--sortable:focus-visible{outline:var(--gog-table-focus-ring-width) solid var(--gog-table-focus-ring);outline-offset:calc(var(--gog-table-focus-ring-width) * -1)}.gog-table__th--sortable:hover,.gog-table__th--sorted{color:var(--gog-table-accent-bright)}.gog-table__th-inner{display:inline-flex;align-items:center;gap:var(--gog-table-th-inner-gap);width:100%}.gog-table__sort-icon{display:inline-block;width:var(--gog-table-sort-icon-width);text-align:center;font-size:var(--gog-table-sort-icon-size);opacity:var(--gog-table-sort-icon-opacity);flex-shrink:0}.gog-table__th--sorted .gog-table__sort-icon{opacity:1}.gog-table__td{padding:var(--gog-table-td-padding-v, var(--gog-table-size-td-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);font-size:var(--gog-table-td-font-size, var(--gog-table-size-td-font-size, var(--gog-table-lg-td-font-size)));border-bottom:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color);vertical-align:middle;overflow-wrap:break-word;word-break:break-word;overflow:hidden}.gog-table__td--num{text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-num-font-size);font-family:var(--gog-table-numeric-font-family);width:var(--gog-table-num-col-width)}.gog-table__row:last-child .gog-table__td{border-bottom:none}.gog-table__row{transition:background-color var(--gog-table-row-transition-duration) var(--gog-easing)}.gog-table__row:hover{background-color:var(--gog-table-hover-bg)}.gog-table__empty{padding:var(--gog-table-empty-padding);text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-empty-font-size)}.gog-table--loading thead{opacity:var(--gog-table-loading-opacity);pointer-events:none}.gog-table__loading-cell{padding:var(--gog-table-loading-padding);text-align:center}.gog-table--col-borders .gog-table__th:not(:last-child),.gog-table--col-borders .gog-table__td:not(:last-child){border-right:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color)}.gog-table__footer{display:grid;grid-template-columns:1fr auto 1fr;grid-template-areas:\"left center right\";align-items:center;min-height:var(--gog-table-footer-min-height);gap:var(--gog-table-footer-gap)}.gog-table__total{font-size:var(--gog-table-total-font-size);color:var(--gog-table-muted-color);font-family:var(--gog-table-numeric-font-family);text-transform:var(--gog-table-total-text-transform);letter-spacing:var(--gog-table-total-letter-spacing)}.gog-table__total[style*=\"grid-area: right\"]{text-align:right}.gog-table__pagination[style*=\"grid-area: left\"]{justify-content:flex-start}.gog-table__pagination[style*=\"grid-area: center\"]{justify-content:center}.gog-table__pagination[style*=\"grid-area: right\"]{justify-content:flex-end}@media(prefers-reduced-motion:reduce){.gog-table__row{transition:none}}\n"] }]
7051
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], showRowNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRowNumbers", required: false }] }], showTotal: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTotal", required: false }] }], emptyPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyPlaceholder", required: false }] }], paginatorPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginatorPosition", required: false }] }], totalPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalPosition", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showColumnBorders: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnBorders", required: false }] }], stickyHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeader", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], columns: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => GogColumn), { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TemplateDirective), { isSignal: true }] }] } });
7624
+ }, template: "<div class=\"gog-table-wrapper gog-contained-layout\">\r\n <gog-scroll axis=\"horizontal\" class=\"gog-table-scroll\">\r\n <table\r\n class=\"gog-table\"\r\n [class]=\"sizeClass()\"\r\n [class.gog-table--col-borders]=\"showColumnBorders()\"\r\n [class.gog-table--loading]=\"loading()\"\r\n [class.gog-table--sticky-header]=\"stickyHeader()\"\r\n [style.width]=\"fullWidth() ? '100%' : 'fit-content'\"\r\n >\r\n <colgroup>\r\n @if (hasSelectionColumn()) {\r\n <col class=\"gog-table__col--select\" />\r\n }\r\n @if (showRowNumbers()) {\r\n <col class=\"gog-table__col--num\" />\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <col\r\n [style.width]=\"col.width() || null\"\r\n [style.min-width]=\"col.minWidth() || null\"\r\n [style.max-width]=\"col.maxWidth() || null\"\r\n />\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @if (hasSelectionColumn()) {\r\n <th class=\"gog-table__th gog-table__th--select\" scope=\"col\">\r\n <!--\r\n Only `multiple` gets a select-all: in `single` mode there is nothing to select\r\n all of, and a checkbox that can only ever check one row is a lie.\r\n -->\r\n @if (selectionMode() === 'multiple') {\r\n <gog-checkbox\r\n [checked]=\"allPageRowsSelected()\"\r\n [indeterminate]=\"somePageRowsSelected()\"\r\n [disabled]=\"loading() || visibleRows().length === 0\"\r\n [ariaLabel]=\"resolvedLabels().selectAllRows\"\r\n (checkedChange)=\"toggleAllOnPage($event)\"\r\n />\r\n }\r\n </th>\r\n }\r\n @if (showRowNumbers()) {\r\n <th class=\"gog-table__th gog-table__th--num\" scope=\"col\">#</th>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <th\r\n class=\"gog-table__th\"\r\n scope=\"col\"\r\n [class.gog-table__th--sortable]=\"col.sortable() && !loading()\"\r\n [class.gog-table__th--sorted]=\"getSortDirection(col.field())\"\r\n [attr.aria-sort]=\"getAriaSort(col.field())\"\r\n [attr.tabindex]=\"col.sortable() && !loading() ? 0 : null\"\r\n (click)=\"handleSortClick(col)\"\r\n (keydown.enter)=\"handleSortClick(col)\"\r\n (keydown.space)=\"handleSortClick(col); $event.preventDefault()\"\r\n >\r\n @if (getHeaderTemplate(col); as headerTpl) {\r\n <ng-container *ngTemplateOutlet=\"headerTpl; context: headerContext(col)\" />\r\n } @else {\r\n <span class=\"gog-table__th-inner\">\r\n {{ col.header() || col.field() }}\r\n @if (col.sortable() && !loading()) {\r\n <span class=\"gog-table__sort-icon\" aria-hidden=\"true\">\r\n @if (getSortDirection(col.field()) === 'asc') {\r\n <gog-icon name=\"sort-up\" />\r\n } @else if (getSortDirection(col.field()) === 'desc') {\r\n <gog-icon name=\"sort-down\" />\r\n } @else {\r\n <gog-icon name=\"sort\" />\r\n }\r\n </span>\r\n }\r\n </span>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @if (loading()) {\r\n <tr>\r\n <td class=\"gog-table__loading-cell\" [attr.colspan]=\"emptyColspan()\">\r\n <gog-spinner size=\"md\" />\r\n </td>\r\n </tr>\r\n } @else if (visibleRows().length === 0) {\r\n <tr>\r\n <td class=\"gog-table__empty\" [attr.colspan]=\"emptyColspan()\">\u2014</td>\r\n </tr>\r\n } @else {\r\n @for (row of visibleRows(); track rowKey(row); let i = $index) {\r\n <tr\r\n class=\"gog-table__row\"\r\n [class.gog-table__row--interactive]=\"interactiveRows()\"\r\n [class.gog-table__row--selected]=\"isSelected(row)\"\r\n [attr.tabindex]=\"interactiveRows() ? 0 : null\"\r\n [attr.aria-selected]=\"hasSelection() ? isSelected(row) : null\"\r\n (click)=\"emitRowClick(row, i, $event)\"\r\n (keydown)=\"onRowKeydown(row, i, $event)\"\r\n >\r\n @if (hasSelectionColumn()) {\r\n <td class=\"gog-table__td gog-table__td--select\">\r\n <!--\r\n `$event.stopPropagation()` so ticking the box does not also count as a row\r\n click: with `interactiveRows` those are two different intents, and firing both\r\n from one gesture is how a \"select\" ends up navigating away.\r\n -->\r\n <gog-checkbox\r\n [checked]=\"isSelected(row)\"\r\n [ariaLabel]=\"resolvedLabels().selectRow\"\r\n (click)=\"$event.stopPropagation()\"\r\n (checkedChange)=\"toggleRowSelection(row, $event)\"\r\n />\r\n </td>\r\n }\r\n @if (showRowNumbers()) {\r\n <td class=\"gog-table__td gog-table__td--num\">{{ globalRowIndex(i) }}</td>\r\n }\r\n @for (col of columns(); track col.field()) {\r\n <td class=\"gog-table__td\">\r\n @if (getBodyTemplate(col); as bodyTpl) {\r\n <ng-container *ngTemplateOutlet=\"bodyTpl; context: bodyContext(row, col, i)\" />\r\n } @else {\r\n {{ formatCellValue(row, col.field()) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n </gog-scroll>\r\n\r\n @if (hasPagination() || showTotal()) {\r\n <div class=\"gog-table__footer\">\r\n @if (showTotal()) {\r\n <span class=\"gog-table__total\" [style.grid-area]=\"totalGridArea()\">\r\n {{ resolvedLabels().total }}: {{ rowCount() }}\r\n </span>\r\n }\r\n\r\n @if (hasPagination()) {\r\n <!--\r\n `[(pageSize)]` straight through to the table's own model: the rows-per-page select\r\n writes back here, and a consumer binding `[(pageSize)]` on the table sees it. No\r\n intermediate signal, in either direction.\r\n -->\r\n <gog-paginator\r\n class=\"gog-table__pagination\"\r\n [style.grid-area]=\"paginatorGridArea()\"\r\n [(page)]=\"currentPage\"\r\n [(pageSize)]=\"pageSize\"\r\n [totalPages]=\"totalPages()\"\r\n [showPageSizeSelect]=\"showPageSizeSelect()\"\r\n [pageSizeOptions]=\"pageSizeOptions()\"\r\n rangeMode=\"ellipsis\"\r\n size=\"sm\"\r\n [ariaLabel]=\"resolvedLabels().pagination\"\r\n />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.gog-table-wrapper{display:flex;flex-direction:column;gap:var(--gog-table-gap);width:100%;overflow-anchor:none}.gog-table-scroll{width:100%}.gog-table{width:100%;border-collapse:collapse;border:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);background-color:var(--gog-table-surface);color:var(--gog-table-text-color);font-family:var(--gog-table-font-family);table-layout:fixed}.gog-table--slg{--gog-table-size-th-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-td-padding-v: var(--gog-table-slg-padding-v);--gog-table-size-th-font-size: var(--gog-table-slg-th-font-size);--gog-table-size-td-font-size: var(--gog-table-slg-td-font-size)}.gog-table--md{--gog-table-size-th-padding-v: var(--gog-table-md-padding-v);--gog-table-size-td-padding-v: var(--gog-table-md-padding-v);--gog-table-size-th-font-size: var(--gog-table-md-th-font-size);--gog-table-size-td-font-size: var(--gog-table-md-td-font-size)}.gog-table--sm{--gog-table-size-th-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-sm-padding-v);--gog-table-size-th-font-size: var(--gog-table-sm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-sm-td-font-size)}.gog-table--xsm{--gog-table-size-th-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-td-padding-v: var(--gog-table-xsm-padding-v);--gog-table-size-th-font-size: var(--gog-table-xsm-th-font-size);--gog-table-size-td-font-size: var(--gog-table-xsm-td-font-size)}.gog-table__col--num{width:var(--gog-table-num-col-width)}.gog-table__th{padding:var(--gog-table-th-padding-v, var(--gog-table-size-th-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);text-align:left;font-family:var(--gog-table-header-font-family);font-size:var(--gog-table-th-font-size, var(--gog-table-size-th-font-size, var(--gog-table-lg-th-font-size)));text-transform:var(--gog-table-header-text-transform);letter-spacing:var(--gog-table-header-letter-spacing);color:var(--gog-table-accent-color);background-color:var(--gog-table-surface);border-bottom:var(--gog-table-border-width) var(--gog-table-border-style) var(--gog-table-border-color);white-space:normal;overflow:hidden}.gog-table--sticky-header .gog-table__th{position:sticky;top:0;z-index:1}.gog-table__th--num{width:var(--gog-table-num-col-width);text-align:center;color:var(--gog-table-muted-color)}.gog-table__th--select,.gog-table__td--select{width:var(--gog-table-select-col-width);text-align:center}.gog-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.gog-table__th--sortable:focus-visible{outline:var(--gog-table-focus-ring-width) solid var(--gog-table-focus-ring);outline-offset:calc(var(--gog-table-focus-ring-width) * -1)}.gog-table__th--sortable:hover,.gog-table__th--sorted{color:var(--gog-table-accent-bright)}.gog-table__th-inner{display:inline-flex;align-items:center;gap:var(--gog-table-th-inner-gap);width:100%}.gog-table__sort-icon{display:inline-block;width:var(--gog-table-sort-icon-width);text-align:center;font-size:var(--gog-table-sort-icon-size);opacity:var(--gog-table-sort-icon-opacity);flex-shrink:0}.gog-table__th--sorted .gog-table__sort-icon{opacity:1}.gog-table__td{padding:var(--gog-table-td-padding-v, var(--gog-table-size-td-padding-v, var(--gog-table-lg-padding-v))) var(--gog-table-padding-h);font-size:var(--gog-table-td-font-size, var(--gog-table-size-td-font-size, var(--gog-table-lg-td-font-size)));border-bottom:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color);vertical-align:middle;overflow-wrap:break-word;word-break:break-word;overflow:hidden}.gog-table__td--num{text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-num-font-size);font-family:var(--gog-table-numeric-font-family);width:var(--gog-table-num-col-width)}.gog-table__row:last-child .gog-table__td{border-bottom:none}.gog-table__row{transition:background-color var(--gog-table-row-transition-duration) var(--gog-easing)}.gog-table__row--interactive{cursor:pointer}.gog-table__row--interactive:focus-visible{outline:var(--gog-table-focus-ring-width) solid var(--gog-table-focus-ring);outline-offset:calc(var(--gog-table-focus-ring-width) * -1)}.gog-table__row:hover{background-color:var(--gog-table-hover-bg)}.gog-table__row--selected,.gog-table__row--selected:hover{background-color:var(--gog-table-selected-bg)}.gog-table__empty{padding:var(--gog-table-empty-padding);text-align:center;color:var(--gog-table-muted-color);font-size:var(--gog-table-empty-font-size)}.gog-table--loading thead{opacity:var(--gog-table-loading-opacity);pointer-events:none}.gog-table__loading-cell{padding:var(--gog-table-loading-padding);text-align:center}.gog-table--col-borders .gog-table__th:not(:last-child),.gog-table--col-borders .gog-table__td:not(:last-child){border-right:var(--gog-table-row-border-width) var(--gog-table-border-style) var(--gog-table-border-color)}.gog-table__footer{display:grid;grid-template-columns:1fr auto 1fr;grid-template-areas:\"left center right\";align-items:center;min-height:var(--gog-table-footer-min-height);gap:var(--gog-table-footer-gap)}.gog-table__total{font-size:var(--gog-table-total-font-size);color:var(--gog-table-muted-color);font-family:var(--gog-table-numeric-font-family);text-transform:var(--gog-table-total-text-transform);letter-spacing:var(--gog-table-total-letter-spacing)}.gog-table__total[style*=\"grid-area: right\"]{text-align:right}.gog-table__pagination[style*=\"grid-area: left\"]{justify-content:flex-start}.gog-table__pagination[style*=\"grid-area: center\"]{justify-content:center}.gog-table__pagination[style*=\"grid-area: right\"]{justify-content:flex-end}@media(prefers-reduced-motion:reduce){.gog-table__row{transition:none}}\n"] }]
7625
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], showPageSizeSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPageSizeSelect", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], totalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalRecords", required: false }] }], interactiveRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactiveRows", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }, { type: i0.Output, args: ["selectionChange"] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], showSelectionColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSelectionColumn", required: false }] }], showRowNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRowNumbers", required: false }] }], showTotal: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTotal", required: false }] }], emptyPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyPlaceholder", required: false }] }], paginatorPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginatorPosition", required: false }] }], totalPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalPosition", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], showColumnBorders: [{ type: i0.Input, args: [{ isSignal: true, alias: "showColumnBorders", required: false }] }], stickyHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeader", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], gogSortChange: [{ type: i0.Output, args: ["gogSortChange"] }], gogPageChange: [{ type: i0.Output, args: ["gogPageChange"] }], gogRowClick: [{ type: i0.Output, args: ["gogRowClick"] }], columns: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => GogColumn), { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TemplateDirective), { isSignal: true }] }] } });
7052
7626
 
7053
7627
  /** Built-in defaults, used when `GOG_CONFIG.theme` doesn't supply one. */
7054
7628
  const DEFAULT_THEME = 'light';
@@ -8168,6 +8742,7 @@ const GOG_TOKEN_GROUPS = [
8168
8742
  '--gog-paginator-ellipsis-font-size',
8169
8743
  '--gog-paginator-ellipsis-min-width',
8170
8744
  '--gog-paginator-gap',
8745
+ '--gog-paginator-page-size-min-width',
8171
8746
  ],
8172
8747
  },
8173
8748
  {
@@ -8438,6 +9013,8 @@ const GOG_TOKEN_GROUPS = [
8438
9013
  '--gog-table-padding-h',
8439
9014
  '--gog-table-row-border-width',
8440
9015
  '--gog-table-row-transition-duration',
9016
+ '--gog-table-select-col-width',
9017
+ '--gog-table-selected-bg',
8441
9018
  '--gog-table-slg-padding-v',
8442
9019
  '--gog-table-slg-td-font-size',
8443
9020
  '--gog-table-slg-th-font-size',
@@ -8777,5 +9354,5 @@ const GOG_TOKEN_GROUPS = [
8777
9354
  * Generated bundle index. Do not edit.
8778
9355
  */
8779
9356
 
8780
- export { AccordionComponent, AutocompleteComponent, ButtonComponent, ButtonToggleGroupComponent, CalendarComponent, CheckboxComponent, ChipComponent, CollapsibleComponent, Column, ConfirmationDialogComponent, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DialogComponent, DialogService, DividerComponent, GOG_CONFIG, GOG_TABS_STATE, GOG_TOKEN_GROUPS, GogAccordionChevronDirective, GogAccordionContentDirective, GogAccordionHeaderDirective, GogBadgeDirective, GogButtonToggleOptionDirective, GogCheckboxIconDirective, GogCollapsibleContentDirective, GogCollapsibleTriggerDirective, GogColumn, GogColumnBodyDirective, GogColumnHeaderDirective, GogDropdownBase, GogDropdownChevronDirective, GogDropdownOptionDirective, GogFloatLabelState, GogInputAddonEndDirective, GogInputAddonStartDirective, GogMultiselectClearIconDirective, GogTabContentDirective, GogTabHeaderDirective, GogTagIconDirective, GogTooltipDirective, ICON_DEFS, IconComponent, InputfieldComponent, MultiselectComponent, PaginatorComponent, ProgressbarComponent, RadioGroupComponent, ScrollComponent, SelectComponent, SkeletonComponent, SliderComponent, SpinnerComponent, SpinnerOverlayComponent, TabComponent, TableComponent, TabsComponent, TagComponent, TemplateDirective, TextareaComponent, ThemeService, ToastComponent, ToastContainerComponent, ToastService, ToggleComponent, addDays, addMonths, addYears, buildMonthGrid, clampDate, copyTimeOnto, daysInMonth, defaultCompare, formatDate, getByPath, isAfterDay, isBeforeDay, isInRange, isSameDay, isSameMonth, isSameOptionValue, isWithinBounds, localeFirstDayOfWeek, monthNames, parseDate, provideGogConfig, readOption, resolveConfigured, startOfDay, weekdayNames, withTime };
9357
+ export { AccordionComponent, AutocompleteComponent, ButtonComponent, ButtonToggleGroupComponent, CalendarComponent, CheckboxComponent, ChipComponent, CollapsibleComponent, Column, ConfirmationDialogComponent, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DialogComponent, DialogService, DividerComponent, GOG_CONFIG, GOG_ICONS, GOG_TABS_STATE, GOG_TOKEN_GROUPS, GogAccordionChevronDirective, GogAccordionContentDirective, GogAccordionHeaderDirective, GogBadgeDirective, GogButtonDirective, GogButtonToggleOptionDirective, GogCheckboxIconDirective, GogCollapsibleContentDirective, GogCollapsibleTriggerDirective, GogColumn, GogColumnBodyDirective, GogColumnHeaderDirective, GogDropdownBase, GogDropdownChevronDirective, GogDropdownOptionDirective, GogFloatLabelState, GogInputAddonEndDirective, GogInputAddonStartDirective, GogMultiselectClearIconDirective, GogTabContentDirective, GogTabHeaderDirective, GogTagIconDirective, GogTooltipDirective, ICON_DEFS, IconComponent, InputfieldComponent, MultiselectComponent, PaginatorComponent, ProgressbarComponent, RadioGroupComponent, ScrollComponent, SelectComponent, SkeletonComponent, SliderComponent, SpinnerComponent, SpinnerOverlayComponent, TabComponent, TableComponent, TabsComponent, TagComponent, TemplateDirective, TextareaComponent, ThemeService, ToastComponent, ToastContainerComponent, ToastService, ToggleComponent, addDays, addMonths, addYears, buildMonthGrid, clampDate, copyTimeOnto, daysInMonth, defaultCompare, formatDate, getByPath, isAfterDay, isBeforeDay, isInRange, isSameDay, isSameMonth, isSameOptionValue, isWithinBounds, localeFirstDayOfWeek, monthNames, parseDate, provideGogConfig, provideGogIcons, readOption, resolveConfigured, startOfDay, weekdayNames, withTime };
8781
9358
  //# sourceMappingURL=guildofgleks-ui.mjs.map