@byuhbll/components 4.3.2 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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,245 @@ 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 }]
2273
+ }] } });
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.showTitle = true;
2290
+ this.showTitleIcon = true;
2291
+ this.titleIconFilled = false;
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 = 5000;
2299
+ this.y = 24;
2300
+ this.closed = new EventEmitter();
2301
+ this.visibleChange = new EventEmitter();
2302
+ this.buttonClicked = new EventEmitter();
2303
+ this.isOpen = false;
2304
+ this.EXIT_MS = 300;
2305
+ }
2306
+ ngOnInit() {
2307
+ if (this.visible) {
2308
+ // enter on next tick
2309
+ setTimeout(() => (this.isOpen = true), 0);
2310
+ this.startDismissTimer();
2311
+ }
2312
+ }
2313
+ ngOnChanges(changes) {
2314
+ if ('visible' in changes) {
2315
+ // when parent toggles visible
2316
+ if (this.visible) {
2317
+ // becoming visible -> open + (re)start timer
2318
+ this.isOpen = false;
2319
+ setTimeout(() => (this.isOpen = true), 0);
2320
+ this.startDismissTimer();
2321
+ }
2322
+ else {
2323
+ // becoming hidden -> stop timers and ensure closed state
2324
+ this.clearDismissTimer();
2325
+ this.isOpen = false;
2326
+ }
2327
+ }
2328
+ }
2329
+ ngOnDestroy() {
2330
+ this.clearDismissTimer();
2331
+ }
2332
+ // used by the × button, done button, and auto-dismiss
2333
+ close(emitButtonClicked = false) {
2334
+ if (!this.isOpen && !this.visible)
2335
+ return;
2336
+ this.clearDismissTimer();
2337
+ this.isOpen = false; // triggers exit transition
2338
+ // after exit animation, hide + notify
2339
+ window.setTimeout(() => {
2340
+ if (this.visible) {
2341
+ this.visible = false;
2342
+ this.visibleChange.emit(false);
2343
+ }
2344
+ if (emitButtonClicked) {
2345
+ this.buttonClicked.emit();
2346
+ }
2347
+ this.closed.emit();
2348
+ }, this.EXIT_MS);
2349
+ }
2350
+ get status() {
2351
+ return purposeToStatusMap[this.purpose];
2352
+ }
2353
+ startDismissTimer() {
2354
+ if (!this.autoDismiss)
2355
+ return;
2356
+ this.clearDismissTimer();
2357
+ this.dismissTimer = window.setTimeout(() => this.close(), this.progressMs);
2358
+ }
2359
+ clearDismissTimer() {
2360
+ if (this.dismissTimer) {
2361
+ clearTimeout(this.dismissTimer);
2362
+ this.dismissTimer = undefined;
2363
+ }
2364
+ }
2365
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2366
+ 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", showTitle: ["showTitle", "showTitle", booleanAttribute], showTitleIcon: ["showTitleIcon", "showTitleIcon", booleanAttribute], titleIconFilled: ["titleIconFilled", "titleIconFilled", 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", statusButtonInputs: "statusButtonInputs" }, outputs: { closed: "closed", visibleChange: "visibleChange", buttonClicked: "buttonClicked" }, 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 [ngClass]=\"titleIconFilled ? 'material-icons' : 'material-icons-outlined'\"\n id=\"snackbar-title-icon\"\n aria-hidden=\"true\"\n >\n {{ titleIcon }}\n </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={{statusButtonInputs?.label}}\n [status]=\"status\"\n leftIcon={{statusButtonInputs?.leftIcon}}\n rightIcon={{statusButtonInputs?.rightIcon}}\n [hideLeftIcon]=\"statusButtonInputs?.hideLeftIcon\"\n [hideRightIcon]=\"statusButtonInputs?.hideRightIcon\"\n [clearVariant]=\"statusButtonInputs?.clearVariant\"\n (click)=\"close(true)\"\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%;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"] }] }); }
2367
+ }
2368
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarComponent, decorators: [{
2369
+ type: Component,
2370
+ 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 [ngClass]=\"titleIconFilled ? 'material-icons' : 'material-icons-outlined'\"\n id=\"snackbar-title-icon\"\n aria-hidden=\"true\"\n >\n {{ titleIcon }}\n </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={{statusButtonInputs?.label}}\n [status]=\"status\"\n leftIcon={{statusButtonInputs?.leftIcon}}\n rightIcon={{statusButtonInputs?.rightIcon}}\n [hideLeftIcon]=\"statusButtonInputs?.hideLeftIcon\"\n [hideRightIcon]=\"statusButtonInputs?.hideRightIcon\"\n [clearVariant]=\"statusButtonInputs?.clearVariant\"\n (click)=\"close(true)\"\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%;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"] }]
2371
+ }], propDecorators: { purpose: [{
2372
+ type: Input
2373
+ }], title: [{
2374
+ type: Input
2375
+ }], description: [{
2376
+ type: Input
2377
+ }], fieldPlaceholder: [{
2378
+ type: Input
2379
+ }], titleIcon: [{
2380
+ type: Input
2381
+ }], showTitle: [{
2382
+ type: Input,
2383
+ args: [{ transform: booleanAttribute }]
2384
+ }], showTitleIcon: [{
2385
+ type: Input,
2386
+ args: [{ transform: booleanAttribute }]
2387
+ }], titleIconFilled: [{
2388
+ type: Input,
2389
+ args: [{ transform: booleanAttribute }]
2390
+ }], showClose: [{
2391
+ type: Input,
2392
+ args: [{ transform: booleanAttribute }]
2393
+ }], showProgressBar: [{
2394
+ type: Input,
2395
+ args: [{ transform: booleanAttribute }]
2396
+ }], showField: [{
2397
+ type: Input,
2398
+ args: [{ transform: booleanAttribute }]
2399
+ }], showButton: [{
2400
+ type: Input,
2401
+ args: [{ transform: booleanAttribute }]
2402
+ }], autoDismiss: [{
2403
+ type: Input,
2404
+ args: [{ transform: booleanAttribute }]
2405
+ }], visible: [{
2406
+ type: Input,
2407
+ args: [{ transform: booleanAttribute }]
2408
+ }], progressMs: [{
2409
+ type: Input
2410
+ }], y: [{
2411
+ type: Input
2412
+ }], statusButtonInputs: [{
2413
+ type: Input
2414
+ }], closed: [{
2415
+ type: Output
2416
+ }], visibleChange: [{
2417
+ type: Output
2418
+ }], buttonClicked: [{
2419
+ type: Output
2263
2420
  }] } });
