@byuhbll/components 4.3.2 → 4.4.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,9 +1,9 @@
1
1
  import * as i1 from '@angular/common';
2
- import { CommonModule, DatePipe, DOCUMENT, LowerCasePipe, NgIf } from '@angular/common';
2
+ import { CommonModule, DatePipe, DOCUMENT, LowerCasePipe, NgIf, NgClass } from '@angular/common';
3
3
  import { toSignal, toObservable } from '@angular/core/rxjs-interop';
4
4
  import { HttpClient } from '@angular/common/http';
5
5
  import * as i0 from '@angular/core';
6
- import { Component, ChangeDetectionStrategy, ViewChild, Input, input, EventEmitter, Output, inject, computed, ViewChildren, Pipe, Renderer2, viewChild, HostListener, ElementRef, ViewEncapsulation, booleanAttribute } from '@angular/core';
6
+ import { Component, ChangeDetectionStrategy, ViewChild, Input, input, EventEmitter, Output, inject, computed, ViewChildren, Pipe, Renderer2, viewChild, HostListener, ElementRef, ViewEncapsulation, booleanAttribute, createComponent, Injectable } from '@angular/core';
7
7
  import { trigger, transition, group, style, query, animateChild, animate } from '@angular/animations';
8
8
  import { map, of, switchMap, shareReplay, combineLatest, Subject, Subscription } from 'rxjs';
9
9
  import { BreakpointObserver } from '@angular/cdk/layout';
@@ -2187,6 +2187,7 @@ class StatusButtonComponent {
2187
2187
  this._rightIcon = '';
2188
2188
  this._hideLeftIcon = false;
2189
2189
  this._hideRightIcon = false;
2190
+ this._clearVariant = false;
2190
2191
  }
