@masmarino/gabarit 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, input, computed, ChangeDetectionStrategy, Component, output, signal, viewChild, HostListener, booleanAttribute, forwardRef, ElementRef, effect, contentChildren, viewChildren, InjectionToken, isDevMode, Injector, afterNextRender } from '@angular/core';
|
|
2
|
+
import { Injectable, inject, input, computed, ChangeDetectionStrategy, Component, output, signal, viewChild, HostListener, booleanAttribute, forwardRef, ElementRef, effect, contentChildren, viewChildren, model, InjectionToken, isDevMode, Injector, afterNextRender } from '@angular/core';
|
|
3
3
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
4
|
-
import {
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
5
|
import * as i1 from '@angular/forms';
|
|
6
|
-
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormControl, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
7
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
7
8
|
import { isObservable } from 'rxjs';
|
|
8
9
|
|
|
9
|
-
const GABARIT_VERSION = '0.
|
|
10
|
+
const GABARIT_VERSION = '0.6.0';
|
|
10
11
|
|
|
11
12
|
const BUILT_IN_ICONS = {
|
|
12
13
|
search: `<path d="m21 21-4.34-4.34" />
|
|
@@ -20,6 +21,8 @@ const BUILT_IN_ICONS = {
|
|
|
20
21
|
<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" />
|
|
21
22
|
<path d="m2 2 20 20" />`,
|
|
22
23
|
'chevron-down': `<path d="m6 9 6 6 6-6" />`,
|
|
24
|
+
'chevron-left': `<path d="m15 18-6-6 6-6" />`,
|
|
25
|
+
'chevron-right': `<path d="m9 18 6-6-6-6" />`,
|
|
23
26
|
'chevrons-left': `<path d="m11 17-5-5 5-5" />
|
|
24
27
|
<path d="m18 17-5-5 5-5" />`,
|
|
25
28
|
'chevrons-right': `<path d="m6 17 5-5-5-5" />
|
|
@@ -36,6 +39,10 @@ const BUILT_IN_ICONS = {
|
|
|
36
39
|
<path d="M12 17h.01" />`,
|
|
37
40
|
info: `<path d="M12 17v-6" />
|
|
38
41
|
<path d="M12 7h.01" />`,
|
|
42
|
+
'arrow-up': `<path d="m5 12 7-7 7 7" />
|
|
43
|
+
<path d="M12 19V5" />`,
|
|
44
|
+
'arrow-down': `<path d="M12 5v14" />
|
|
45
|
+
<path d="m19 12-7 7-7-7" />`,
|
|
39
46
|
};
|
|
40
47
|
|
|
41
48
|
class IconRegistry {
|
|
@@ -219,23 +226,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
219
226
|
args: [{ selector: 'gbt-button', standalone: true, imports: [Icon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [type]=\"type()\"\n class=\"gbt-button gbt-button--{{ variant() }} gbt-button--{{ size() }}\"\n [disabled]=\"disabled() || loading()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n (click)=\"handleClick()\"\n>\n @if (iconName()) {\n <gbt-icon [name]=\"iconName()!\" aria-hidden=\"true\" />\n }\n @if (loading()) {\n <span class=\"gbt-button__spinner\" aria-hidden=\"true\"></span>\n <span class=\"sr-only\">{{ loadingLabel() }}</span>\n }\n <span>{{ text() }}</span>\n</button>\n", styles: [":host{display:inline-block;width:fit-content}.gbt-button{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;border:none;border-radius:var(--site-border-radius-sm);font-family:var(--font-family);font-weight:600;cursor:pointer;transition:background-color var(--site-transition-fast),opacity var(--site-transition-fast)}.gbt-button:disabled{cursor:not-allowed;opacity:.5}.gbt-button--small{padding:.375rem .75rem;font-size:.8125rem}.gbt-button--medium{padding:.5rem 1rem;font-size:.875rem}.gbt-button--large{padding:.75rem 1.5rem;font-size:1rem}.gbt-button--primary{background:var(--primary);color:var(--text-on-primary)}.gbt-button--primary:not(:disabled):hover{background:var(--primary-hover)}.gbt-button--secondary{background:var(--bg-panel);color:var(--text-primary);border:1px solid var(--border-color)}.gbt-button--secondary:not(:disabled):hover{background:var(--bg-hover)}.gbt-button--danger{background:var(--color-error-fill);color:var(--text-on-error)}.gbt-button--danger:not(:disabled):hover{background:var(--color-error-hover)}.gbt-button__spinner{width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:gbt-button-spin .6s linear infinite}@media(prefers-reduced-motion:reduce){.gbt-button__spinner{animation:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@keyframes gbt-button-spin{to{transform:rotate(360deg)}}\n"] }]
|
|
220
227
|
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], iconName: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconName", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
|
|
221
228
|
|
|
222
|
-
class
|
|
223
|
-
|
|
224
|
-
|
|
229
|
+
class Badge {
|
|
230
|
+
variant = input('neutral', /* @ts-ignore */
|
|
231
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
232
|
+
icon = input(/* @ts-ignore */
|
|
233
|
+
...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
234
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Badge, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
235
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Badge, isStandalone: true, selector: "gbt-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span class=\"gbt-badge\" [attr.data-variant]=\"variant()\">\n @if (icon(); as name) {\n <gbt-icon [name]=\"name\" class=\"gbt-badge__icon\" aria-hidden=\"true\" />\n }\n <span class=\"gbt-badge__label\"><ng-content /></span>\n</span>\n", styles: [":host{display:inline-flex}.gbt-badge{box-sizing:border-box;display:inline-flex;align-items:center;gap:.25rem;padding:.125rem .5rem;border-radius:999px;background:var(--bg-hover);color:var(--text-secondary);font-size:.75rem;font-weight:600;line-height:1.4;white-space:nowrap}.gbt-badge[data-variant=success]{background:var(--color-success-bg);color:var(--color-success-bg-text)}.gbt-badge[data-variant=warning]{background:var(--color-warning-bg);color:var(--color-warning-bg-text)}.gbt-badge[data-variant=error]{background:var(--color-error-bg);color:var(--color-error-bg-text)}.gbt-badge[data-variant=info]{background:var(--color-info-bg);color:var(--color-info-bg-text)}.gbt-badge__icon{flex-shrink:0;width:.875em;height:.875em}.gbt-badge__label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"], dependencies: [{ kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
236
|
+
}
|
|
237
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Badge, decorators: [{
|
|
238
|
+
type: Component,
|
|
239
|
+
args: [{ selector: 'gbt-badge', standalone: true, imports: [Icon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"gbt-badge\" [attr.data-variant]=\"variant()\">\n @if (icon(); as name) {\n <gbt-icon [name]=\"name\" class=\"gbt-badge__icon\" aria-hidden=\"true\" />\n }\n <span class=\"gbt-badge__label\"><ng-content /></span>\n</span>\n", styles: [":host{display:inline-flex}.gbt-badge{box-sizing:border-box;display:inline-flex;align-items:center;gap:.25rem;padding:.125rem .5rem;border-radius:999px;background:var(--bg-hover);color:var(--text-secondary);font-size:.75rem;font-weight:600;line-height:1.4;white-space:nowrap}.gbt-badge[data-variant=success]{background:var(--color-success-bg);color:var(--color-success-bg-text)}.gbt-badge[data-variant=warning]{background:var(--color-warning-bg);color:var(--color-warning-bg-text)}.gbt-badge[data-variant=error]{background:var(--color-error-bg);color:var(--color-error-bg-text)}.gbt-badge[data-variant=info]{background:var(--color-info-bg);color:var(--color-info-bg-text)}.gbt-badge__icon{flex-shrink:0;width:.875em;height:.875em}.gbt-badge__label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"] }]
|
|
240
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }] } });
|
|
241
|
+
|
|
242
|
+
/** A 6-digit hex color, with or without its leading `#`. */
|
|
243
|
+
const HEX_6 = /^#?[0-9a-fA-F]{6}$/;
|
|
244
|
+
function normalizeHex(hex) {
|
|
245
|
+
if (!HEX_6.test(hex)) {
|
|
246
|
+
throw new Error(`getReadableTextColor: expected a 6-digit hex color such as "#dc2626" or "dc2626", got ${JSON.stringify(hex)}. ` +
|
|
247
|
+
'Shorthand hex (#abc), CSS named colors, rgb()/hsl() and custom properties are not supported.');
|
|
248
|
+
}
|
|
249
|
+
return hex.replace('#', '');
|
|
250
|
+
}
|
|
251
|
+
function linearizeChannel(value) {
|
|
252
|
+
const c = value / 255;
|
|
253
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
254
|
+
}
|
|
255
|
+
function relativeLuminance(normalizedHex) {
|
|
256
|
+
const r = parseInt(normalizedHex.substring(0, 2), 16);
|
|
257
|
+
const g = parseInt(normalizedHex.substring(2, 4), 16);
|
|
258
|
+
const b = parseInt(normalizedHex.substring(4, 6), 16);
|
|
259
|
+
return 0.2126 * linearizeChannel(r) + 0.7152 * linearizeChannel(g) + 0.0722 * linearizeChannel(b);
|
|
260
|
+
}
|
|
261
|
+
function contrastRatio(normalizedA, normalizedB) {
|
|
262
|
+
const lA = relativeLuminance(normalizedA);
|
|
263
|
+
const lB = relativeLuminance(normalizedB);
|
|
264
|
+
const lighter = Math.max(lA, lB);
|
|
265
|
+
const darker = Math.min(lA, lB);
|
|
266
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Returns `'#ffffff'` or `'#000000'`, whichever reaches a higher WCAG contrast
|
|
270
|
+
* ratio against `backgroundHex`. Used by `Tag` to keep its text readable on
|
|
271
|
+
* an arbitrary caller-supplied background color that isn't one of the
|
|
272
|
+
* design system's own semantic tokens.
|
|
273
|
+
*
|
|
274
|
+
* These two endpoints are not interchangeable with a "softer" dark such as
|
|
275
|
+
* `#1a1a1a`: sweeping all 16 777 216 sRGB backgrounds, the worst achievable
|
|
276
|
+
* ratio is **4.58:1** with `#000000` (at `#cf0dcc`) but only **4.17:1** with
|
|
277
|
+
* `#1a1a1a` (at `#da25c3`) — below the 4.5:1 AA threshold that `Tag`'s
|
|
278
|
+
* 12px bold text must meet, since it is not "large text".
|
|
279
|
+
*
|
|
280
|
+
* @param backgroundHex a 6-digit hex color, with or without its leading `#`.
|
|
281
|
+
* @throws if `backgroundHex` is not a well-formed 6-digit hex color. Silently
|
|
282
|
+
* guessing would be worse: a malformed value used to produce `NaN` ratios,
|
|
283
|
+
* and `NaN >= NaN` being `false` returned dark text for *any* unparseable
|
|
284
|
+
* input — so `'#000'` got dark text on a black background.
|
|
285
|
+
*/
|
|
286
|
+
function getReadableTextColor(backgroundHex) {
|
|
287
|
+
const background = normalizeHex(backgroundHex);
|
|
288
|
+
const white = 'ffffff';
|
|
289
|
+
const dark = '000000';
|
|
290
|
+
return contrastRatio(background, white) >= contrastRatio(background, dark) ? '#ffffff' : '#000000';
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
class Tag {
|
|
294
|
+
color = input.required(/* @ts-ignore */
|
|
295
|
+
...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
296
|
+
removable = input(false, /* @ts-ignore */
|
|
297
|
+
...(ngDevMode ? [{ debugName: "removable" }] : /* istanbul ignore next */ []));
|
|
298
|
+
removeLabel = input('Remove', /* @ts-ignore */
|
|
299
|
+
...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
|
|
300
|
+
removed = output();
|
|
301
|
+
textColor = computed(() => getReadableTextColor(this.color()), /* @ts-ignore */
|
|
302
|
+
...(ngDevMode ? [{ debugName: "textColor" }] : /* istanbul ignore next */ []));
|
|
303
|
+
onRemoveClick(event) {
|
|
304
|
+
event.stopPropagation();
|
|
305
|
+
this.removed.emit();
|
|
306
|
+
}
|
|
307
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Tag, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
308
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Tag, isStandalone: true, selector: "gbt-tag", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: true, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, ngImport: i0, template: "<span class=\"gbt-tag\" [style.background]=\"color()\" [style.color]=\"textColor()\">\n <span class=\"gbt-tag__label\"><ng-content /></span>\n @if (removable()) {\n <button type=\"button\" class=\"gbt-tag__remove\" [attr.aria-label]=\"removeLabel()\" (click)=\"onRemoveClick($event)\">\n <gbt-icon name=\"x\" aria-hidden=\"true\" />\n </button>\n }\n</span>\n", styles: [":host{display:inline-flex;max-width:100%}.gbt-tag{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:var(--site-border-radius-sm);font-size:.75rem;font-weight:600;line-height:1.4;max-width:100%}.gbt-tag__label{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gbt-tag__remove{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;background:transparent;border:none;border-radius:4px;color:currentColor;cursor:pointer;transition:background var(--site-transition-fast)}.gbt-tag__remove:hover{background:color-mix(in srgb,currentColor 20%,transparent)}\n"], dependencies: [{ kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
309
|
+
}
|
|
310
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Tag, decorators: [{
|
|
311
|
+
type: Component,
|
|
312
|
+
args: [{ selector: 'gbt-tag', standalone: true, imports: [Icon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<span class=\"gbt-tag\" [style.background]=\"color()\" [style.color]=\"textColor()\">\n <span class=\"gbt-tag__label\"><ng-content /></span>\n @if (removable()) {\n <button type=\"button\" class=\"gbt-tag__remove\" [attr.aria-label]=\"removeLabel()\" (click)=\"onRemoveClick($event)\">\n <gbt-icon name=\"x\" aria-hidden=\"true\" />\n </button>\n }\n</span>\n", styles: [":host{display:inline-flex;max-width:100%}.gbt-tag{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:var(--site-border-radius-sm);font-size:.75rem;font-weight:600;line-height:1.4;max-width:100%}.gbt-tag__label{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gbt-tag__remove{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;background:transparent;border:none;border-radius:4px;color:currentColor;cursor:pointer;transition:background var(--site-transition-fast)}.gbt-tag__remove:hover{background:color-mix(in srgb,currentColor 20%,transparent)}\n"] }]
|
|
313
|
+
}], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: true }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], removed: [{ type: i0.Output, args: ["removed"] }] } });
|
|
314
|
+
|
|
315
|
+
class EmptyState {
|
|
316
|
+
illustration = input.required(/* @ts-ignore */
|
|
317
|
+
...(ngDevMode ? [{ debugName: "illustration" }] : /* istanbul ignore next */ []));
|
|
318
|
+
heading = input.required(/* @ts-ignore */
|
|
225
319
|
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
226
|
-
|
|
227
|
-
...(ngDevMode ? [{ debugName: "
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
cardClass = computed(() => 'gbt-card' + (this.hoverable() ? ' gbt-card--hoverable' : ''), /* @ts-ignore */
|
|
231
|
-
...(ngDevMode ? [{ debugName: "cardClass" }] : /* istanbul ignore next */ []));
|
|
232
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Card, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
233
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Card, isStandalone: true, selector: "gbt-card", inputs: { hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"cardClass()\">\n @if (heading()) {\n <div class=\"gbt-card__header\">\n @switch (headingLevel()) {\n @case (1) {\n <h1 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h1>\n }\n @case (3) {\n <h3 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h3>\n }\n @case (4) {\n <h4 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h4>\n }\n @case (5) {\n <h5 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h5>\n }\n @case (6) {\n <h6 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h6>\n }\n @default {\n <h2 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h2>\n }\n }\n <ng-content select=\"[card-header-actions]\"></ng-content>\n </div>\n }\n <ng-content></ng-content>\n</div>\n<ng-template #headingContent>\n @if (icon()) {\n <gbt-icon [name]=\"icon()\" aria-hidden=\"true\" />\n }\n {{ heading() }}\n</ng-template>\n", styles: [":host{display:block}.gbt-card{background:var(--bg-principal);border-radius:var(--site-border-radius-lg);box-shadow:var(--site-shadow-sm);position:relative;overflow:hidden;transition:box-shadow .18s cubic-bezier(.4,0,.2,1);padding:1.25rem 1.5rem;font-size:.9rem;line-height:1.65;color:var(--text-secondary)}.gbt-card--hoverable{cursor:pointer;-webkit-user-select:none;user-select:none}.gbt-card--hoverable:hover{box-shadow:var(--site-shadow-lg)}.gbt-card__header{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:.75rem}.gbt-card__title{display:flex;align-items:center;gap:.5rem;font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}\n"], dependencies: [{ kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
320
|
+
message = input('', /* @ts-ignore */
|
|
321
|
+
...(ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []));
|
|
322
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EmptyState, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
323
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EmptyState, isStandalone: true, selector: "gbt-empty-state", inputs: { illustration: { classPropertyName: "illustration", publicName: "illustration", isSignal: true, isRequired: true, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: true, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"gbt-empty-state\">\n <div class=\"gbt-empty-state__illustration\" aria-hidden=\"true\">\n @switch (illustration()) {\n @case ('folder') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"16\" y=\"38\" width=\"64\" height=\"40\" rx=\"4\" />\n <path d=\"M16 38 v-8a4 4 0 0 1 4-4h16l8 8h28a4 4 0 0 1 4 4\" />\n <rect x=\"34\" y=\"14\" width=\"16\" height=\"20\" rx=\"2\" transform=\"rotate(-8 42 24)\" opacity=\"0.55\" />\n <rect x=\"50\" y=\"16\" width=\"16\" height=\"20\" rx=\"2\" transform=\"rotate(6 58 26)\" opacity=\"0.55\" />\n </svg>\n }\n @case ('star') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M48,18 L55.6,37.5 L76.5,38.7 L60.4,52 L65.6,72.3 L48,61 L30.4,72.3 L35.6,52 L19.5,38.7 L40.4,37.5 Z\" />\n <path d=\"M78,14 L81,20 L78,26 L75,20 Z\" opacity=\"0.55\" />\n <path d=\"M16,64 L19,70 L16,76 L13,70 Z\" opacity=\"0.55\" />\n </svg>\n }\n @case ('checklist') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"24\" y=\"18\" width=\"48\" height=\"64\" rx=\"6\" />\n <rect x=\"38\" y=\"12\" width=\"20\" height=\"10\" rx=\"3\" />\n <line x1=\"34\" y1=\"38\" x2=\"62\" y2=\"38\" />\n <path d=\"M32 50 l4 4 l8-8\" />\n <line x1=\"46\" y1=\"52\" x2=\"62\" y2=\"52\" />\n <line x1=\"34\" y1=\"66\" x2=\"62\" y2=\"66\" opacity=\"0.55\" />\n </svg>\n }\n @case ('merge') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"26\" cy=\"20\" r=\"7\" />\n <circle cx=\"26\" cy=\"76\" r=\"7\" />\n <circle cx=\"70\" cy=\"48\" r=\"7\" />\n <path d=\"M26 27 V60 Q26 68 34 68 H63\" />\n <path d=\"M26 55 Q26 41 40 41 H63\" />\n </svg>\n }\n @case ('pipeline') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"18\" cy=\"48\" r=\"10\" />\n <path d=\"M14 42 L25 48 L14 54 Z\" fill=\"currentColor\" stroke=\"none\" />\n <line x1=\"28\" y1=\"48\" x2=\"42\" y2=\"48\" />\n <circle cx=\"50\" cy=\"48\" r=\"8\" />\n <line x1=\"58\" y1=\"48\" x2=\"72\" y2=\"48\" />\n <circle cx=\"80\" cy=\"48\" r=\"8\" />\n </svg>\n }\n @case ('tag') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 20 H54 L82 48 L54 76 H18 Q14 76 14 72 V24 Q14 20 18 20 Z\" />\n <circle cx=\"34\" cy=\"36\" r=\"5\" />\n </svg>\n }\n @case ('book') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M48 26 Q34 16 16 20 V72 Q34 68 48 78 Q62 68 80 72 V20 Q62 16 48 26 Z\" />\n <line x1=\"24\" y1=\"32\" x2=\"40\" y2=\"30\" />\n <line x1=\"24\" y1=\"42\" x2=\"40\" y2=\"40\" />\n <line x1=\"56\" y1=\"30\" x2=\"72\" y2=\"32\" />\n <line x1=\"56\" y1=\"40\" x2=\"72\" y2=\"42\" />\n </svg>\n }\n }\n </div>\n <p class=\"gbt-empty-state__heading\">{{ heading() }}</p>\n @if (message()) {\n <p class=\"gbt-empty-state__message\">{{ message() }}</p>\n }\n <div class=\"gbt-empty-state__action\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block}.gbt-empty-state{display:flex;flex-direction:column;align-items:center;text-align:center;gap:.75rem;padding:3rem 1.5rem}.gbt-empty-state__illustration{width:6rem;height:6rem;color:var(--text-discret)}.gbt-empty-state__illustration svg{width:100%;height:100%}.gbt-empty-state__heading{margin:0;font-size:1rem;font-weight:600;color:var(--text-primary)}.gbt-empty-state__message{margin:0;max-width:32rem;color:var(--text-secondary);font-size:.875rem}.gbt-empty-state__action:empty{display:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
234
324
|
}
|
|
235
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type:
|
|
325
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EmptyState, decorators: [{
|
|
236
326
|
type: Component,
|
|
237
|
-
args: [{ selector: 'gbt-
|
|
238
|
-
}], propDecorators: {
|
|
327
|
+
args: [{ selector: 'gbt-empty-state', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"gbt-empty-state\">\n <div class=\"gbt-empty-state__illustration\" aria-hidden=\"true\">\n @switch (illustration()) {\n @case ('folder') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"16\" y=\"38\" width=\"64\" height=\"40\" rx=\"4\" />\n <path d=\"M16 38 v-8a4 4 0 0 1 4-4h16l8 8h28a4 4 0 0 1 4 4\" />\n <rect x=\"34\" y=\"14\" width=\"16\" height=\"20\" rx=\"2\" transform=\"rotate(-8 42 24)\" opacity=\"0.55\" />\n <rect x=\"50\" y=\"16\" width=\"16\" height=\"20\" rx=\"2\" transform=\"rotate(6 58 26)\" opacity=\"0.55\" />\n </svg>\n }\n @case ('star') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M48,18 L55.6,37.5 L76.5,38.7 L60.4,52 L65.6,72.3 L48,61 L30.4,72.3 L35.6,52 L19.5,38.7 L40.4,37.5 Z\" />\n <path d=\"M78,14 L81,20 L78,26 L75,20 Z\" opacity=\"0.55\" />\n <path d=\"M16,64 L19,70 L16,76 L13,70 Z\" opacity=\"0.55\" />\n </svg>\n }\n @case ('checklist') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"24\" y=\"18\" width=\"48\" height=\"64\" rx=\"6\" />\n <rect x=\"38\" y=\"12\" width=\"20\" height=\"10\" rx=\"3\" />\n <line x1=\"34\" y1=\"38\" x2=\"62\" y2=\"38\" />\n <path d=\"M32 50 l4 4 l8-8\" />\n <line x1=\"46\" y1=\"52\" x2=\"62\" y2=\"52\" />\n <line x1=\"34\" y1=\"66\" x2=\"62\" y2=\"66\" opacity=\"0.55\" />\n </svg>\n }\n @case ('merge') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"26\" cy=\"20\" r=\"7\" />\n <circle cx=\"26\" cy=\"76\" r=\"7\" />\n <circle cx=\"70\" cy=\"48\" r=\"7\" />\n <path d=\"M26 27 V60 Q26 68 34 68 H63\" />\n <path d=\"M26 55 Q26 41 40 41 H63\" />\n </svg>\n }\n @case ('pipeline') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"18\" cy=\"48\" r=\"10\" />\n <path d=\"M14 42 L25 48 L14 54 Z\" fill=\"currentColor\" stroke=\"none\" />\n <line x1=\"28\" y1=\"48\" x2=\"42\" y2=\"48\" />\n <circle cx=\"50\" cy=\"48\" r=\"8\" />\n <line x1=\"58\" y1=\"48\" x2=\"72\" y2=\"48\" />\n <circle cx=\"80\" cy=\"48\" r=\"8\" />\n </svg>\n }\n @case ('tag') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 20 H54 L82 48 L54 76 H18 Q14 76 14 72 V24 Q14 20 18 20 Z\" />\n <circle cx=\"34\" cy=\"36\" r=\"5\" />\n </svg>\n }\n @case ('book') {\n <svg viewBox=\"0 0 96 96\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M48 26 Q34 16 16 20 V72 Q34 68 48 78 Q62 68 80 72 V20 Q62 16 48 26 Z\" />\n <line x1=\"24\" y1=\"32\" x2=\"40\" y2=\"30\" />\n <line x1=\"24\" y1=\"42\" x2=\"40\" y2=\"40\" />\n <line x1=\"56\" y1=\"30\" x2=\"72\" y2=\"32\" />\n <line x1=\"56\" y1=\"40\" x2=\"72\" y2=\"42\" />\n </svg>\n }\n }\n </div>\n <p class=\"gbt-empty-state__heading\">{{ heading() }}</p>\n @if (message()) {\n <p class=\"gbt-empty-state__message\">{{ message() }}</p>\n }\n <div class=\"gbt-empty-state__action\">\n <ng-content />\n </div>\n</div>\n", styles: [":host{display:block}.gbt-empty-state{display:flex;flex-direction:column;align-items:center;text-align:center;gap:.75rem;padding:3rem 1.5rem}.gbt-empty-state__illustration{width:6rem;height:6rem;color:var(--text-discret)}.gbt-empty-state__illustration svg{width:100%;height:100%}.gbt-empty-state__heading{margin:0;font-size:1rem;font-weight:600;color:var(--text-primary)}.gbt-empty-state__message{margin:0;max-width:32rem;color:var(--text-secondary);font-size:.875rem}.gbt-empty-state__action:empty{display:none}\n"] }]
|
|
328
|
+
}], propDecorators: { illustration: [{ type: i0.Input, args: [{ isSignal: true, alias: "illustration", required: true }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: true }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }] } });
|
|
239
329
|
|
|
240
330
|
let nextInputId = 0;
|
|
241
331
|
class GbtInput {
|
|
@@ -319,59 +409,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
319
409
|
], template: "<div class=\"gbt-input\">\n @if (label()) {\n <label [for]=\"id()\">{{ label() }}{{ required() ? ' *' : '' }}</label>\n }\n <div class=\"gbt-input__wrapper\">\n <input\n [id]=\"id()\"\n [type]=\"effectiveType()\"\n [placeholder]=\"placeholder()\"\n [required]=\"required()\"\n [disabled]=\"isDisabled()\"\n [attr.autocomplete]=\"autocomplete()\"\n [value]=\"value()\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"errorMessage() ? id() + '-error' : null\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n @if (type() === 'password') {\n <button\n type=\"button\"\n class=\"gbt-input__toggle\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"passwordVisible() ? hidePasswordLabel() : showPasswordLabel()\"\n >\n <gbt-icon [name]=\"passwordVisible() ? 'eye-off' : 'eye'\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n @if (errorMessage()) {\n <p [id]=\"id() + '-error'\" class=\"gbt-input__error\" role=\"alert\">{{ errorMessage() }}</p>\n }\n</div>\n", styles: [":host{display:block}.gbt-input{display:flex;flex-direction:column;gap:.375rem}.gbt-input label{font-size:.8125rem;font-weight:600;color:var(--text-secondary)}.gbt-input__wrapper{position:relative;display:flex;align-items:center}.gbt-input input{box-sizing:border-box;width:100%;padding:.5rem .75rem;font-family:var(--font-family);font-size:.875rem;color:var(--text-primary);background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);transition:border-color var(--site-transition-fast)}.gbt-input input:focus{outline:none;border-color:var(--primary)}.gbt-input input:focus-visible{outline:2px solid var(--primary);outline-offset:1px}.gbt-input input:disabled{background:var(--bg-panel);cursor:not-allowed}.gbt-input__toggle{position:absolute;right:.5rem;display:inline-flex;background:none;border:none;color:var(--text-discret);cursor:pointer}.gbt-input__toggle:before{content:\"\";position:absolute;inset:50% auto auto 50%;width:max(100%,24px);height:max(100%,24px);transform:translate(-50%,-50%)}.gbt-input__error{margin:0;font-size:.75rem;color:var(--color-error-text)}\n"] }]
|
|
320
410
|
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], showPasswordLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPasswordLabel", required: false }] }], hidePasswordLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidePasswordLabel", required: false }] }], committed: [{ type: i0.Output, args: ["committed"] }] } });
|
|
321
411
|
|
|
322
|
-
let nextCheckboxId = 0;
|
|
323
|
-
class Checkbox {
|
|
324
|
-
id = input(`gbt-checkbox-${++nextCheckboxId}`, /* @ts-ignore */
|
|
325
|
-
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
326
|
-
label = input('', /* @ts-ignore */
|
|
327
|
-
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
328
|
-
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
329
|
-
checked = signal(false, /* @ts-ignore */
|
|
330
|
-
...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
331
|
-
formDisabled = signal(false, /* @ts-ignore */
|
|
332
|
-
...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
|
|
333
|
-
isDisabled = computed(() => this.disabled() || this.formDisabled(), /* @ts-ignore */
|
|
334
|
-
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
335
|
-
onChange = () => { };
|
|
336
|
-
onTouched = () => { };
|
|
337
|
-
writeValue(value) {
|
|
338
|
-
this.checked.set(!!value);
|
|
339
|
-
}
|
|
340
|
-
registerOnChange(fn) {
|
|
341
|
-
this.onChange = fn;
|
|
342
|
-
}
|
|
343
|
-
registerOnTouched(fn) {
|
|
344
|
-
this.onTouched = fn;
|
|
345
|
-
}
|
|
346
|
-
setDisabledState(isDisabled) {
|
|
347
|
-
this.formDisabled.set(isDisabled);
|
|
348
|
-
}
|
|
349
|
-
onToggle(event) {
|
|
350
|
-
const value = event.target.checked;
|
|
351
|
-
this.checked.set(value);
|
|
352
|
-
this.onChange(value);
|
|
353
|
-
this.onTouched();
|
|
354
|
-
}
|
|
355
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Checkbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
356
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: Checkbox, isStandalone: true, selector: "gbt-checkbox", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
357
|
-
{
|
|
358
|
-
provide: NG_VALUE_ACCESSOR,
|
|
359
|
-
useExisting: forwardRef(() => Checkbox),
|
|
360
|
-
multi: true,
|
|
361
|
-
},
|
|
362
|
-
], ngImport: i0, template: "<label class=\"gbt-checkbox\" [class.gbt-checkbox--disabled]=\"isDisabled()\">\n <input\n type=\"checkbox\"\n [id]=\"id()\"\n [checked]=\"checked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"onToggle($event)\"\n />\n <span>{{ label() }}</span>\n</label>\n", styles: [".gbt-checkbox{position:relative;display:inline-flex;align-items:center;gap:.5rem;font-size:.875rem;color:var(--text-primary);cursor:pointer}.gbt-checkbox:before{content:\"\";position:absolute;inset:50% auto auto 50%;width:max(100%,24px);height:max(100%,24px);transform:translate(-50%,-50%)}.gbt-checkbox--disabled{cursor:not-allowed;opacity:.5}.gbt-checkbox input{width:1rem;height:1rem;accent-color:var(--primary)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
363
|
-
}
|
|
364
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Checkbox, decorators: [{
|
|
365
|
-
type: Component,
|
|
366
|
-
args: [{ selector: 'gbt-checkbox', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
367
|
-
{
|
|
368
|
-
provide: NG_VALUE_ACCESSOR,
|
|
369
|
-
useExisting: forwardRef(() => Checkbox),
|
|
370
|
-
multi: true,
|
|
371
|
-
},
|
|
372
|
-
], template: "<label class=\"gbt-checkbox\" [class.gbt-checkbox--disabled]=\"isDisabled()\">\n <input\n type=\"checkbox\"\n [id]=\"id()\"\n [checked]=\"checked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"onToggle($event)\"\n />\n <span>{{ label() }}</span>\n</label>\n", styles: [".gbt-checkbox{position:relative;display:inline-flex;align-items:center;gap:.5rem;font-size:.875rem;color:var(--text-primary);cursor:pointer}.gbt-checkbox:before{content:\"\";position:absolute;inset:50% auto auto 50%;width:max(100%,24px);height:max(100%,24px);transform:translate(-50%,-50%)}.gbt-checkbox--disabled{cursor:not-allowed;opacity:.5}.gbt-checkbox input{width:1rem;height:1rem;accent-color:var(--primary)}\n"] }]
|
|
373
|
-
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
374
|
-
|
|
375
412
|
let nextSelectId = 0;
|
|
376
413
|
class Select {
|
|
377
414
|
elementRef = inject(ElementRef);
|
|
@@ -379,9 +416,12 @@ class Select {
|
|
|
379
416
|
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
380
417
|
label = input('', /* @ts-ignore */
|
|
381
418
|
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
419
|
+
size = input('md', /* @ts-ignore */
|
|
420
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
382
421
|
options = input.required(/* @ts-ignore */
|
|
383
422
|
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
384
423
|
multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
424
|
+
chips = input(false, { ...(ngDevMode ? { debugName: "chips" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
385
425
|
placeholder = input('Select…', /* @ts-ignore */
|
|
386
426
|
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
387
427
|
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
@@ -390,6 +430,8 @@ class Select {
|
|
|
390
430
|
...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
391
431
|
selectedCountLabel = input((count) => `${count} selected`, /* @ts-ignore */
|
|
392
432
|
...(ngDevMode ? [{ debugName: "selectedCountLabel" }] : /* istanbul ignore next */ []));
|
|
433
|
+
chipRemoveLabel = input((label) => `Remove ${label}`, /* @ts-ignore */
|
|
434
|
+
...(ngDevMode ? [{ debugName: "chipRemoveLabel" }] : /* istanbul ignore next */ []));
|
|
393
435
|
open = signal(false, /* @ts-ignore */
|
|
394
436
|
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
395
437
|
activeIndex = signal(-1, /* @ts-ignore */
|
|
@@ -402,6 +444,8 @@ class Select {
|
|
|
402
444
|
...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
|
|
403
445
|
labelId = computed(() => `${this.id()}-label`, /* @ts-ignore */
|
|
404
446
|
...(ngDevMode ? [{ debugName: "labelId" }] : /* istanbul ignore next */ []));
|
|
447
|
+
chipsId = computed(() => `${this.id()}-chips`, /* @ts-ignore */
|
|
448
|
+
...(ngDevMode ? [{ debugName: "chipsId" }] : /* istanbul ignore next */ []));
|
|
405
449
|
isDisabled = computed(() => this.disabled() || this.formDisabled(), /* @ts-ignore */
|
|
406
450
|
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
407
451
|
onChange = () => { };
|
|
@@ -433,12 +477,33 @@ class Select {
|
|
|
433
477
|
if (opts.length === 0) {
|
|
434
478
|
return this.placeholder();
|
|
435
479
|
}
|
|
480
|
+
if (this.chips() && this.multiple()) {
|
|
481
|
+
return this.placeholder();
|
|
482
|
+
}
|
|
436
483
|
if (this.multiple() && opts.length > 1) {
|
|
437
484
|
return this.selectedCountLabel()(opts.length);
|
|
438
485
|
}
|
|
439
486
|
return opts[0].label;
|
|
440
487
|
}, /* @ts-ignore */
|
|
441
488
|
...(ngDevMode ? [{ debugName: "triggerLabel" }] : /* istanbul ignore next */ []));
|
|
489
|
+
chipsVisible = computed(() => this.chips() && this.multiple() && this.selectedOptions().length > 0, /* @ts-ignore */
|
|
490
|
+
...(ngDevMode ? [{ debugName: "chipsVisible" }] : /* istanbul ignore next */ []));
|
|
491
|
+
/**
|
|
492
|
+
* In chips mode the trigger keeps showing the placeholder, so the selection
|
|
493
|
+
* is conveyed to assistive technology by describing the trigger with the
|
|
494
|
+
* chip row itself. The error message keeps its own id in the list.
|
|
495
|
+
*/
|
|
496
|
+
describedBy = computed(() => {
|
|
497
|
+
const ids = [];
|
|
498
|
+
if (this.chipsVisible()) {
|
|
499
|
+
ids.push(this.chipsId());
|
|
500
|
+
}
|
|
501
|
+
if (this.errorMessage()) {
|
|
502
|
+
ids.push(`${this.id()}-error`);
|
|
503
|
+
}
|
|
504
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
505
|
+
}, /* @ts-ignore */
|
|
506
|
+
...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
|
|
442
507
|
triggerIcon = computed(() => {
|
|
443
508
|
const opts = this.selectedOptions();
|
|
444
509
|
return opts.length === 1 ? opts[0].icon : undefined;
|
|
@@ -471,12 +536,41 @@ class Select {
|
|
|
471
536
|
return;
|
|
472
537
|
}
|
|
473
538
|
const rect = trigger.getBoundingClientRect();
|
|
539
|
+
// In chips mode the chip row sits between the trigger and the panel.
|
|
540
|
+
// Anchoring the panel to the trigger alone would lay it over the chips,
|
|
541
|
+
// whose remove buttons are focusable — WCAG 2.4.11 "focus not obscured".
|
|
542
|
+
const chipRow = this.elementRef.nativeElement.querySelector('.gbt-select__chips');
|
|
543
|
+
const anchorBottom = chipRow
|
|
544
|
+
? Math.max(rect.bottom, chipRow.getBoundingClientRect().bottom)
|
|
545
|
+
: rect.bottom;
|
|
474
546
|
this.panelStyle.set({
|
|
475
|
-
top: `${
|
|
547
|
+
top: `${anchorBottom + 6}px`,
|
|
476
548
|
left: `${rect.left}px`,
|
|
477
549
|
width: `${rect.width}px`,
|
|
478
550
|
});
|
|
479
551
|
}
|
|
552
|
+
/**
|
|
553
|
+
* Removes the chip at `index`. Refuses to mutate anything while the control
|
|
554
|
+
* is disabled (the remove buttons are not rendered then, but a programmatic
|
|
555
|
+
* caller must not be able to bypass the disabled state either), and moves
|
|
556
|
+
* focus off the button it is about to destroy — otherwise focus falls back
|
|
557
|
+
* to `<body>`.
|
|
558
|
+
*/
|
|
559
|
+
removeChip(value, index) {
|
|
560
|
+
if (this.isDisabled()) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const host = this.elementRef.nativeElement;
|
|
564
|
+
const removeButtons = Array.from(host.querySelectorAll('.gbt-select__chips .gbt-tag__remove'));
|
|
565
|
+
// `@for` tracks options by value, so the surviving chips keep their DOM
|
|
566
|
+
// nodes across this removal — the element resolved here is still the right
|
|
567
|
+
// one once the view updates.
|
|
568
|
+
const nextFocus = removeButtons[index + 1] ??
|
|
569
|
+
removeButtons[index - 1] ??
|
|
570
|
+
host.querySelector('.gbt-select__trigger');
|
|
571
|
+
this.selectOption(value);
|
|
572
|
+
nextFocus?.focus();
|
|
573
|
+
}
|
|
480
574
|
selectOption(value) {
|
|
481
575
|
if (this.multiple()) {
|
|
482
576
|
const current = this.selected();
|
|
@@ -485,6 +579,9 @@ class Select {
|
|
|
485
579
|
: [...current, value];
|
|
486
580
|
this.selected.set(next);
|
|
487
581
|
this.onChange(next);
|
|
582
|
+
// A chip can be removed without ever opening the panel, so this is the
|
|
583
|
+
// only place that marks the control as touched in that flow.
|
|
584
|
+
this.onTouched();
|
|
488
585
|
}
|
|
489
586
|
else {
|
|
490
587
|
this.selected.set([value]);
|
|
@@ -538,29 +635,155 @@ class Select {
|
|
|
538
635
|
}
|
|
539
636
|
}
|
|
540
637
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Select, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
541
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Select, isStandalone: true, selector: "gbt-select", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, selectedCountLabel: { classPropertyName: "selectedCountLabel", publicName: "selectedCountLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "handleClickOutside($event)", "keydown": "onKeydown($event)", "window:scroll": "updatePanelPosition()", "window:resize": "updatePanelPosition()" } }, providers: [
|
|
638
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Select, isStandalone: true, selector: "gbt-select", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, chips: { classPropertyName: "chips", publicName: "chips", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, selectedCountLabel: { classPropertyName: "selectedCountLabel", publicName: "selectedCountLabel", isSignal: true, isRequired: false, transformFunction: null }, chipRemoveLabel: { classPropertyName: "chipRemoveLabel", publicName: "chipRemoveLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "handleClickOutside($event)", "keydown": "onKeydown($event)", "window:scroll": "updatePanelPosition()", "window:resize": "updatePanelPosition()" }, properties: { "class.gbt-select--sm": "size() === 'sm'" } }, providers: [
|
|
542
639
|
{
|
|
543
640
|
provide: NG_VALUE_ACCESSOR,
|
|
544
641
|
useExisting: forwardRef(() => Select),
|
|
545
642
|
multi: true,
|
|
546
643
|
},
|
|
547
|
-
], ngImport: i0, template: "<div class=\"gbt-select\" [class.gbt-select--disabled]=\"isDisabled()\">\n @if (label()) {\n <label [id]=\"labelId()\" [for]=\"id()\" class=\"gbt-select__label\"\n >{{ label() }}{{ required() ? ' *' : '' }}</label\n >\n }\n\n <button\n type=\"button\"\n [id]=\"id()\"\n class=\"gbt-select__trigger\"\n [class.gbt-select__trigger--open]=\"open()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [attr.aria-labelledby]=\"label() ? labelId() + ' ' + id() : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"
|
|
644
|
+
], ngImport: i0, template: "<div class=\"gbt-select\" [class.gbt-select--disabled]=\"isDisabled()\">\n @if (label()) {\n <label [id]=\"labelId()\" [for]=\"id()\" class=\"gbt-select__label\"\n >{{ label() }}{{ required() ? ' *' : '' }}</label\n >\n }\n\n <button\n type=\"button\"\n [id]=\"id()\"\n class=\"gbt-select__trigger\"\n [class.gbt-select__trigger--open]=\"open()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [attr.aria-labelledby]=\"label() ? labelId() + ' ' + id() : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n (click)=\"toggleOpen()\"\n >\n @if (triggerIcon(); as icon) {\n <gbt-icon [name]=\"icon\" class=\"gbt-select__trigger-icon\" aria-hidden=\"true\" />\n }\n <span\n class=\"gbt-select__trigger-label\"\n [class.gbt-select__trigger-label--placeholder]=\"selectedOptions().length === 0\"\n >\n {{ triggerLabel() }}\n </span>\n <gbt-icon name=\"chevron-down\" class=\"gbt-select__chevron\" aria-hidden=\"true\" />\n </button>\n @if (chipsVisible()) {\n <div class=\"gbt-select__chips\" [id]=\"chipsId()\">\n @for (option of selectedOptions(); track option.value; let i = $index) {\n <gbt-tag\n [color]=\"option.color ?? '#6b7280'\"\n [removable]=\"!isDisabled()\"\n [removeLabel]=\"chipRemoveLabel()(option.label)\"\n (removed)=\"removeChip(option.value, i)\"\n >\n {{ option.label }}\n </gbt-tag>\n }\n </div>\n }\n @if (chips() && multiple()) {\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">\n {{ selectedCountLabel()(selectedOptions().length) }}\n </div>\n }\n @if (open() && panelStyle(); as style) {\n <ul\n [id]=\"id() + '-listbox'\"\n class=\"gbt-select__panel\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || placeholder()\"\n [attr.aria-multiselectable]=\"multiple()\"\n [style.top]=\"style.top\"\n [style.left]=\"style.left\"\n [style.width]=\"style.width\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <li role=\"presentation\">\n <button\n [id]=\"id() + '-option-' + i\"\n type=\"button\"\n role=\"option\"\n tabindex=\"-1\"\n class=\"gbt-select__option\"\n [class.gbt-select__option--selected]=\"isSelected(option.value)\"\n [class.gbt-select__option--active]=\"i === activeIndex()\"\n [attr.aria-selected]=\"isSelected(option.value)\"\n (click)=\"selectOption(option.value)\"\n (mouseenter)=\"activeIndex.set(i)\"\n >\n @if (option.icon) {\n <gbt-icon [name]=\"option.icon\" class=\"gbt-select__option-icon\" aria-hidden=\"true\" />\n }\n <span class=\"gbt-select__option-label\">{{ option.label }}</span>\n @if (isSelected(option.value)) {\n <gbt-icon name=\"check\" class=\"gbt-select__option-check\" aria-hidden=\"true\" />\n }\n </button>\n </li>\n }\n </ul>\n }\n @if (errorMessage()) {\n <p [id]=\"id() + '-error'\" class=\"gbt-select__error\" role=\"alert\">{{ errorMessage() }}</p>\n }\n</div>\n", styles: [":host{position:relative;display:inline-block;min-width:180px}.gbt-select{display:flex;flex-direction:column;gap:.375rem}.gbt-select--disabled{opacity:.5}.gbt-select__label{font-size:.8125rem;font-weight:600;color:var(--text-secondary)}.gbt-select__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:100%;height:40px;padding:0 10px;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);color:var(--text-primary);font-size:14px;cursor:pointer;transition:border-color .15s cubic-bezier(.4,0,.2,1),box-shadow .15s cubic-bezier(.4,0,.2,1)}.gbt-select__trigger:hover:not(:disabled){border-color:var(--border-color)}.gbt-select__trigger--open{border-color:var(--primary);box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 12%,transparent)}.gbt-select__trigger:disabled{cursor:not-allowed}:host(.gbt-select--sm){min-width:120px}:host(.gbt-select--sm) .gbt-select__trigger{height:32px;padding:0 8px;font-size:13px}.gbt-select__trigger-icon{flex-shrink:0;color:var(--text-secondary)}.gbt-select__trigger-label{flex:1;min-width:0;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gbt-select__trigger-label--placeholder{color:var(--text-discret)}.gbt-select__chevron{flex-shrink:0;color:var(--text-secondary);transition:transform .2s cubic-bezier(.4,0,.2,1)}.gbt-select__trigger--open .gbt-select__chevron{transform:rotate(180deg)}.gbt-select__panel{position:fixed;z-index:1000;margin:0;padding:6px;list-style:none;max-height:280px;overflow-y:auto;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);box-shadow:var(--site-shadow-lg);animation:gbt-select-scale-in .15s cubic-bezier(.34,1.56,.64,1) both}.gbt-select__panel::-webkit-scrollbar{width:6px}.gbt-select__panel::-webkit-scrollbar-track{background:transparent}.gbt-select__panel::-webkit-scrollbar-thumb{background:var(--bg-hover);border-radius:3px}.gbt-select__option{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;background:transparent;border:none;border-radius:8px;color:var(--text-primary);font-size:14px;text-align:left;cursor:pointer;transition:background .12s cubic-bezier(.4,0,.2,1)}.gbt-select__option:hover,.gbt-select__option--active{background:var(--bg-hover)}.gbt-select__option--selected{color:var(--primary);font-weight:600}.gbt-select__option-icon{flex-shrink:0;color:var(--text-secondary)}.gbt-select__option--selected .gbt-select__option-icon{color:var(--primary)}.gbt-select__option-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gbt-select__option-check{flex-shrink:0;color:var(--primary)}@keyframes gbt-select-scale-in{0%{opacity:0;transform:scale(.97) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}.gbt-select__chips{display:flex;flex-wrap:wrap;gap:4px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.gbt-select__error{margin:0;font-size:.75rem;color:var(--color-error-text)}@media(prefers-reduced-motion:reduce){.gbt-select__panel{animation:none}.gbt-select__chevron{transition:none}}\n"], dependencies: [{ kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }, { kind: "component", type: Tag, selector: "gbt-tag", inputs: ["color", "removable", "removeLabel"], outputs: ["removed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
548
645
|
}
|
|
549
646
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Select, decorators: [{
|
|
550
647
|
type: Component,
|
|
551
|
-
args: [{ selector: 'gbt-select', standalone: true, imports: [Icon], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
648
|
+
args: [{ selector: 'gbt-select', standalone: true, imports: [Icon, Tag], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
552
649
|
'(document:click)': 'handleClickOutside($event)',
|
|
553
650
|
'(keydown)': 'onKeydown($event)',
|
|
554
651
|
'(window:scroll)': 'updatePanelPosition()',
|
|
555
652
|
'(window:resize)': 'updatePanelPosition()',
|
|
653
|
+
'[class.gbt-select--sm]': "size() === 'sm'",
|
|
556
654
|
}, providers: [
|
|
557
655
|
{
|
|
558
656
|
provide: NG_VALUE_ACCESSOR,
|
|
559
657
|
useExisting: forwardRef(() => Select),
|
|
560
658
|
multi: true,
|
|
561
659
|
},
|
|
562
|
-
], template: "<div class=\"gbt-select\" [class.gbt-select--disabled]=\"isDisabled()\">\n @if (label()) {\n <label [id]=\"labelId()\" [for]=\"id()\" class=\"gbt-select__label\"\n >{{ label() }}{{ required() ? ' *' : '' }}</label\n >\n }\n\n <button\n type=\"button\"\n [id]=\"id()\"\n class=\"gbt-select__trigger\"\n [class.gbt-select__trigger--open]=\"open()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [attr.aria-labelledby]=\"label() ? labelId() + ' ' + id() : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"
|
|
563
|
-
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], selectedCountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedCountLabel", required: false }] }] } });
|
|
660
|
+
], template: "<div class=\"gbt-select\" [class.gbt-select--disabled]=\"isDisabled()\">\n @if (label()) {\n <label [id]=\"labelId()\" [for]=\"id()\" class=\"gbt-select__label\"\n >{{ label() }}{{ required() ? ' *' : '' }}</label\n >\n }\n\n <button\n type=\"button\"\n [id]=\"id()\"\n class=\"gbt-select__trigger\"\n [class.gbt-select__trigger--open]=\"open()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"open() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"activeOptionId()\"\n [attr.aria-labelledby]=\"label() ? labelId() + ' ' + id() : null\"\n [attr.aria-required]=\"required() ? true : null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n (click)=\"toggleOpen()\"\n >\n @if (triggerIcon(); as icon) {\n <gbt-icon [name]=\"icon\" class=\"gbt-select__trigger-icon\" aria-hidden=\"true\" />\n }\n <span\n class=\"gbt-select__trigger-label\"\n [class.gbt-select__trigger-label--placeholder]=\"selectedOptions().length === 0\"\n >\n {{ triggerLabel() }}\n </span>\n <gbt-icon name=\"chevron-down\" class=\"gbt-select__chevron\" aria-hidden=\"true\" />\n </button>\n @if (chipsVisible()) {\n <div class=\"gbt-select__chips\" [id]=\"chipsId()\">\n @for (option of selectedOptions(); track option.value; let i = $index) {\n <gbt-tag\n [color]=\"option.color ?? '#6b7280'\"\n [removable]=\"!isDisabled()\"\n [removeLabel]=\"chipRemoveLabel()(option.label)\"\n (removed)=\"removeChip(option.value, i)\"\n >\n {{ option.label }}\n </gbt-tag>\n }\n </div>\n }\n @if (chips() && multiple()) {\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">\n {{ selectedCountLabel()(selectedOptions().length) }}\n </div>\n }\n @if (open() && panelStyle(); as style) {\n <ul\n [id]=\"id() + '-listbox'\"\n class=\"gbt-select__panel\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || placeholder()\"\n [attr.aria-multiselectable]=\"multiple()\"\n [style.top]=\"style.top\"\n [style.left]=\"style.left\"\n [style.width]=\"style.width\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <li role=\"presentation\">\n <button\n [id]=\"id() + '-option-' + i\"\n type=\"button\"\n role=\"option\"\n tabindex=\"-1\"\n class=\"gbt-select__option\"\n [class.gbt-select__option--selected]=\"isSelected(option.value)\"\n [class.gbt-select__option--active]=\"i === activeIndex()\"\n [attr.aria-selected]=\"isSelected(option.value)\"\n (click)=\"selectOption(option.value)\"\n (mouseenter)=\"activeIndex.set(i)\"\n >\n @if (option.icon) {\n <gbt-icon [name]=\"option.icon\" class=\"gbt-select__option-icon\" aria-hidden=\"true\" />\n }\n <span class=\"gbt-select__option-label\">{{ option.label }}</span>\n @if (isSelected(option.value)) {\n <gbt-icon name=\"check\" class=\"gbt-select__option-check\" aria-hidden=\"true\" />\n }\n </button>\n </li>\n }\n </ul>\n }\n @if (errorMessage()) {\n <p [id]=\"id() + '-error'\" class=\"gbt-select__error\" role=\"alert\">{{ errorMessage() }}</p>\n }\n</div>\n", styles: [":host{position:relative;display:inline-block;min-width:180px}.gbt-select{display:flex;flex-direction:column;gap:.375rem}.gbt-select--disabled{opacity:.5}.gbt-select__label{font-size:.8125rem;font-weight:600;color:var(--text-secondary)}.gbt-select__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:100%;height:40px;padding:0 10px;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);color:var(--text-primary);font-size:14px;cursor:pointer;transition:border-color .15s cubic-bezier(.4,0,.2,1),box-shadow .15s cubic-bezier(.4,0,.2,1)}.gbt-select__trigger:hover:not(:disabled){border-color:var(--border-color)}.gbt-select__trigger--open{border-color:var(--primary);box-shadow:0 0 0 4px color-mix(in srgb,var(--primary) 12%,transparent)}.gbt-select__trigger:disabled{cursor:not-allowed}:host(.gbt-select--sm){min-width:120px}:host(.gbt-select--sm) .gbt-select__trigger{height:32px;padding:0 8px;font-size:13px}.gbt-select__trigger-icon{flex-shrink:0;color:var(--text-secondary)}.gbt-select__trigger-label{flex:1;min-width:0;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gbt-select__trigger-label--placeholder{color:var(--text-discret)}.gbt-select__chevron{flex-shrink:0;color:var(--text-secondary);transition:transform .2s cubic-bezier(.4,0,.2,1)}.gbt-select__trigger--open .gbt-select__chevron{transform:rotate(180deg)}.gbt-select__panel{position:fixed;z-index:1000;margin:0;padding:6px;list-style:none;max-height:280px;overflow-y:auto;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);box-shadow:var(--site-shadow-lg);animation:gbt-select-scale-in .15s cubic-bezier(.34,1.56,.64,1) both}.gbt-select__panel::-webkit-scrollbar{width:6px}.gbt-select__panel::-webkit-scrollbar-track{background:transparent}.gbt-select__panel::-webkit-scrollbar-thumb{background:var(--bg-hover);border-radius:3px}.gbt-select__option{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;background:transparent;border:none;border-radius:8px;color:var(--text-primary);font-size:14px;text-align:left;cursor:pointer;transition:background .12s cubic-bezier(.4,0,.2,1)}.gbt-select__option:hover,.gbt-select__option--active{background:var(--bg-hover)}.gbt-select__option--selected{color:var(--primary);font-weight:600}.gbt-select__option-icon{flex-shrink:0;color:var(--text-secondary)}.gbt-select__option--selected .gbt-select__option-icon{color:var(--primary)}.gbt-select__option-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gbt-select__option-check{flex-shrink:0;color:var(--primary)}@keyframes gbt-select-scale-in{0%{opacity:0;transform:scale(.97) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}.gbt-select__chips{display:flex;flex-wrap:wrap;gap:4px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.gbt-select__error{margin:0;font-size:.75rem;color:var(--color-error-text)}@media(prefers-reduced-motion:reduce){.gbt-select__panel{animation:none}.gbt-select__chevron{transition:none}}\n"] }]
|
|
661
|
+
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], chips: [{ type: i0.Input, args: [{ isSignal: true, alias: "chips", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], selectedCountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedCountLabel", required: false }] }], chipRemoveLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "chipRemoveLabel", required: false }] }] } });
|
|
662
|
+
|
|
663
|
+
class ListToolbar {
|
|
664
|
+
searchValue = input('', /* @ts-ignore */
|
|
665
|
+
...(ngDevMode ? [{ debugName: "searchValue" }] : /* istanbul ignore next */ []));
|
|
666
|
+
searchLabel = input.required(/* @ts-ignore */
|
|
667
|
+
...(ngDevMode ? [{ debugName: "searchLabel" }] : /* istanbul ignore next */ []));
|
|
668
|
+
searchPlaceholder = input('', /* @ts-ignore */
|
|
669
|
+
...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
|
|
670
|
+
sortOptions = input.required(/* @ts-ignore */
|
|
671
|
+
...(ngDevMode ? [{ debugName: "sortOptions" }] : /* istanbul ignore next */ []));
|
|
672
|
+
sortValue = input.required(/* @ts-ignore */
|
|
673
|
+
...(ngDevMode ? [{ debugName: "sortValue" }] : /* istanbul ignore next */ []));
|
|
674
|
+
sortDirection = input('asc', /* @ts-ignore */
|
|
675
|
+
...(ngDevMode ? [{ debugName: "sortDirection" }] : /* istanbul ignore next */ []));
|
|
676
|
+
sortLabel = input('Sort by', /* @ts-ignore */
|
|
677
|
+
...(ngDevMode ? [{ debugName: "sortLabel" }] : /* istanbul ignore next */ []));
|
|
678
|
+
directionLabel = input('Reverse sort direction', /* @ts-ignore */
|
|
679
|
+
...(ngDevMode ? [{ debugName: "directionLabel" }] : /* istanbul ignore next */ []));
|
|
680
|
+
searchValueChange = output();
|
|
681
|
+
sortValueChange = output();
|
|
682
|
+
sortDirectionChange = output();
|
|
683
|
+
// Plain `[ngModel]` bindings on the child `gbt-input`/`gbt-select` defer their
|
|
684
|
+
// initial value to a control-value-accessor writeValue() call scheduled on a
|
|
685
|
+
// microtask (an Angular Forms `NgModel` implementation detail), so the very
|
|
686
|
+
// first render would briefly show the empty/placeholder state. Reactive
|
|
687
|
+
// FormControls propagate `setValue()` to the CVA synchronously, so we mirror
|
|
688
|
+
// the inputs onto internal controls instead and forward user edits back out.
|
|
689
|
+
searchControl = new FormControl('', { nonNullable: true });
|
|
690
|
+
sortControl = new FormControl(null);
|
|
691
|
+
constructor() {
|
|
692
|
+
effect(() => this.searchControl.setValue(this.searchValue(), { emitEvent: false }));
|
|
693
|
+
effect(() => this.sortControl.setValue(this.sortValue(), { emitEvent: false }));
|
|
694
|
+
this.searchControl.valueChanges
|
|
695
|
+
.pipe(takeUntilDestroyed())
|
|
696
|
+
.subscribe((value) => this.searchValueChange.emit(value));
|
|
697
|
+
this.sortControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
|
698
|
+
if (value !== null && value !== this.sortValue()) {
|
|
699
|
+
this.sortValueChange.emit(value);
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
asSelectOptions(options) {
|
|
704
|
+
return options;
|
|
705
|
+
}
|
|
706
|
+
toggleDirection() {
|
|
707
|
+
this.sortDirectionChange.emit(this.sortDirection() === 'asc' ? 'desc' : 'asc');
|
|
708
|
+
}
|
|
709
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListToolbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
710
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: ListToolbar, isStandalone: true, selector: "gbt-list-toolbar", inputs: { searchValue: { classPropertyName: "searchValue", publicName: "searchValue", isSignal: true, isRequired: false, transformFunction: null }, searchLabel: { classPropertyName: "searchLabel", publicName: "searchLabel", isSignal: true, isRequired: true, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, sortOptions: { classPropertyName: "sortOptions", publicName: "sortOptions", isSignal: true, isRequired: true, transformFunction: null }, sortValue: { classPropertyName: "sortValue", publicName: "sortValue", isSignal: true, isRequired: true, transformFunction: null }, sortDirection: { classPropertyName: "sortDirection", publicName: "sortDirection", isSignal: true, isRequired: false, transformFunction: null }, sortLabel: { classPropertyName: "sortLabel", publicName: "sortLabel", isSignal: true, isRequired: false, transformFunction: null }, directionLabel: { classPropertyName: "directionLabel", publicName: "directionLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchValueChange: "searchValueChange", sortValueChange: "sortValueChange", sortDirectionChange: "sortDirectionChange" }, ngImport: i0, template: "<div class=\"gbt-list-toolbar\">\n <gbt-input\n class=\"gbt-list-toolbar__search\"\n [label]=\"searchLabel()\"\n [placeholder]=\"searchPlaceholder()\"\n [formControl]=\"searchControl\"\n />\n <gbt-select\n class=\"gbt-list-toolbar__sort\"\n [label]=\"sortLabel()\"\n [options]=\"asSelectOptions(sortOptions())\"\n [formControl]=\"sortControl\"\n />\n <button\n type=\"button\"\n class=\"gbt-list-toolbar__direction\"\n (click)=\"toggleDirection()\"\n [attr.aria-label]=\"directionLabel()\"\n [attr.aria-pressed]=\"sortDirection() === 'desc'\"\n >\n <gbt-icon [name]=\"sortDirection() === 'asc' ? 'arrow-up' : 'arrow-down'\" />\n </button>\n</div>\n", styles: [":host{display:block}.gbt-list-toolbar{display:flex;align-items:flex-end;gap:.75rem;flex-wrap:wrap}.gbt-list-toolbar__search{flex:1;min-width:200px}.gbt-list-toolbar__sort{min-width:160px}.gbt-list-toolbar__direction{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;flex-shrink:0;padding:0;border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);background:var(--bg-principal);color:var(--text-secondary);cursor:pointer;transition:background var(--site-transition-fast)}.gbt-list-toolbar__direction:hover{background:var(--bg-hover)}.gbt-list-toolbar__direction:focus-visible{outline:2px solid var(--primary);outline-offset:2px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: GbtInput, selector: "gbt-input", inputs: ["id", "label", "type", "required", "disabled", "placeholder", "errorMessage", "autocomplete", "showPasswordLabel", "hidePasswordLabel"], outputs: ["committed"] }, { kind: "component", type: Select, selector: "gbt-select", inputs: ["id", "label", "size", "options", "multiple", "chips", "placeholder", "disabled", "required", "errorMessage", "selectedCountLabel", "chipRemoveLabel"] }, { kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
711
|
+
}
|
|
712
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListToolbar, decorators: [{
|
|
713
|
+
type: Component,
|
|
714
|
+
args: [{ selector: 'gbt-list-toolbar', standalone: true, imports: [ReactiveFormsModule, GbtInput, Select, Icon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"gbt-list-toolbar\">\n <gbt-input\n class=\"gbt-list-toolbar__search\"\n [label]=\"searchLabel()\"\n [placeholder]=\"searchPlaceholder()\"\n [formControl]=\"searchControl\"\n />\n <gbt-select\n class=\"gbt-list-toolbar__sort\"\n [label]=\"sortLabel()\"\n [options]=\"asSelectOptions(sortOptions())\"\n [formControl]=\"sortControl\"\n />\n <button\n type=\"button\"\n class=\"gbt-list-toolbar__direction\"\n (click)=\"toggleDirection()\"\n [attr.aria-label]=\"directionLabel()\"\n [attr.aria-pressed]=\"sortDirection() === 'desc'\"\n >\n <gbt-icon [name]=\"sortDirection() === 'asc' ? 'arrow-up' : 'arrow-down'\" />\n </button>\n</div>\n", styles: [":host{display:block}.gbt-list-toolbar{display:flex;align-items:flex-end;gap:.75rem;flex-wrap:wrap}.gbt-list-toolbar__search{flex:1;min-width:200px}.gbt-list-toolbar__sort{min-width:160px}.gbt-list-toolbar__direction{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;flex-shrink:0;padding:0;border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);background:var(--bg-principal);color:var(--text-secondary);cursor:pointer;transition:background var(--site-transition-fast)}.gbt-list-toolbar__direction:hover{background:var(--bg-hover)}.gbt-list-toolbar__direction:focus-visible{outline:2px solid var(--primary);outline-offset:2px}\n"] }]
|
|
715
|
+
}], ctorParameters: () => [], propDecorators: { searchValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchValue", required: false }] }], searchLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchLabel", required: true }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], sortOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortOptions", required: true }] }], sortValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortValue", required: true }] }], sortDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDirection", required: false }] }], sortLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortLabel", required: false }] }], directionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "directionLabel", required: false }] }], searchValueChange: [{ type: i0.Output, args: ["searchValueChange"] }], sortValueChange: [{ type: i0.Output, args: ["sortValueChange"] }], sortDirectionChange: [{ type: i0.Output, args: ["sortDirectionChange"] }] } });
|
|
716
|
+
|
|
717
|
+
class Card {
|
|
718
|
+
hoverable = input(false, { ...(ngDevMode ? { debugName: "hoverable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
719
|
+
heading = input('', /* @ts-ignore */
|
|
720
|
+
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
721
|
+
icon = input('', /* @ts-ignore */
|
|
722
|
+
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
723
|
+
headingLevel = input(2, /* @ts-ignore */
|
|
724
|
+
...(ngDevMode ? [{ debugName: "headingLevel" }] : /* istanbul ignore next */ []));
|
|
725
|
+
cardClass = computed(() => 'gbt-card' + (this.hoverable() ? ' gbt-card--hoverable' : ''), /* @ts-ignore */
|
|
726
|
+
...(ngDevMode ? [{ debugName: "cardClass" }] : /* istanbul ignore next */ []));
|
|
727
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Card, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
728
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Card, isStandalone: true, selector: "gbt-card", inputs: { hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"cardClass()\">\n @if (heading()) {\n <div class=\"gbt-card__header\">\n @switch (headingLevel()) {\n @case (1) {\n <h1 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h1>\n }\n @case (3) {\n <h3 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h3>\n }\n @case (4) {\n <h4 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h4>\n }\n @case (5) {\n <h5 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h5>\n }\n @case (6) {\n <h6 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h6>\n }\n @default {\n <h2 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h2>\n }\n }\n <ng-content select=\"[card-header-actions]\"></ng-content>\n </div>\n }\n <ng-content></ng-content>\n</div>\n<ng-template #headingContent>\n @if (icon()) {\n <gbt-icon [name]=\"icon()\" aria-hidden=\"true\" />\n }\n {{ heading() }}\n</ng-template>\n", styles: [":host{display:block}.gbt-card{background:var(--bg-principal);border-radius:var(--site-border-radius-lg);box-shadow:var(--site-shadow-sm);position:relative;overflow:hidden;transition:box-shadow .18s cubic-bezier(.4,0,.2,1);padding:1.25rem 1.5rem;font-size:.9rem;line-height:1.65;color:var(--text-secondary)}.gbt-card--hoverable{cursor:pointer;-webkit-user-select:none;user-select:none}.gbt-card--hoverable:hover{box-shadow:var(--site-shadow-lg)}.gbt-card__header{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:.75rem}.gbt-card__title{display:flex;align-items:center;gap:.5rem;font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}\n"], dependencies: [{ kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
729
|
+
}
|
|
730
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Card, decorators: [{
|
|
731
|
+
type: Component,
|
|
732
|
+
args: [{ selector: 'gbt-card', standalone: true, imports: [Icon, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"cardClass()\">\n @if (heading()) {\n <div class=\"gbt-card__header\">\n @switch (headingLevel()) {\n @case (1) {\n <h1 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h1>\n }\n @case (3) {\n <h3 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h3>\n }\n @case (4) {\n <h4 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h4>\n }\n @case (5) {\n <h5 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h5>\n }\n @case (6) {\n <h6 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h6>\n }\n @default {\n <h2 class=\"gbt-card__title\"><ng-container *ngTemplateOutlet=\"headingContent\" /></h2>\n }\n }\n <ng-content select=\"[card-header-actions]\"></ng-content>\n </div>\n }\n <ng-content></ng-content>\n</div>\n<ng-template #headingContent>\n @if (icon()) {\n <gbt-icon [name]=\"icon()\" aria-hidden=\"true\" />\n }\n {{ heading() }}\n</ng-template>\n", styles: [":host{display:block}.gbt-card{background:var(--bg-principal);border-radius:var(--site-border-radius-lg);box-shadow:var(--site-shadow-sm);position:relative;overflow:hidden;transition:box-shadow .18s cubic-bezier(.4,0,.2,1);padding:1.25rem 1.5rem;font-size:.9rem;line-height:1.65;color:var(--text-secondary)}.gbt-card--hoverable{cursor:pointer;-webkit-user-select:none;user-select:none}.gbt-card--hoverable:hover{box-shadow:var(--site-shadow-lg)}.gbt-card__header{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:.75rem}.gbt-card__title{display:flex;align-items:center;gap:.5rem;font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}\n"] }]
|
|
733
|
+
}], propDecorators: { hoverable: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverable", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }] } });
|
|
734
|
+
|
|
735
|
+
let nextCheckboxId = 0;
|
|
736
|
+
class Checkbox {
|
|
737
|
+
id = input(`gbt-checkbox-${++nextCheckboxId}`, /* @ts-ignore */
|
|
738
|
+
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
739
|
+
label = input('', /* @ts-ignore */
|
|
740
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
741
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
742
|
+
checked = signal(false, /* @ts-ignore */
|
|
743
|
+
...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
|
|
744
|
+
formDisabled = signal(false, /* @ts-ignore */
|
|
745
|
+
...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
|
|
746
|
+
isDisabled = computed(() => this.disabled() || this.formDisabled(), /* @ts-ignore */
|
|
747
|
+
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
748
|
+
onChange = () => { };
|
|
749
|
+
onTouched = () => { };
|
|
750
|
+
writeValue(value) {
|
|
751
|
+
this.checked.set(!!value);
|
|
752
|
+
}
|
|
753
|
+
registerOnChange(fn) {
|
|
754
|
+
this.onChange = fn;
|
|
755
|
+
}
|
|
756
|
+
registerOnTouched(fn) {
|
|
757
|
+
this.onTouched = fn;
|
|
758
|
+
}
|
|
759
|
+
setDisabledState(isDisabled) {
|
|
760
|
+
this.formDisabled.set(isDisabled);
|
|
761
|
+
}
|
|
762
|
+
onToggle(event) {
|
|
763
|
+
const value = event.target.checked;
|
|
764
|
+
this.checked.set(value);
|
|
765
|
+
this.onChange(value);
|
|
766
|
+
this.onTouched();
|
|
767
|
+
}
|
|
768
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Checkbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
769
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: Checkbox, isStandalone: true, selector: "gbt-checkbox", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
770
|
+
{
|
|
771
|
+
provide: NG_VALUE_ACCESSOR,
|
|
772
|
+
useExisting: forwardRef(() => Checkbox),
|
|
773
|
+
multi: true,
|
|
774
|
+
},
|
|
775
|
+
], ngImport: i0, template: "<label class=\"gbt-checkbox\" [class.gbt-checkbox--disabled]=\"isDisabled()\">\n <input\n type=\"checkbox\"\n [id]=\"id()\"\n [checked]=\"checked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"onToggle($event)\"\n />\n <span>{{ label() }}</span>\n</label>\n", styles: [".gbt-checkbox{position:relative;display:inline-flex;align-items:center;gap:.5rem;font-size:.875rem;color:var(--text-primary);cursor:pointer}.gbt-checkbox:before{content:\"\";position:absolute;inset:50% auto auto 50%;width:max(100%,24px);height:max(100%,24px);transform:translate(-50%,-50%)}.gbt-checkbox--disabled{cursor:not-allowed;opacity:.5}.gbt-checkbox input{width:1rem;height:1rem;accent-color:var(--primary)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
776
|
+
}
|
|
777
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Checkbox, decorators: [{
|
|
778
|
+
type: Component,
|
|
779
|
+
args: [{ selector: 'gbt-checkbox', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
780
|
+
{
|
|
781
|
+
provide: NG_VALUE_ACCESSOR,
|
|
782
|
+
useExisting: forwardRef(() => Checkbox),
|
|
783
|
+
multi: true,
|
|
784
|
+
},
|
|
785
|
+
], template: "<label class=\"gbt-checkbox\" [class.gbt-checkbox--disabled]=\"isDisabled()\">\n <input\n type=\"checkbox\"\n [id]=\"id()\"\n [checked]=\"checked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"onToggle($event)\"\n />\n <span>{{ label() }}</span>\n</label>\n", styles: [".gbt-checkbox{position:relative;display:inline-flex;align-items:center;gap:.5rem;font-size:.875rem;color:var(--text-primary);cursor:pointer}.gbt-checkbox:before{content:\"\";position:absolute;inset:50% auto auto 50%;width:max(100%,24px);height:max(100%,24px);transform:translate(-50%,-50%)}.gbt-checkbox--disabled{cursor:not-allowed;opacity:.5}.gbt-checkbox input{width:1rem;height:1rem;accent-color:var(--primary)}\n"] }]
|
|
786
|
+
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
564
787
|
|
|
565
788
|
class Modal {
|
|
566
789
|
isOpen = input.required(/* @ts-ignore */
|
|
@@ -892,7 +1115,7 @@ class Tabs {
|
|
|
892
1115
|
...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
|
|
893
1116
|
triggers = viewChildren('trigger', /* @ts-ignore */
|
|
894
1117
|
...(ngDevMode ? [{ debugName: "triggers" }] : /* istanbul ignore next */ []));
|
|
895
|
-
activeIndex =
|
|
1118
|
+
activeIndex = model(0, /* @ts-ignore */
|
|
896
1119
|
...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
897
1120
|
constructor() {
|
|
898
1121
|
effect(() => {
|
|
@@ -901,6 +1124,21 @@ class Tabs {
|
|
|
901
1124
|
const groupId = this.id();
|
|
902
1125
|
tabs.forEach((tab, i) => tab.setState(i, i === active, groupId));
|
|
903
1126
|
});
|
|
1127
|
+
// Self-heals an out-of-range `activeIndex` — e.g. a consumer binds it to
|
|
1128
|
+
// a URL query parameter and the stored value no longer matches any tab —
|
|
1129
|
+
// instead of leaving every panel hidden and every trigger out of the
|
|
1130
|
+
// keyboard tab order with no way to reach the component at all.
|
|
1131
|
+
effect(() => {
|
|
1132
|
+
const count = this.tabs().length;
|
|
1133
|
+
if (count === 0) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
const current = this.activeIndex();
|
|
1137
|
+
const clamped = Math.min(Math.max(current, 0), count - 1);
|
|
1138
|
+
if (clamped !== current) {
|
|
1139
|
+
this.activeIndex.set(clamped);
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
904
1142
|
}
|
|
905
1143
|
select(index) {
|
|
906
1144
|
this.activeIndex.set(index);
|
|
@@ -925,12 +1163,12 @@ class Tabs {
|
|
|
925
1163
|
this.triggers()[next]?.nativeElement.focus();
|
|
926
1164
|
}
|
|
927
1165
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Tabs, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
928
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Tabs, isStandalone: true, selector: "gbt-tabs", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "tabs", predicate: Tab, isSignal: true }], viewQueries: [{ propertyName: "triggers", predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"gbt-tabs\">\n <div class=\"gbt-tabs__list\" role=\"tablist\">\n @for (tab of tabs(); track tab; let i = $index) {\n <button\n #trigger\n type=\"button\"\n class=\"gbt-tabs__trigger\"\n [class.gbt-tabs__trigger--active]=\"activeIndex() === i\"\n role=\"tab\"\n [id]=\"id() + '-trigger-' + i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-controls]=\"id() + '-panel-' + i\"\n [tabIndex]=\"activeIndex() === i ? 0 : -1\"\n (click)=\"select(i)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n {{ tab.label() }}\n </button>\n }\n </div>\n <div class=\"gbt-tabs__panels\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [":host{display:block}.gbt-tabs{display:flex;flex-direction:column}.gbt-tabs__list{display:flex;gap:.5rem;border-bottom:1px solid var(--border-color);overflow-x:auto}.gbt-tabs__trigger{appearance:none;background:none;border:none;border-bottom:2px solid transparent;padding:.75rem 1rem;font-size:.9375rem;font-weight:500;color:var(--text-secondary);cursor:pointer;white-space:nowrap;transition:color var(--site-transition-fast),border-color var(--site-transition-fast)}.gbt-tabs__trigger:hover{color:var(--text-primary)}.gbt-tabs__trigger:focus-visible{outline:2px solid var(--primary);outline-offset:-2px;border-radius:var(--site-border-radius-sm)}.gbt-tabs__trigger--active{color:var(--primary);border-bottom-color:var(--primary)}.gbt-tabs__panels{padding-top:1rem;display:flex;flex-direction:column;gap:1rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1166
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Tabs, isStandalone: true, selector: "gbt-tabs", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange" }, queries: [{ propertyName: "tabs", predicate: Tab, isSignal: true }], viewQueries: [{ propertyName: "triggers", predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"gbt-tabs\">\n <div class=\"gbt-tabs__list\" role=\"tablist\">\n @for (tab of tabs(); track tab; let i = $index) {\n <button\n #trigger\n type=\"button\"\n class=\"gbt-tabs__trigger\"\n [class.gbt-tabs__trigger--active]=\"activeIndex() === i\"\n role=\"tab\"\n [id]=\"id() + '-trigger-' + i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-controls]=\"id() + '-panel-' + i\"\n [tabIndex]=\"activeIndex() === i ? 0 : -1\"\n (click)=\"select(i)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n {{ tab.label() }}\n </button>\n }\n </div>\n <div class=\"gbt-tabs__panels\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [":host{display:block}.gbt-tabs{display:flex;flex-direction:column}.gbt-tabs__list{display:flex;gap:.5rem;border-bottom:1px solid var(--border-color);overflow-x:auto}.gbt-tabs__trigger{appearance:none;background:none;border:none;border-bottom:2px solid transparent;padding:.75rem 1rem;font-size:.9375rem;font-weight:500;color:var(--text-secondary);cursor:pointer;white-space:nowrap;transition:color var(--site-transition-fast),border-color var(--site-transition-fast)}.gbt-tabs__trigger:hover{color:var(--text-primary)}.gbt-tabs__trigger:focus-visible{outline:2px solid var(--primary);outline-offset:-2px;border-radius:var(--site-border-radius-sm)}.gbt-tabs__trigger--active{color:var(--primary);border-bottom-color:var(--primary)}.gbt-tabs__panels{padding-top:1rem;display:flex;flex-direction:column;gap:1rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
929
1167
|
}
|
|
930
1168
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Tabs, decorators: [{
|
|
931
1169
|
type: Component,
|
|
932
1170
|
args: [{ selector: 'gbt-tabs', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"gbt-tabs\">\n <div class=\"gbt-tabs__list\" role=\"tablist\">\n @for (tab of tabs(); track tab; let i = $index) {\n <button\n #trigger\n type=\"button\"\n class=\"gbt-tabs__trigger\"\n [class.gbt-tabs__trigger--active]=\"activeIndex() === i\"\n role=\"tab\"\n [id]=\"id() + '-trigger-' + i\"\n [attr.aria-selected]=\"activeIndex() === i\"\n [attr.aria-controls]=\"id() + '-panel-' + i\"\n [tabIndex]=\"activeIndex() === i ? 0 : -1\"\n (click)=\"select(i)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n {{ tab.label() }}\n </button>\n }\n </div>\n <div class=\"gbt-tabs__panels\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [":host{display:block}.gbt-tabs{display:flex;flex-direction:column}.gbt-tabs__list{display:flex;gap:.5rem;border-bottom:1px solid var(--border-color);overflow-x:auto}.gbt-tabs__trigger{appearance:none;background:none;border:none;border-bottom:2px solid transparent;padding:.75rem 1rem;font-size:.9375rem;font-weight:500;color:var(--text-secondary);cursor:pointer;white-space:nowrap;transition:color var(--site-transition-fast),border-color var(--site-transition-fast)}.gbt-tabs__trigger:hover{color:var(--text-primary)}.gbt-tabs__trigger:focus-visible{outline:2px solid var(--primary);outline-offset:-2px;border-radius:var(--site-border-radius-sm)}.gbt-tabs__trigger--active{color:var(--primary);border-bottom-color:var(--primary)}.gbt-tabs__panels{padding-top:1rem;display:flex;flex-direction:column;gap:1rem}\n"] }]
|
|
933
|
-
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => Tab), { isSignal: true }] }], triggers: [{ type: i0.ViewChildren, args: ['trigger', { isSignal: true }] }] } });
|
|
1171
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => Tab), { isSignal: true }] }], triggers: [{ type: i0.ViewChildren, args: ['trigger', { isSignal: true }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }, { type: i0.Output, args: ["activeIndexChange"] }] } });
|
|
934
1172
|
|
|
935
1173
|
function linearScale(domain, range) {
|
|
936
1174
|
const [d0, d1] = domain;
|
|
@@ -2431,6 +2669,117 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
2431
2669
|
}, template: "<div class=\"gbt-menu\">\n <button\n #trigger\n type=\"button\"\n class=\"gbt-menu__trigger\"\n [class.gbt-menu__trigger--open]=\"open()\"\n [class.gbt-menu__trigger--icon-only]=\"triggerIcon()\"\n aria-haspopup=\"menu\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-label]=\"triggerIcon() ? label() : null\"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n @if (triggerIcon(); as icon) {\n <gbt-icon [name]=\"icon\" aria-hidden=\"true\" />\n } @else {\n <span class=\"gbt-menu__label\">{{ label() }}</span>\n <gbt-icon name=\"chevron-down\" class=\"gbt-menu__chevron\" aria-hidden=\"true\" />\n }\n </button>\n\n @if (open() && position(); as pos) {\n <div\n #list\n class=\"gbt-menu__list\"\n role=\"menu\"\n tabindex=\"-1\"\n [attr.aria-label]=\"label()\"\n [style.top]=\"pos.top\"\n [style.left]=\"pos.left\"\n [style.right]=\"pos.right\"\n (keydown)=\"onListKeydown($event)\"\n (click)=\"onListClick()\"\n >\n <ng-content />\n </div>\n }\n</div>\n", styles: [":host{display:inline-block}.gbt-menu{position:relative;display:inline-block}.gbt-menu__trigger{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:transparent;border:1px solid transparent;border-radius:var(--site-border-radius-sm);color:var(--text-primary);font-size:.875rem;cursor:pointer;transition:background .12s cubic-bezier(.4,0,.2,1)}.gbt-menu__trigger:hover{background:var(--bg-hover)}.gbt-menu__trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.gbt-menu__trigger--open{background:var(--bg-hover)}.gbt-menu__trigger--icon-only{padding:.5rem;gap:0}.gbt-menu__chevron{flex-shrink:0;color:var(--text-secondary);transition:transform .2s cubic-bezier(.4,0,.2,1)}.gbt-menu__trigger--open .gbt-menu__chevron{transform:rotate(180deg)}.gbt-menu__list{position:fixed;z-index:1000;display:flex;flex-direction:column;min-width:180px;padding:6px;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);box-shadow:var(--site-shadow-lg);animation:gbt-menu-scale-in .15s cubic-bezier(.34,1.56,.64,1) both}@keyframes gbt-menu-scale-in{0%{opacity:0;transform:scale(.97) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(prefers-reduced-motion:reduce){.gbt-menu__list{animation:none}.gbt-menu__chevron{transition:none}}\n"] }]
|
|
2432
2670
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], triggerIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerIcon", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], list: [{ type: i0.ViewChild, args: ['list', { isSignal: true }] }] } });
|
|
2433
2671
|
|
|
2672
|
+
const ELLIPSIS = '…';
|
|
2673
|
+
function range(start, end) {
|
|
2674
|
+
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
2675
|
+
}
|
|
2676
|
+
function paginationRange(page, pageCount, siblingCount) {
|
|
2677
|
+
const totalPageNumbers = siblingCount + 5;
|
|
2678
|
+
if (totalPageNumbers >= pageCount) {
|
|
2679
|
+
return range(1, pageCount);
|
|
2680
|
+
}
|
|
2681
|
+
const leftSiblingIndex = Math.max(page - siblingCount, 1);
|
|
2682
|
+
const rightSiblingIndex = Math.min(page + siblingCount, pageCount);
|
|
2683
|
+
const shouldShowLeftDots = leftSiblingIndex > 2;
|
|
2684
|
+
// -2, not -1: a lone skipped page right before the last one isn't worth an
|
|
2685
|
+
// ellipsis — showing that page costs no more room than the "…" would.
|
|
2686
|
+
const shouldShowRightDots = rightSiblingIndex < pageCount - 2;
|
|
2687
|
+
if (!shouldShowLeftDots && shouldShowRightDots) {
|
|
2688
|
+
const leftItemCount = 3 + siblingCount * 2;
|
|
2689
|
+
return [...range(1, leftItemCount), ELLIPSIS, pageCount];
|
|
2690
|
+
}
|
|
2691
|
+
if (shouldShowLeftDots && !shouldShowRightDots) {
|
|
2692
|
+
const rightItemCount = 3 + siblingCount * 2;
|
|
2693
|
+
return [1, ELLIPSIS, ...range(pageCount - rightItemCount + 1, pageCount)];
|
|
2694
|
+
}
|
|
2695
|
+
return [1, ELLIPSIS, ...range(leftSiblingIndex, rightSiblingIndex), ELLIPSIS, pageCount];
|
|
2696
|
+
}
|
|
2697
|
+
class Pagination {
|
|
2698
|
+
page = input(1, /* @ts-ignore */
|
|
2699
|
+
...(ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []));
|
|
2700
|
+
pageSize = input(10, /* @ts-ignore */
|
|
2701
|
+
...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
|
|
2702
|
+
totalItems = input.required(/* @ts-ignore */
|
|
2703
|
+
...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
|
|
2704
|
+
siblingCount = input(1, /* @ts-ignore */
|
|
2705
|
+
...(ngDevMode ? [{ debugName: "siblingCount" }] : /* istanbul ignore next */ []));
|
|
2706
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2707
|
+
ariaLabel = input('Pagination', /* @ts-ignore */
|
|
2708
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
2709
|
+
previousLabel = input('Previous page', /* @ts-ignore */
|
|
2710
|
+
...(ngDevMode ? [{ debugName: "previousLabel" }] : /* istanbul ignore next */ []));
|
|
2711
|
+
nextLabel = input('Next page', /* @ts-ignore */
|
|
2712
|
+
...(ngDevMode ? [{ debugName: "nextLabel" }] : /* istanbul ignore next */ []));
|
|
2713
|
+
pageLabel = input((page) => `Page ${page}`, /* @ts-ignore */
|
|
2714
|
+
...(ngDevMode ? [{ debugName: "pageLabel" }] : /* istanbul ignore next */ []));
|
|
2715
|
+
pageSizeOptions = input([], /* @ts-ignore */
|
|
2716
|
+
...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
|
|
2717
|
+
pageSizeLabel = input((size) => `${size} / page`, /* @ts-ignore */
|
|
2718
|
+
...(ngDevMode ? [{ debugName: "pageSizeLabel" }] : /* istanbul ignore next */ []));
|
|
2719
|
+
pageSizeSelectLabel = input('Rows per page', /* @ts-ignore */
|
|
2720
|
+
...(ngDevMode ? [{ debugName: "pageSizeSelectLabel" }] : /* istanbul ignore next */ []));
|
|
2721
|
+
showItemsSummary = input(false, { ...(ngDevMode ? { debugName: "showItemsSummary" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2722
|
+
itemsSummaryLabel = input((shown, total) => `${shown} of ${total} items`, /* @ts-ignore */
|
|
2723
|
+
...(ngDevMode ? [{ debugName: "itemsSummaryLabel" }] : /* istanbul ignore next */ []));
|
|
2724
|
+
pageChange = output();
|
|
2725
|
+
pageSizeChange = output();
|
|
2726
|
+
ELLIPSIS = ELLIPSIS;
|
|
2727
|
+
pageCount = computed(() => Math.max(1, Math.ceil(this.totalItems() / this.pageSize())), /* @ts-ignore */
|
|
2728
|
+
...(ngDevMode ? [{ debugName: "pageCount" }] : /* istanbul ignore next */ []));
|
|
2729
|
+
items = computed(() => paginationRange(this.page(), this.pageCount(), this.siblingCount()), /* @ts-ignore */
|
|
2730
|
+
...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
2731
|
+
itemsShown = computed(() => {
|
|
2732
|
+
const start = (this.page() - 1) * this.pageSize();
|
|
2733
|
+
return Math.max(0, Math.min(this.pageSize(), this.totalItems() - start));
|
|
2734
|
+
}, /* @ts-ignore */
|
|
2735
|
+
...(ngDevMode ? [{ debugName: "itemsShown" }] : /* istanbul ignore next */ []));
|
|
2736
|
+
itemsSummary = computed(() => this.itemsSummaryLabel()(this.itemsShown(), this.totalItems()), /* @ts-ignore */
|
|
2737
|
+
...(ngDevMode ? [{ debugName: "itemsSummary" }] : /* istanbul ignore next */ []));
|
|
2738
|
+
pageSizeSelectOptions = computed(() => this.pageSizeOptions().map((size) => ({ value: size, label: this.pageSizeLabel()(size) })), /* @ts-ignore */
|
|
2739
|
+
...(ngDevMode ? [{ debugName: "pageSizeSelectOptions" }] : /* istanbul ignore next */ []));
|
|
2740
|
+
pageSizeControl = new FormControl(this.pageSize(), {
|
|
2741
|
+
nonNullable: true,
|
|
2742
|
+
});
|
|
2743
|
+
constructor() {
|
|
2744
|
+
effect(() => {
|
|
2745
|
+
const size = this.pageSize();
|
|
2746
|
+
if (this.pageSizeControl.value !== size) {
|
|
2747
|
+
this.pageSizeControl.setValue(size, { emitEvent: false });
|
|
2748
|
+
}
|
|
2749
|
+
});
|
|
2750
|
+
this.pageSizeControl.valueChanges.pipe(takeUntilDestroyed()).subscribe((size) => {
|
|
2751
|
+
this.pageSizeChange.emit(size);
|
|
2752
|
+
this.pageChange.emit(1);
|
|
2753
|
+
});
|
|
2754
|
+
// Self-heals a stale `page` — e.g. a filter shrinks `totalItems` while
|
|
2755
|
+
// the app was sitting on a now out-of-range page — instead of leaving
|
|
2756
|
+
// the pager stuck with no page marked current and a live "previous"
|
|
2757
|
+
// button pointing at a page that no longer exists.
|
|
2758
|
+
effect(() => {
|
|
2759
|
+
const count = this.pageCount();
|
|
2760
|
+
const current = this.page();
|
|
2761
|
+
const clamped = Math.min(Math.max(current, 1), count);
|
|
2762
|
+
if (clamped !== current) {
|
|
2763
|
+
this.pageChange.emit(clamped);
|
|
2764
|
+
}
|
|
2765
|
+
});
|
|
2766
|
+
}
|
|
2767
|
+
goTo(page) {
|
|
2768
|
+
if (this.disabled())
|
|
2769
|
+
return;
|
|
2770
|
+
const clamped = Math.min(Math.max(page, 1), this.pageCount());
|
|
2771
|
+
if (clamped === this.page())
|
|
2772
|
+
return;
|
|
2773
|
+
this.pageChange.emit(clamped);
|
|
2774
|
+
}
|
|
2775
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Pagination, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2776
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: Pagination, isStandalone: true, selector: "gbt-pagination", inputs: { page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, totalItems: { classPropertyName: "totalItems", publicName: "totalItems", isSignal: true, isRequired: true, transformFunction: null }, siblingCount: { classPropertyName: "siblingCount", publicName: "siblingCount", 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 }, previousLabel: { classPropertyName: "previousLabel", publicName: "previousLabel", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, pageLabel: { classPropertyName: "pageLabel", publicName: "pageLabel", isSignal: true, isRequired: false, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, pageSizeLabel: { classPropertyName: "pageSizeLabel", publicName: "pageSizeLabel", isSignal: true, isRequired: false, transformFunction: null }, pageSizeSelectLabel: { classPropertyName: "pageSizeSelectLabel", publicName: "pageSizeSelectLabel", isSignal: true, isRequired: false, transformFunction: null }, showItemsSummary: { classPropertyName: "showItemsSummary", publicName: "showItemsSummary", isSignal: true, isRequired: false, transformFunction: null }, itemsSummaryLabel: { classPropertyName: "itemsSummaryLabel", publicName: "itemsSummaryLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange" }, ngImport: i0, template: "<div class=\"gbt-pagination\">\n <div class=\"gbt-pagination__side gbt-pagination__side--start\">\n @if (showItemsSummary()) {\n <span class=\"gbt-pagination__summary\">{{ itemsSummary() }}</span>\n }\n </div>\n\n <nav [attr.aria-label]=\"ariaLabel()\">\n <ul class=\"gbt-pagination__list\">\n <li>\n <button\n type=\"button\"\n class=\"gbt-pagination__nav\"\n [disabled]=\"disabled() || page() <= 1\"\n [attr.aria-label]=\"previousLabel()\"\n (click)=\"goTo(page() - 1)\"\n >\n <gbt-icon name=\"chevron-left\" aria-hidden=\"true\" />\n </button>\n </li>\n @for (item of items(); track $index) {\n @if (item === ELLIPSIS) {\n <li class=\"gbt-pagination__ellipsis\" aria-hidden=\"true\">{{ ELLIPSIS }}</li>\n } @else {\n <li>\n <button\n type=\"button\"\n class=\"gbt-pagination__page\"\n [class.gbt-pagination__page--current]=\"item === page()\"\n [attr.aria-current]=\"item === page() ? 'page' : null\"\n [attr.aria-label]=\"pageLabel()(item)\"\n [disabled]=\"disabled()\"\n (click)=\"goTo(item)\"\n >\n {{ item }}\n </button>\n </li>\n }\n }\n <li>\n <button\n type=\"button\"\n class=\"gbt-pagination__nav\"\n [disabled]=\"disabled() || page() >= pageCount()\"\n [attr.aria-label]=\"nextLabel()\"\n (click)=\"goTo(page() + 1)\"\n >\n <gbt-icon name=\"chevron-right\" aria-hidden=\"true\" />\n </button>\n </li>\n </ul>\n </nav>\n\n <div class=\"gbt-pagination__side gbt-pagination__side--end\">\n @if (pageSizeOptions().length > 0) {\n <gbt-select\n class=\"gbt-pagination__page-size\"\n size=\"sm\"\n [label]=\"pageSizeSelectLabel()\"\n [options]=\"pageSizeSelectOptions()\"\n [disabled]=\"disabled()\"\n [formControl]=\"pageSizeControl\"\n />\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.gbt-pagination{display:flex;align-items:center;flex-wrap:wrap;gap:1rem}.gbt-pagination__side{display:flex;align-items:center;flex:1;min-width:0}.gbt-pagination__side--start{justify-content:flex-start}.gbt-pagination__side--end{justify-content:flex-end}.gbt-pagination__summary{color:var(--text-secondary);font-size:.8125rem;white-space:nowrap}.gbt-pagination__page-size{min-width:0}.gbt-pagination__list{display:flex;align-items:center;gap:.25rem;margin:0;padding:0;list-style:none}.gbt-pagination__nav,.gbt-pagination__page{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;padding:0 .375rem;border:none;border-radius:var(--site-border-radius-sm);background:transparent;color:var(--text-primary);font-size:.875rem;cursor:pointer;transition:background .12s cubic-bezier(.4,0,.2,1)}.gbt-pagination__nav:hover:not(:disabled),.gbt-pagination__page:hover:not(:disabled){background:var(--bg-hover)}.gbt-pagination__nav:focus-visible,.gbt-pagination__page:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.gbt-pagination__nav:disabled,.gbt-pagination__page:disabled{color:var(--text-discret);cursor:not-allowed}.gbt-pagination__page--current{background:var(--primary);color:var(--text-on-primary);font-weight:600}.gbt-pagination__page--current:hover{background:var(--primary)}.gbt-pagination__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;color:var(--text-discret)}\n"], dependencies: [{ kind: "component", type: Icon, selector: "gbt-icon", inputs: ["name"] }, { kind: "component", type: Select, selector: "gbt-select", inputs: ["id", "label", "size", "options", "multiple", "chips", "placeholder", "disabled", "required", "errorMessage", "selectedCountLabel", "chipRemoveLabel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2777
|
+
}
|
|
2778
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: Pagination, decorators: [{
|
|
2779
|
+
type: Component,
|
|
2780
|
+
args: [{ selector: 'gbt-pagination', standalone: true, imports: [Icon, Select, ReactiveFormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"gbt-pagination\">\n <div class=\"gbt-pagination__side gbt-pagination__side--start\">\n @if (showItemsSummary()) {\n <span class=\"gbt-pagination__summary\">{{ itemsSummary() }}</span>\n }\n </div>\n\n <nav [attr.aria-label]=\"ariaLabel()\">\n <ul class=\"gbt-pagination__list\">\n <li>\n <button\n type=\"button\"\n class=\"gbt-pagination__nav\"\n [disabled]=\"disabled() || page() <= 1\"\n [attr.aria-label]=\"previousLabel()\"\n (click)=\"goTo(page() - 1)\"\n >\n <gbt-icon name=\"chevron-left\" aria-hidden=\"true\" />\n </button>\n </li>\n @for (item of items(); track $index) {\n @if (item === ELLIPSIS) {\n <li class=\"gbt-pagination__ellipsis\" aria-hidden=\"true\">{{ ELLIPSIS }}</li>\n } @else {\n <li>\n <button\n type=\"button\"\n class=\"gbt-pagination__page\"\n [class.gbt-pagination__page--current]=\"item === page()\"\n [attr.aria-current]=\"item === page() ? 'page' : null\"\n [attr.aria-label]=\"pageLabel()(item)\"\n [disabled]=\"disabled()\"\n (click)=\"goTo(item)\"\n >\n {{ item }}\n </button>\n </li>\n }\n }\n <li>\n <button\n type=\"button\"\n class=\"gbt-pagination__nav\"\n [disabled]=\"disabled() || page() >= pageCount()\"\n [attr.aria-label]=\"nextLabel()\"\n (click)=\"goTo(page() + 1)\"\n >\n <gbt-icon name=\"chevron-right\" aria-hidden=\"true\" />\n </button>\n </li>\n </ul>\n </nav>\n\n <div class=\"gbt-pagination__side gbt-pagination__side--end\">\n @if (pageSizeOptions().length > 0) {\n <gbt-select\n class=\"gbt-pagination__page-size\"\n size=\"sm\"\n [label]=\"pageSizeSelectLabel()\"\n [options]=\"pageSizeSelectOptions()\"\n [disabled]=\"disabled()\"\n [formControl]=\"pageSizeControl\"\n />\n }\n </div>\n</div>\n", styles: [":host{display:block;width:100%}.gbt-pagination{display:flex;align-items:center;flex-wrap:wrap;gap:1rem}.gbt-pagination__side{display:flex;align-items:center;flex:1;min-width:0}.gbt-pagination__side--start{justify-content:flex-start}.gbt-pagination__side--end{justify-content:flex-end}.gbt-pagination__summary{color:var(--text-secondary);font-size:.8125rem;white-space:nowrap}.gbt-pagination__page-size{min-width:0}.gbt-pagination__list{display:flex;align-items:center;gap:.25rem;margin:0;padding:0;list-style:none}.gbt-pagination__nav,.gbt-pagination__page{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;padding:0 .375rem;border:none;border-radius:var(--site-border-radius-sm);background:transparent;color:var(--text-primary);font-size:.875rem;cursor:pointer;transition:background .12s cubic-bezier(.4,0,.2,1)}.gbt-pagination__nav:hover:not(:disabled),.gbt-pagination__page:hover:not(:disabled){background:var(--bg-hover)}.gbt-pagination__nav:focus-visible,.gbt-pagination__page:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.gbt-pagination__nav:disabled,.gbt-pagination__page:disabled{color:var(--text-discret);cursor:not-allowed}.gbt-pagination__page--current{background:var(--primary);color:var(--text-on-primary);font-weight:600}.gbt-pagination__page--current:hover{background:var(--primary)}.gbt-pagination__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;color:var(--text-discret)}\n"] }]
|
|
2781
|
+
}], ctorParameters: () => [], propDecorators: { page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], totalItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalItems", required: true }] }], siblingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "siblingCount", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], previousLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousLabel", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], pageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageLabel", required: false }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], pageSizeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeLabel", required: false }] }], pageSizeSelectLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeSelectLabel", required: false }] }], showItemsSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "showItemsSummary", required: false }] }], itemsSummaryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemsSummaryLabel", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], pageSizeChange: [{ type: i0.Output, args: ["pageSizeChange"] }] } });
|
|
2782
|
+
|
|
2434
2783
|
class Breadcrumb {
|
|
2435
2784
|
ariaLabel = input.required(/* @ts-ignore */
|
|
2436
2785
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
@@ -3059,5 +3408,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
3059
3408
|
* Generated bundle index. Do not edit.
|
|
3060
3409
|
*/
|
|
3061
3410
|
|
|
3062
|
-
export { AppShell, Autocomplete, BarChart, BarSeries, Breadcrumb, Button, CHART_CONTEXT, Card, ChartAxis, ChartEmpty, ChartFrame, ChartLegend, ChartTable, ChartTooltip, Checkbox, ConfirmDangerModal, DimensionCard, FunnelChart, GABARIT_VERSION, GaugeBar, GbtInput, Icon, IconRegistry, LineChart, LineSeries, Menu, Modal, RadioGroup, SearchBar, Select, Sparkline, Switch, Tab, Table, Tabs, Textarea, TimelineChart, TimelineSeries, Toaster, Tooltip, areaPath, bandScale, formatCompact, formatDuration, formatNumber, formatPercent, linePath, linearScale, nearestIndex, niceTicks, niceXDomain, niceYDomain, timeScale, timeTicks };
|
|
3411
|
+
export { AppShell, Autocomplete, Badge, BarChart, BarSeries, Breadcrumb, Button, CHART_CONTEXT, Card, ChartAxis, ChartEmpty, ChartFrame, ChartLegend, ChartTable, ChartTooltip, Checkbox, ConfirmDangerModal, DimensionCard, EmptyState, FunnelChart, GABARIT_VERSION, GaugeBar, GbtInput, Icon, IconRegistry, LineChart, LineSeries, ListToolbar, Menu, Modal, Pagination, RadioGroup, SearchBar, Select, Sparkline, Switch, Tab, Table, Tabs, Tag, Textarea, TimelineChart, TimelineSeries, Toaster, Tooltip, areaPath, bandScale, formatCompact, formatDuration, formatNumber, formatPercent, linePath, linearScale, nearestIndex, niceTicks, niceXDomain, niceYDomain, timeScale, timeTicks };
|
|
3063
3412
|
//# sourceMappingURL=masmarino-gabarit.mjs.map
|