2264
2421
 
2422
+ class SnackbarService {
2423
+ constructor(appRef, env) {
2424
+ this.appRef = appRef;
2425
+ this.env = env;
2426
+ }
2427
+ /**
2428
+ * This open method is what consuming code will use to create a snackbar
2429
+ * @param snackbarOptions interface
2430
+ * @param anchor HTML Element, optional. The snackbar's entrance and exit animations will happen on this element's Y axis (px)
2431
+ * @returns void.
2432
+ */
2433
+ open(snackbarOptions = {}, anchor) {
2434
+ const statusButtonInputs = {
2435
+ label: 'Done',
2436
+ hideLeftIcon: true,
2437
+ clearVariant: true,
2438
+ };
2439
+ const compRef = createComponent(SnackbarComponent, {
2440
+ environmentInjector: this.env,
2441
+ });
2442
+ const desiredY = anchor // could be clamped if above or below viewport
2443
+ ? anchor.getBoundingClientRect().top
2444
+ : snackbarOptions.y ?? 24;
2445
+ Object.assign(compRef.instance, {
2446
+ purpose: 'warning',
2447
+ title: 'Snackbar Title',
2448
+ description: 'Lorem ipsum is the standard dummy text in the design industry',
2449
+ titleIcon: 'info',
2450
+ fieldPlaceholder: 'Placeholder',
2451
+ showTitle: true,
2452
+ showTitleIcon: true,
2453
+ titleIconFilled: false,
2454
+ showClose: true,
2455
+ showProgressBar: true,
2456
+ showField: true,
2457
+ showButton: true,
2458
+ progressMs: 5000,
2459
+ autoDismiss: true,
2460
+ y: desiredY,
2461
+ right: 24,
2462
+ zIndex: 10000,
2463
+ visible: true,
2464
+ statusButtonInputs,
2465
+ ...snackbarOptions,
2466
+ });
2467
+ this.appRef.attachView(compRef.hostView);
2468
+ document.body.appendChild(compRef.location.nativeElement);
2469
+ compRef.changeDetectorRef.detectChanges();
2470
+ // Clamp Y after it’s in the DOM
2471
+ const margin = 8;
2472
+ const adjustY = () => {
2473
+ const host = compRef.location.nativeElement.querySelector('section.snackbar') ??
2474
+ compRef.location.nativeElement;
2475
+ const h = host.offsetHeight || 0;
2476
+ const maxTop = Math.max(margin, window.innerHeight - h - margin);
2477
+ const clamped = Math.min(Math.max(desiredY, margin), maxTop);
2478
+ if (compRef.instance.y !== clamped) {
2479
+ compRef.instance.y = clamped;
2480
+ compRef.changeDetectorRef.detectChanges();
2481
+ }
2482
+ };
2483
+ // Measure on next frame (styles applied)
2484
+ const rafId = requestAnimationFrame(adjustY);
2485
+ // re-clamp on resize (in case viewport changes while visible)
2486
+ const onResize = () => adjustY();
2487
+ window.addEventListener('resize', onResize);
2488
+ // Cleanup when closed
2489
+ const sub = compRef.instance.closed.subscribe(() => {
2490
+ sub.unsubscribe();
2491
+ cancelAnimationFrame(rafId);
2492
+ window.removeEventListener('resize', onResize);
2493
+ this.appRef.detachView(compRef.hostView);
2494
+ compRef.destroy();
2495
+ });
2496
+ return {
2497
+ close: () => compRef.instance.close(),
2498
+ buttonClicked: compRef.instance.buttonClicked,
2499
+ };
2500
+ }
2501
+ 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 }); }
2502
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarService, providedIn: 'root' }); }
2503
+ }
2504
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: SnackbarService, decorators: [{
2505
+ type: Injectable,
2506
+ args: [{ providedIn: 'root' }]
2507
+ }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
2508
+
2265
2509
  /*
2266
2510
  * Public API Surface of components
2267
2511
  */
@@ -2270,5 +2514,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
2270
2514
  * Generated bundle index. Do not edit.
2271
2515
  */
2272
2516
 
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 };
2517
+ 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
2518
  //# sourceMappingURL=byuhbll-components.mjs.map