2191
2192
  set status(value) {
2192
2193
  this._status = value || 'info';
@@ -2222,6 +2223,12 @@ class StatusButtonComponent {
2222
2223
  get hideRightIcon() {
2223
2224
  return this._hideRightIcon;
2224
2225
  }
2226
+ set clearVariant(value) {
2227
+ this._clearVariant = value;
2228
+ }
2229
+ get clearVariant() {
2230
+ return this._clearVariant;
2231
+ }
2225
2232
  /** helper for default left icons */
2226
2233
  getDefaultLeftIcon(status) {
2227
2234
  switch (status) {
@@ -2240,11 +2247,11 @@ class StatusButtonComponent {
2240
2247
  }
2241
2248
  }
2242
2249
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: StatusButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2243
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "18.1.0", type: StatusButtonComponent, isStandalone: true, selector: "lib-status-button", inputs: { label: "label", status: "status", leftIcon: "leftIcon", rightIcon: "rightIcon", hideLeftIcon: ["hideLeftIcon", "hideLeftIcon", booleanAttribute], hideRightIcon: ["hideRightIcon", "hideRightIcon", booleanAttribute] }, ngImport: i0, template: "<button\n type=\"button\"\n [className]=\"status\"\n>\n <span *ngIf=\"leftIcon\" class=\"icon material-symbols-outlined\">{{ leftIcon }}</span>\n {{ label }}\n <span *ngIf=\"rightIcon\" class=\"icon material-symbols-outlined\">{{ rightIcon }}</span>\n</button>\n", styles: ["button{align-items:center;background-color:#ecf2f6;border:1px solid #457fa6;border-radius:4px;color:#3e7295;display:inline-flex;flex-shrink:0;font-size:16px;font-weight:400;gap:8px;height:36px;justify-content:center;padding:4px 8px}button .icon{font-size:20px}button:focus{outline:2px solid #b967c7;outline-offset:2px}button:hover{background-color:#a2bfd3;color:#26485f;cursor:pointer}button.success{background-color:#ebf6ee;border:1px solid #3ba35a;color:#1d562e}button.success:hover{background-color:#9dd1ac;color:#1d562e}button.info{background-color:#ecf2f6;border:1px solid #457fa6;color:#3e7295}button.info:hover{background-color:#a2bfd3;color:#26485f}button.warning{background-color:#faf9ec;border:1px solid #d1c844;color:#635f04}button.warning:hover{background-color:#e8e3a1;color:#635f04}button.error{background-color:#f9ecec;border:1px solid #c73e3d;color:#702121}button.error:hover{background-color:#e39e9e;color:#702121}button.disabled{background-color:#e7e7e7;border:1px solid #8f8f8f;color:#767676}button.disabled:hover{background-color:#d0d0d0;color:#141414}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
2250
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "18.1.0", type: StatusButtonComponent, isStandalone: true, selector: "lib-status-button", inputs: { label: "label", status: "status", leftIcon: "leftIcon", rightIcon: "rightIcon", hideLeftIcon: ["hideLeftIcon", "hideLeftIcon", booleanAttribute], hideRightIcon: ["hideRightIcon", "hideRightIcon", booleanAttribute], clearVariant: ["clearVariant", "clearVariant", booleanAttribute] }, ngImport: i0, template: "<button\n type=\"button\"\n [ngClass]=\"[\n status,\n clearVariant ? 'strokeless transparent-bg' : ''\n ]\"\n>\n <span *ngIf=\"leftIcon\" class=\"icon material-symbols-outlined\">{{ leftIcon }}</span>\n {{ label }}\n <span *ngIf=\"rightIcon\" class=\"icon material-symbols-outlined\">{{ rightIcon }}</span>\n</button>\n", styles: ["button{align-items:center;background-color:#ecf2f6;border:1px solid #457fa6;border-radius:4px;color:#3e7295;display:inline-flex;flex-shrink:0;font-size:1em;font-weight:400;gap:.5em;height:2.25em;justify-content:center;padding:var(--status-button-padding, .25em .5em)}button .icon{font-size:1.25em}button:focus{outline:2px solid #b967c7;outline-offset:2px}button:hover{background-color:#a2bfd3;color:#26485f;cursor:pointer}button.success{background-color:#ebf6ee;border:1px solid #3ba35a;color:#1d562e}button.success:hover{background-color:#9dd1ac;color:#1d562e}button.info{background-color:#ecf2f6;border:1px solid #457fa6;color:#3e7295}button.info:hover{background-color:#a2bfd3;color:#26485f}button.warning{background-color:#faf9ec;border:1px solid #d1c844;color:#635f04}button.warning:hover{background-color:#e8e3a1;color:#635f04}button.error{background-color:#f9ecec;border:1px solid #c73e3d;color:#702121}button.error:hover{background-color:#e39e9e;color:#702121}button.disabled{background-color:#e7e7e7;border:1px solid #8f8f8f;color:#767676}button.disabled:hover{background-color:#d0d0d0;color:#141414}button.strokeless{border:0px}button.transparent-bg{background:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
2244
2251
  }
2245
2252
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: StatusButtonComponent, decorators: [{
2246
2253
  type: Component,
2247
- args: [{ selector: 'lib-status-button', standalone: true, imports: [CommonModule, NgIf], template: "<button\n type=\"button\"\n [className]=\"status\"\n>\n <span *ngIf=\"leftIcon\" class=\"icon material-symbols-outlined\">{{ leftIcon }}</span>\n {{ label }}\n <span *ngIf=\"rightIcon\" class=\"icon material-symbols-outlined\">{{ rightIcon }}</span>\n</button>\n", styles: ["button{align-items:center;background-color:#ecf2f6;border:1px solid #457fa6;border-radius:4px;color:#3e7295;display:inline-flex;flex-shrink:0;font-size:16px;font-weight:400;gap:8px;height:36px;justify-content:center;padding:4px 8px}button .icon{font-size:20px}button:focus{outline:2px solid #b967c7;outline-offset:2px}button:hover{background-color:#a2bfd3;color:#26485f;cursor:pointer}button.success{background-color:#ebf6ee;border:1px solid #3ba35a;color:#1d562e}button.success:hover{background-color:#9dd1ac;color:#1d562e}button.info{background-color:#ecf2f6;border:1px solid #457fa6;color:#3e7295}button.info:hover{background-color:#a2bfd3;color:#26485f}button.warning{background-color:#faf9ec;border:1px solid #d1c844;color:#635f04}button.warning:hover{background-color:#e8e3a1;color:#635f04}button.error{background-color:#f9ecec;border:1px solid #c73e3d;color:#702121}button.error:hover{background-color:#e39e9e;color:#702121}button.disabled{background-color:#e7e7e7;border:1px solid #8f8f8f;color:#767676}button.disabled:hover{background-color:#d0d0d0;color:#141414}\n"] }]
2254
+ args: [{ selector: 'lib-status-button', standalone: true, imports: [CommonModule, NgIf], template: "<button\n type=\"button\"\n [ngClass]=\"[\n status,\n clearVariant ? 'strokeless transparent-bg' : ''\n ]\"\n>\n <span *ngIf=\"leftIcon\" class=\"icon material-symbols-outlined\">{{ leftIcon }}</span>\n {{ label }}\n <span *ngIf=\"rightIcon\" class=\"icon material-symbols-outlined\">{{ rightIcon }}</span>\n</button>\n", styles: ["button{align-items:center;background-color:#ecf2f6;border:1px solid #457fa6;border-radius:4px;color:#3e7295;display:inline-flex;flex-shrink:0;font-size:1em;font-weight:400;gap:.5em;height:2.25em;justify-content:center;padding:var(--status-button-padding, .25em .5em)}button .icon{font-size:1.25em}button:focus{outline:2px solid #b967c7;outline-offset:2px}button:hover{background-color:#a2bfd3;color:#26485f;cursor:pointer}button.success{background-color:#ebf6ee;border:1px solid #3ba35a;color:#1d562e}button.success:hover{background-color:#9dd1ac;color:#1d562e}button.info{background-color:#ecf2f6;border:1px solid #457fa6;color:#3e7295}button.info:hover{background-color:#a2bfd3;color:#26485f}button.warning{background-color:#faf9ec;border:1px solid #d1c844;color:#635f04}button.warning:hover{background-color:#e8e3a1;color:#635f04}button.error{background-color:#f9ecec;border:1px solid #c73e3d;color:#702121}button.error:hover{background-color:#e39e9e;color:#702121}button.disabled{background-color:#e7e7e7;border:1px solid #8f8f8f;color:#767676}button.disabled:hover{background-color:#d0d0d0;color:#141414}button.strokeless{border:0px}button.transparent-bg{background:transparent}\n"] }]
2248
2255
  }], propDecorators: { label: [{
2249
2256
  type: Input,
2250
2257
  args: [{ required: true }]
@@ -2260,8 +2267,228 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
2260
2267
  }], hideRightIcon: [{
2261
2268
  type: Input,
2262
2269
  args: [{ transform: booleanAttribute }]
2270
+ }], clearVariant: [{
2271
+ type: Input,
2272
+ args: [{ transform: booleanAttribute }]
2263
2273
  }] } });
2264
2274
 
2275
+ const purposeToStatusMap = {
2276
+ default: 'info',
2277
+ info: 'info',
2278
+ success: 'success',
2279
+ error: 'error',
2280
+ warning: 'warning',
2281
+ };
2282
+ class SnackbarComponent {
2283
+ constructor() {
2284
+ this.purpose = 'default';
2285
+ this.title = 'Snackbar Title';
2286
+ this.description = 'Lorem ipsum';
2287
+ this.fieldPlaceholder = 'Placeholder';
2288
+ this.titleIcon = 'info';
2289
+ this.buttonLabel = 'Done';
2290
+ this.showTitle = true;
2291
+ this.showTitleIcon = true;
2292
+ this.showClose = true;
2293
+ this.showProgressBar = true;
2294
+ this.showField = true;
2295
+ this.showButton = true;
2296
+ this.autoDismiss = true;
2297
+ this.visible = true;
2298
+ this.progressMs = 4000;
2299
+ this.y = 24;
2300
+ this.closed = new EventEmitter();
2301
+ this.visibleChange = new EventEmitter();
2302
+ this.isOpen = false;
2303
+ this.EXIT_MS = 300;
2304
+ }
2305
+ ngOnInit() {
2306
+ if (this.visible) {
2307
+ // enter on next tick
2308
+ setTimeout(() => (this.isOpen = true), 0);
2309
+ this.startDismissTimer();
2310
+ }
2311
+ }
2312
+ ngOnChanges(changes) {
2313
+ if ('visible' in changes) {
2314
+ // when parent toggles visible
2315
+ if (this.visible) {
2316
+ // becoming visible -> open + (re)start timer
2317
+ this.isOpen = false;
2318
+ setTimeout(() => (this.isOpen = true), 0);
2319
+ this.startDismissTimer();
2320
+ }
2321
+ else {
2322
+ // becoming hidden -> stop timers and ensure closed state
2323
+ this.clearDismissTimer();
2324
+ this.isOpen = false;
2325
+ }
2326
+ }
2327
+ }
2328
+ ngOnDestroy() {
2329
+ this.clearDismissTimer();
2330
+ }
2331
+ // used by the × button, done button, and auto-dismiss
2332
+ close() {
2333
+ if (!this.isOpen && !this.visible)
2334
+ return;
2335
+ this.clearDismissTimer();
2336
+ this.isOpen = false; // triggers exit transition
2337
+ // after exit animation, hide + notify
2338
+ window.setTimeout(() => {
2339
+ if (this.visible) {
2340
+ this.visible = false;
2341
+ this.visibleChange.emit(false);
2342
+ }
2343
+ this.closed.emit();
2344
+ }, this.EXIT_MS);
2345
+ }
2346
+ get status() {
2347
+ return purposeToStatusMap[this.purpose];
2348
+ }
2349
+ startDismissTimer() {
2350
+ if (!this.autoDismiss)
2351
+ return;
2352
+ this.clearDismissTimer();
2353
+ this.dismissTimer = window.setTimeout(() => this.close(), this.progressMs);
2354
+ }
2355
+ clearDismissTimer() {
2356
+ if (this.dismissTimer) {
2357
+ clearTimeout(this.dismissTimer);
2358
+ this.dismissTimer = undefined;
2359
+ }
2360
+ }
2361
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2362
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: SnackbarComponent, isStandalone: true, selector: "lib-snackbar", inputs: { purpose: "purpose", title: "title", description: "description", fieldPlaceholder: "fieldPlaceholder", titleIcon: "titleIcon", buttonLabel: "buttonLabel", showTitle: ["showTitle", "showTitle", booleanAttribute], showTitleIcon: ["showTitleIcon", "showTitleIcon", booleanAttribute], showClose: ["showClose", "showClose", booleanAttribute], showProgressBar: ["showProgressBar", "showProgressBar", booleanAttribute], showField: ["showField", "showField", booleanAttribute], showButton: ["showButton", "showButton", booleanAttribute], autoDismiss: ["autoDismiss", "autoDismiss", booleanAttribute], visible: ["visible", "visible", booleanAttribute], progressMs: "progressMs", y: "y" }, outputs: { closed: "closed", visibleChange: "visibleChange" }, usesOnChanges: true, ngImport: i0, template: "@if (visible) {\n <section\n class=\"snackbar\"\n [ngClass]=\"{\n 'is-default': purpose === 'default',\n 'is-info': purpose === 'info',\n 'is-success': purpose === 'success',\n 'is-error': purpose === 'error',\n 'is-warning': purpose === 'warning',\n 'is-open': isOpen,\n }\"\n role=\"status\"\n aria-live=\"polite\"\n [style.--snackbar-progress-duration]=\"progressMs + 'ms'\"\n [style.top.px]=\"y\"\n >\n <div class=\"snackbar__left\">\n @if(showTitle) {\n <div class=\"snackbar__title-row\">\n <span \n [ngClass]=\"{\n 'snackbar__title-icon': true,\n 'has-icon': showTitle && showTitleIcon\n }\"\n aria-hidden=\"true\"\n >\n @if (showTitle && showTitleIcon) {\n <i class=\"material-icons\" id=\"snackbar-title-icon\" aria-hidden=\"true\">{{ titleIcon }}</i>\n }\n </span>\n @if (showTitle) {\n <h3 class=\"snackbar__title\">{{ title }}</h3>\n }\n </div>\n }\n <p class=\"snackbar__desc\">\n {{ description }}\n </p>\n @if (showField) {\n <input class=\"snackbar__input\" type=\"text\" [placeholder]=\"fieldPlaceholder\" />\n }\n @if (showButton) {\n <lib-status-button\n label={{buttonLabel}}\n [status]=\"status\"\n [clearVariant]=\"true\"\n (click)=\"close()\"\n ></lib-status-button>\n\n }\n </div>\n <button \n type=\"button\"\n (click)=\"close()\"\n class=\"snackbar__close\"\n aria-label=\"Dismiss\"\n [style.visibility]=\"showClose ? 'visible' : 'hidden'\"\n >\n \u00D7\n </button>\n @if (showProgressBar) {\n <div class=\"snackbar__progress\">\n <div class=\"snackbar__progress-fill\"></div>\n </div>\n }\n </section>\n}\n", styles: [":root{--border-radius-md: 4px;--colors-border-primary: #d0d0d0;--colors-surface-primary: white;--colors-border-information: #457fa6;--colors-surface-information: #ecf2f6;--colors-border-success: #3ba35a;--colors-surface-success: #ebf6ee;--colors-border-warning: #d1c844;--colors-surface-warning: #faf9ec;--colors-border-error: #c73e3d;--colors-surface-error: #f9ecec}.snackbar{--snackbar-border-color: var(--colors-border-primary);--snackbar-bg: var(--colors-surface-primary);--snackbar-text: #141414;--snackbar-title-color: var(--snackbar-text);--snackbar-icon-bg: #e5edf8;--snackbar-accent: #0047ba;--snackbar-input-border: var(--snackbar-border-color);--snackbar-progress: var(--snackbar-accent);display:flex;width:26.25rem;padding:1.25rem 1rem;justify-content:space-between;align-items:flex-start;gap:.25rem;position:relative;border-radius:var(--border-radius-md, 4px);border:1px solid var(--snackbar-border-color);background:var(--snackbar-bg);box-shadow:1px 1px 4px #00000040;color:var(--snackbar-text)}.snackbar__left{display:grid;gap:.5rem;flex:1 1 auto}.snackbar__left>.snackbar__title-row~*{margin-left:var(--snackbar-right-gutter, 1.85rem)}.snackbar__title-row{display:flex;align-items:center;gap:.25rem}.snackbar__title{margin:0;font-weight:400;font-size:1.2rem;line-height:1.2;color:var(--snackbar-title-color)}.snackbar__title-icon{display:inline-flex;align-items:center;justify-content:center;width:1.5em;height:1.5em}.snackbar__title-icon.has-icon{border-radius:50%;background:var(--snackbar-icon-bg);color:var(--snackbar-accent)}.snackbar__icon{font-weight:700;font-size:1rem;line-height:1}.snackbar__desc{margin:0;opacity:.9}.snackbar__input{width:100%;max-width:100%;box-sizing:border-box;padding:.5em;border-radius:4px;border:1px solid var(--snackbar-input-border);background:#fff;color:inherit}.snackbar__close{margin-left:.5em;border:0;background:transparent;color:inherit;opacity:.7;font-size:1.5rem;padding:.25rem;line-height:1;cursor:pointer}.snackbar__progress{position:absolute;left:0;right:0;bottom:-1px;height:4px;overflow:hidden;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.snackbar__progress-fill{height:100%;width:0%;background:var(--snackbar-progress);animation:fill var(--snackbar-progress-duration, 4s) linear forwards}@keyframes fill{to{width:100%}}.snackbar.is-default{--snackbar-border-color: var(--colors-border-primary, #d0d0d0);--snackbar-bg: var(--colors-surface-primary, white);--snackbar-text: #141414;--snackbar-title-color: #003995;--snackbar-icon-bg: #e5edf8;--snackbar-accent: #003995;--snackbar-input-border: #d0d0d0;--snackbar-progress: #003995}.snackbar.is-info{--snackbar-border-color: var(--colors-border-information, #457fa6);--snackbar-bg: var(--colors-surface-information, #ecf2f6);--snackbar-text: #24495c;--snackbar-title-color: #24495c;--snackbar-icon-bg: #a2bfd3;--snackbar-accent: #306a88;--snackbar-input-border: #a2bfd3;--snackbar-progress: #306a88}.snackbar.is-success{--snackbar-border-color: var(--colors-border-success, #3ba35a);--snackbar-bg: var(--colors-surface-success, #ebf6ee);--snackbar-text: #20522e;--snackbar-title-color: #20522e;--snackbar-icon-bg: #9dd1ac;--snackbar-accent: #2e7d3f;--snackbar-input-border: #9dd1ac;--snackbar-progress: #2e7d3f}.snackbar.is-warning{--snackbar-border-color: var(--colors-border-warning, #d1c844);--snackbar-bg: var(--colors-surface-warning, #faf9ec);--snackbar-text: #514a18;--snackbar-title-color: #514a18;--snackbar-icon-bg: #e8e3a1;--snackbar-accent: #7a6f13;--snackbar-input-border: #d1c844;--snackbar-progress: #7a6f13}.snackbar.is-error{--snackbar-border-color: var(--colors-border-error, #c73e3d);--snackbar-bg: var(--colors-surface-error, #f9ecec);--snackbar-text: #611a1a;--snackbar-title-color: #611a1a;--snackbar-icon-bg: #e39e9e;--snackbar-accent: #912525;--snackbar-input-border: #c73e3d;--snackbar-progress: #912525}.snackbar{position:fixed;top:24px;right:24px;z-index:1000;transform:translate(120%);transition:transform .6s ease}.snackbar.is-open{transform:translate(0)}lib-status-button{--status-button-padding: .25em .5em .25em 0}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: StatusButtonComponent, selector: "lib-status-button", inputs: ["label", "status", "leftIcon", "rightIcon", "hideLeftIcon", "hideRightIcon", "clearVariant"] }] }); }
2363
+ }
2364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarComponent, decorators: [{
2365
+ type: Component,
2366
+ args: [{ selector: 'lib-snackbar', standalone: true, imports: [NgClass, StatusButtonComponent], template: "@if (visible) {\n <section\n class=\"snackbar\"\n [ngClass]=\"{\n 'is-default': purpose === 'default',\n 'is-info': purpose === 'info',\n 'is-success': purpose === 'success',\n 'is-error': purpose === 'error',\n 'is-warning': purpose === 'warning',\n 'is-open': isOpen,\n }\"\n role=\"status\"\n aria-live=\"polite\"\n [style.--snackbar-progress-duration]=\"progressMs + 'ms'\"\n [style.top.px]=\"y\"\n >\n <div class=\"snackbar__left\">\n @if(showTitle) {\n <div class=\"snackbar__title-row\">\n <span \n [ngClass]=\"{\n 'snackbar__title-icon': true,\n 'has-icon': showTitle && showTitleIcon\n }\"\n aria-hidden=\"true\"\n >\n @if (showTitle && showTitleIcon) {\n <i class=\"material-icons\" id=\"snackbar-title-icon\" aria-hidden=\"true\">{{ titleIcon }}</i>\n }\n </span>\n @if (showTitle) {\n <h3 class=\"snackbar__title\">{{ title }}</h3>\n }\n </div>\n }\n <p class=\"snackbar__desc\">\n {{ description }}\n </p>\n @if (showField) {\n <input class=\"snackbar__input\" type=\"text\" [placeholder]=\"fieldPlaceholder\" />\n }\n @if (showButton) {\n <lib-status-button\n label={{buttonLabel}}\n [status]=\"status\"\n [clearVariant]=\"true\"\n (click)=\"close()\"\n ></lib-status-button>\n\n }\n </div>\n <button \n type=\"button\"\n (click)=\"close()\"\n class=\"snackbar__close\"\n aria-label=\"Dismiss\"\n [style.visibility]=\"showClose ? 'visible' : 'hidden'\"\n >\n \u00D7\n </button>\n @if (showProgressBar) {\n <div class=\"snackbar__progress\">\n <div class=\"snackbar__progress-fill\"></div>\n </div>\n }\n </section>\n}\n", styles: [":root{--border-radius-md: 4px;--colors-border-primary: #d0d0d0;--colors-surface-primary: white;--colors-border-information: #457fa6;--colors-surface-information: #ecf2f6;--colors-border-success: #3ba35a;--colors-surface-success: #ebf6ee;--colors-border-warning: #d1c844;--colors-surface-warning: #faf9ec;--colors-border-error: #c73e3d;--colors-surface-error: #f9ecec}.snackbar{--snackbar-border-color: var(--colors-border-primary);--snackbar-bg: var(--colors-surface-primary);--snackbar-text: #141414;--snackbar-title-color: var(--snackbar-text);--snackbar-icon-bg: #e5edf8;--snackbar-accent: #0047ba;--snackbar-input-border: var(--snackbar-border-color);--snackbar-progress: var(--snackbar-accent);display:flex;width:26.25rem;padding:1.25rem 1rem;justify-content:space-between;align-items:flex-start;gap:.25rem;position:relative;border-radius:var(--border-radius-md, 4px);border:1px solid var(--snackbar-border-color);background:var(--snackbar-bg);box-shadow:1px 1px 4px #00000040;color:var(--snackbar-text)}.snackbar__left{display:grid;gap:.5rem;flex:1 1 auto}.snackbar__left>.snackbar__title-row~*{margin-left:var(--snackbar-right-gutter, 1.85rem)}.snackbar__title-row{display:flex;align-items:center;gap:.25rem}.snackbar__title{margin:0;font-weight:400;font-size:1.2rem;line-height:1.2;color:var(--snackbar-title-color)}.snackbar__title-icon{display:inline-flex;align-items:center;justify-content:center;width:1.5em;height:1.5em}.snackbar__title-icon.has-icon{border-radius:50%;background:var(--snackbar-icon-bg);color:var(--snackbar-accent)}.snackbar__icon{font-weight:700;font-size:1rem;line-height:1}.snackbar__desc{margin:0;opacity:.9}.snackbar__input{width:100%;max-width:100%;box-sizing:border-box;padding:.5em;border-radius:4px;border:1px solid var(--snackbar-input-border);background:#fff;color:inherit}.snackbar__close{margin-left:.5em;border:0;background:transparent;color:inherit;opacity:.7;font-size:1.5rem;padding:.25rem;line-height:1;cursor:pointer}.snackbar__progress{position:absolute;left:0;right:0;bottom:-1px;height:4px;overflow:hidden;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.snackbar__progress-fill{height:100%;width:0%;background:var(--snackbar-progress);animation:fill var(--snackbar-progress-duration, 4s) linear forwards}@keyframes fill{to{width:100%}}.snackbar.is-default{--snackbar-border-color: var(--colors-border-primary, #d0d0d0);--snackbar-bg: var(--colors-surface-primary, white);--snackbar-text: #141414;--snackbar-title-color: #003995;--snackbar-icon-bg: #e5edf8;--snackbar-accent: #003995;--snackbar-input-border: #d0d0d0;--snackbar-progress: #003995}.snackbar.is-info{--snackbar-border-color: var(--colors-border-information, #457fa6);--snackbar-bg: var(--colors-surface-information, #ecf2f6);--snackbar-text: #24495c;--snackbar-title-color: #24495c;--snackbar-icon-bg: #a2bfd3;--snackbar-accent: #306a88;--snackbar-input-border: #a2bfd3;--snackbar-progress: #306a88}.snackbar.is-success{--snackbar-border-color: var(--colors-border-success, #3ba35a);--snackbar-bg: var(--colors-surface-success, #ebf6ee);--snackbar-text: #20522e;--snackbar-title-color: #20522e;--snackbar-icon-bg: #9dd1ac;--snackbar-accent: #2e7d3f;--snackbar-input-border: #9dd1ac;--snackbar-progress: #2e7d3f}.snackbar.is-warning{--snackbar-border-color: var(--colors-border-warning, #d1c844);--snackbar-bg: var(--colors-surface-warning, #faf9ec);--snackbar-text: #514a18;--snackbar-title-color: #514a18;--snackbar-icon-bg: #e8e3a1;--snackbar-accent: #7a6f13;--snackbar-input-border: #d1c844;--snackbar-progress: #7a6f13}.snackbar.is-error{--snackbar-border-color: var(--colors-border-error, #c73e3d);--snackbar-bg: var(--colors-surface-error, #f9ecec);--snackbar-text: #611a1a;--snackbar-title-color: #611a1a;--snackbar-icon-bg: #e39e9e;--snackbar-accent: #912525;--snackbar-input-border: #c73e3d;--snackbar-progress: #912525}.snackbar{position:fixed;top:24px;right:24px;z-index:1000;transform:translate(120%);transition:transform .6s ease}.snackbar.is-open{transform:translate(0)}lib-status-button{--status-button-padding: .25em .5em .25em 0}\n"] }]
2367
+ }], propDecorators: { purpose: [{
2368
+ type: Input
2369
+ }], title: [{
2370
+ type: Input
2371
+ }], description: [{
2372
+ type: Input
2373
+ }], fieldPlaceholder: [{
2374
+ type: Input
2375
+ }], titleIcon: [{
2376
+ type: Input
2377
+ }], buttonLabel: [{
2378
+ type: Input
2379
+ }], showTitle: [{
2380
+ type: Input,
2381
+ args: [{ transform: booleanAttribute }]
2382
+ }], showTitleIcon: [{
2383
+ type: Input,
2384
+ args: [{ transform: booleanAttribute }]
2385
+ }], showClose: [{
2386
+ type: Input,
2387
+ args: [{ transform: booleanAttribute }]
2388
+ }], showProgressBar: [{
2389
+ type: Input,
2390
+ args: [{ transform: booleanAttribute }]
2391
+ }], showField: [{
2392
+ type: Input,
2393
+ args: [{ transform: booleanAttribute }]
2394
+ }], showButton: [{
2395
+ type: Input,
2396
+ args: [{ transform: booleanAttribute }]
2397
+ }], autoDismiss: [{
2398
+ type: Input,
2399
+ args: [{ transform: booleanAttribute }]
2400
+ }], visible: [{
2401
+ type: Input,
2402
+ args: [{ transform: booleanAttribute }]
2403
+ }], progressMs: [{
2404
+ type: Input
2405
+ }], y: [{
2406
+ type: Input
2407
+ }], closed: [{
2408
+ type: Output
2409
+ }], visibleChange: [{
2410
+ type: Output
2411
+ }] } });
2412
+
2413
+ class SnackbarService {
2414
+ constructor(appRef, env) {
2415
+ this.appRef = appRef;
2416
+ this.env = env;
2417
+ }
2418
+ /**
2419
+ * This open method is what consuming code will use to create a snackbar
2420
+ * @param snackbarOptions interface found above
2421
+ * @param anchor HTML Element, optional. The snackbar's entrance and exit animations will happen on this element's Y axis (px)
2422
+ * @returns void.
2423
+ */
2424
+ open(snackbarOptions = {}, anchor) {
2425
+ const compRef = createComponent(SnackbarComponent, {
2426
+ environmentInjector: this.env,
2427
+ });
2428
+ const desiredY = anchor // could be clamped if above or below viewport
2429
+ ? anchor.getBoundingClientRect().top
2430
+ : snackbarOptions.y ?? 24;
2431
+ Object.assign(compRef.instance, {
2432
+ purpose: 'warning',
2433
+ title: 'Snackbar Title',
2434
+ description: 'Lorem ipsum is the standard dummy text in the design industry',
2435
+ titleIcon: 'info',
2436
+ fieldPlaceholder: 'Placeholder',
2437
+ showTitle: true,
2438
+ showTitleIcon: true,
2439
+ showClose: true,
2440
+ showProgressBar: true,
2441
+ showField: true,
2442
+ showButton: true,
2443
+ progressMs: 4000,
2444
+ autoDismiss: true,
2445
+ y: desiredY,
2446
+ right: 24,
2447
+ zIndex: 10000,
2448
+ visible: true,
2449
+ ...snackbarOptions,
2450
+ });
2451
+ this.appRef.attachView(compRef.hostView);
2452
+ document.body.appendChild(compRef.location.nativeElement);
2453
+ compRef.changeDetectorRef.detectChanges();
2454
+ // Clamp Y after it’s in the DOM
2455
+ const margin = 8;
2456
+ const adjustY = () => {
2457
+ const host = compRef.location.nativeElement.querySelector('section.snackbar') ??
2458
+ compRef.location.nativeElement;
2459
+ const h = host.offsetHeight || 0;
2460
+ const maxTop = Math.max(margin, window.innerHeight - h - margin);
2461
+ const clamped = Math.min(Math.max(desiredY, margin), maxTop);
2462
+ if (compRef.instance.y !== clamped) {
2463
+ compRef.instance.y = clamped;
2464
+ compRef.changeDetectorRef.detectChanges();
2465
+ }
2466
+ };
2467
+ // Measure on next frame (styles applied)
2468
+ const rafId = requestAnimationFrame(adjustY);
2469
+ // re-clamp on resize (in case viewport changes while visible)
2470
+ const onResize = () => adjustY();
2471
+ window.addEventListener('resize', onResize);
2472
+ // Cleanup when closed
2473
+ const sub = compRef.instance.closed.subscribe(() => {
2474
+ sub.unsubscribe();
2475
+ cancelAnimationFrame(rafId);
2476
+ window.removeEventListener('resize', onResize);
2477
+ this.appRef.detachView(compRef.hostView);
2478
+ compRef.destroy();
2479
+ });
2480
+ return {
2481
+ close: () => compRef.instance.close(),
2482
+ };
2483
+ }
2484
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); }
2485
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarService, providedIn: 'root' }); }
2486
+ }
2487
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarService, decorators: [{
2488
+ type: Injectable,
2489
+ args: [{ providedIn: 'root' }]
2490
+ }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
2491
+
2265
2492
  /*
2266
2493
  * Public API Surface of components
2267
2494
  */
@@ -2270,5 +2497,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
2270
2497
  * Generated bundle index. Do not edit.
2271
2498
  */
2272
2499
 
2273
- export { ADVANCED_SEARCH_FIELD_MAP, ADVANCED_SEARCH_OPTIONS, ADVANCED_SEARCH_QUALIFIER_MAP, HbllFooterComponent, HbllHeaderComponent, HbllItemTypeIconPipe, HeaderWithImpersonationComponent, ImpersonateModalComponent, ImpersonateUserPipe, ImpersonationBannerComponent, LIBRARY_HOURS_API_URL, SsSearchBarComponent, StatusButtonComponent, defaultOidcBaseUri, defaultOidcDefaultIdp, getUserStatusFromRoles, isAdvancedSearchExternalFieldOption, isAdvancedSearchFieldOption, isAdvancedSearchLocalFieldOption, isSearchScope };
2500
+ export { ADVANCED_SEARCH_FIELD_MAP, ADVANCED_SEARCH_OPTIONS, ADVANCED_SEARCH_QUALIFIER_MAP, HbllFooterComponent, HbllHeaderComponent, HbllItemTypeIconPipe, HeaderWithImpersonationComponent, ImpersonateModalComponent, ImpersonateUserPipe, ImpersonationBannerComponent, LIBRARY_HOURS_API_URL, SnackbarComponent, SnackbarService, SsSearchBarComponent, StatusButtonComponent, defaultOidcBaseUri, defaultOidcDefaultIdp, getUserStatusFromRoles, isAdvancedSearchExternalFieldOption, isAdvancedSearchFieldOption, isAdvancedSearchLocalFieldOption, isSearchScope };
2274
2501
  //# sourceMappingURL=byuhbll-components.mjs.map