@byuhbll/components 5.1.0-beta.2 → 5.1.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,39 @@
1
+ import { Component, Input, Output, EventEmitter } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import * as i0 from "@angular/core";
4
+ export class ButtonGroupItemComponent {
5
+ constructor() {
6
+ this.disabled = false;
7
+ this.buttonClick = new EventEmitter();
8
+ // Set by parent button group after content projection
9
+ this.isActive = false;
10
+ }
11
+ /**
12
+ * Handles the button click event and emits the button's ID to the parent component.
13
+ */
14
+ onClick() {
15
+ this.buttonClick.emit(this.id);
16
+ }
17
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonGroupItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: ButtonGroupItemComponent, isStandalone: true, selector: "lib-button-group-item", inputs: { id: "id", title: "title", icon: "icon", ariaLabel: "ariaLabel", disabled: "disabled", position: "position" }, outputs: { buttonClick: "buttonClick" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"tab-btn\"\n [class.first]=\"position === 'first'\"\n [class.last]=\"position === 'last'\"\n [class.active]=\"isActive\"\n [disabled]=\"disabled\"\n (click)=\"onClick()\"\n role=\"tab\"\n [attr.aria-pressed]=\"isActive\"\n [attr.aria-label]=\"ariaLabel ? ariaLabel : null\"\n [attr.tabindex]=\"disabled ? -1 : 0\"\n>\n @if (icon) {\n <span class=\"icon material-symbols-outlined\">{{ icon }}</span>\n }\n\n @if (title) {\n <span class=\"button-title\">{{ title }}</span>\n }\n</button>\n", styles: [".tab-btn{padding:.5rem 1rem;font-size:1rem;font-weight:400;line-height:1.5rem;color:#00245d;background-color:#fff;cursor:pointer;position:relative;border:.0625rem solid #d0d0d0;border-left:none;border-radius:0;transition:all .2s ease;display:inline-flex;align-items:center;justify-content:center;height:2.5rem}.tab-btn:not(:disabled):hover{background-color:#e5edf8}.tab-btn.active{background-color:#0047ba;color:#fff;z-index:2}.tab-btn.active:not(:disabled):hover{background-color:#003995}.tab-btn:focus-visible{outline:.125rem solid #b967c7;outline-offset:.125rem;z-index:3}.tab-btn:disabled{cursor:not-allowed;color:#767676;background-color:#e7e7e7;border-color:#767676}.tab-btn .icon{display:flex;align-items:center;justify-content:center}.tab-btn .icon img{height:1.5rem;width:auto}.tab-btn .button-title{flex-shrink:0}.tab-btn.first{border-radius:.25rem 0 0 .25rem;border-left:.0625rem solid #d0d0d0}.tab-btn.first:disabled{border-left:.0625rem solid #767676}.tab-btn.last{border-radius:0 .25rem .25rem 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
19
+ }
20
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonGroupItemComponent, decorators: [{
21
+ type: Component,
22
+ args: [{ selector: 'lib-button-group-item', standalone: true, imports: [CommonModule], template: "<button\n type=\"button\"\n class=\"tab-btn\"\n [class.first]=\"position === 'first'\"\n [class.last]=\"position === 'last'\"\n [class.active]=\"isActive\"\n [disabled]=\"disabled\"\n (click)=\"onClick()\"\n role=\"tab\"\n [attr.aria-pressed]=\"isActive\"\n [attr.aria-label]=\"ariaLabel ? ariaLabel : null\"\n [attr.tabindex]=\"disabled ? -1 : 0\"\n>\n @if (icon) {\n <span class=\"icon material-symbols-outlined\">{{ icon }}</span>\n }\n\n @if (title) {\n <span class=\"button-title\">{{ title }}</span>\n }\n</button>\n", styles: [".tab-btn{padding:.5rem 1rem;font-size:1rem;font-weight:400;line-height:1.5rem;color:#00245d;background-color:#fff;cursor:pointer;position:relative;border:.0625rem solid #d0d0d0;border-left:none;border-radius:0;transition:all .2s ease;display:inline-flex;align-items:center;justify-content:center;height:2.5rem}.tab-btn:not(:disabled):hover{background-color:#e5edf8}.tab-btn.active{background-color:#0047ba;color:#fff;z-index:2}.tab-btn.active:not(:disabled):hover{background-color:#003995}.tab-btn:focus-visible{outline:.125rem solid #b967c7;outline-offset:.125rem;z-index:3}.tab-btn:disabled{cursor:not-allowed;color:#767676;background-color:#e7e7e7;border-color:#767676}.tab-btn .icon{display:flex;align-items:center;justify-content:center}.tab-btn .icon img{height:1.5rem;width:auto}.tab-btn .button-title{flex-shrink:0}.tab-btn.first{border-radius:.25rem 0 0 .25rem;border-left:.0625rem solid #d0d0d0}.tab-btn.first:disabled{border-left:.0625rem solid #767676}.tab-btn.last{border-radius:0 .25rem .25rem 0}\n"] }]
23
+ }], propDecorators: { id: [{
24
+ type: Input,
25
+ args: [{ required: true }]
26
+ }], title: [{
27
+ type: Input
28
+ }], icon: [{
29
+ type: Input
30
+ }], ariaLabel: [{
31
+ type: Input
32
+ }], disabled: [{
33
+ type: Input
34
+ }], position: [{
35
+ type: Input
36
+ }], buttonClick: [{
37
+ type: Output
38
+ }] } });
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnV0dG9uLWdyb3VwLWl0ZW0uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29tcG9uZW50cy9zcmMvbGliL3N1YmF0b21pYy1jb21wb25lbnRzL2J1dHRvbi1ncm91cC1pdGVtL2J1dHRvbi1ncm91cC1pdGVtLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbXBvbmVudHMvc3JjL2xpYi9zdWJhdG9taWMtY29tcG9uZW50cy9idXR0b24tZ3JvdXAtaXRlbS9idXR0b24tZ3JvdXAtaXRlbS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7QUFTL0MsTUFBTSxPQUFPLHdCQUF3QjtJQVByQztRQVlhLGFBQVEsR0FBWSxLQUFLLENBQUM7UUFFekIsZ0JBQVcsR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO1FBQ25ELHNEQUFzRDtRQUMvQyxhQUFRLEdBQVksS0FBSyxDQUFDO0tBUXBDO0lBTkc7O09BRUc7SUFDSCxPQUFPO1FBQ0gsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ25DLENBQUM7OEdBaEJRLHdCQUF3QjtrR0FBeEIsd0JBQXdCLGtQQ1ZyQyx1a0JBcUJBLDZpQ0RmYyxZQUFZOzsyRkFJYix3QkFBd0I7a0JBUHBDLFNBQVM7K0JBQ0ksdUJBQXVCLGNBQ3JCLElBQUksV0FDUCxDQUFDLFlBQVksQ0FBQzs4QkFLSSxFQUFFO3NCQUE1QixLQUFLO3VCQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtnQkFDaEIsS0FBSztzQkFBYixLQUFLO2dCQUNHLElBQUk7c0JBQVosS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDSSxXQUFXO3NCQUFwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnbGliLWJ1dHRvbi1ncm91cC1pdGVtJyxcbiAgICBzdGFuZGFsb25lOiB0cnVlLFxuICAgIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9idXR0b24tZ3JvdXAtaXRlbS5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmw6ICcuL2J1dHRvbi1ncm91cC1pdGVtLmNvbXBvbmVudC5zY3NzJyxcbn0pXG5leHBvcnQgY2xhc3MgQnV0dG9uR3JvdXBJdGVtQ29tcG9uZW50IHtcbiAgICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KSBpZCE6IHN0cmluZztcbiAgICBASW5wdXQoKSB0aXRsZT86IHN0cmluZztcbiAgICBASW5wdXQoKSBpY29uPzogc3RyaW5nO1xuICAgIEBJbnB1dCgpIGFyaWFMYWJlbD86IHN0cmluZztcbiAgICBASW5wdXQoKSBkaXNhYmxlZDogYm9vbGVhbiA9IGZhbHNlO1xuICAgIEBJbnB1dCgpIHBvc2l0aW9uPzogJ2ZpcnN0JyB8ICdsYXN0JyB8ICdtaWRkbGUnO1xuICAgIEBPdXRwdXQoKSBidXR0b25DbGljayA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAgIC8vIFNldCBieSBwYXJlbnQgYnV0dG9uIGdyb3VwIGFmdGVyIGNvbnRlbnQgcHJvamVjdGlvblxuICAgIHB1YmxpYyBpc0FjdGl2ZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB0aGUgYnV0dG9uIGNsaWNrIGV2ZW50IGFuZCBlbWl0cyB0aGUgYnV0dG9uJ3MgSUQgdG8gdGhlIHBhcmVudCBjb21wb25lbnQuXG4gICAgICovXG4gICAgb25DbGljaygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5idXR0b25DbGljay5lbWl0KHRoaXMuaWQpO1xuICAgIH1cbn1cbiIsIjxidXR0b25cbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICBjbGFzcz1cInRhYi1idG5cIlxuICAgIFtjbGFzcy5maXJzdF09XCJwb3NpdGlvbiA9PT0gJ2ZpcnN0J1wiXG4gICAgW2NsYXNzLmxhc3RdPVwicG9zaXRpb24gPT09ICdsYXN0J1wiXG4gICAgW2NsYXNzLmFjdGl2ZV09XCJpc0FjdGl2ZVwiXG4gICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCJcbiAgICAoY2xpY2spPVwib25DbGljaygpXCJcbiAgICByb2xlPVwidGFiXCJcbiAgICBbYXR0ci5hcmlhLXByZXNzZWRdPVwiaXNBY3RpdmVcIlxuICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsID8gYXJpYUxhYmVsIDogbnVsbFwiXG4gICAgW2F0dHIudGFiaW5kZXhdPVwiZGlzYWJsZWQgPyAtMSA6IDBcIlxuPlxuICAgIEBpZiAoaWNvbikge1xuICAgICAgICA8c3BhbiBjbGFzcz1cImljb24gbWF0ZXJpYWwtc3ltYm9scy1vdXRsaW5lZFwiPnt7IGljb24gfX08L3NwYW4+XG4gICAgfVxuXG4gICAgQGlmICh0aXRsZSkge1xuICAgICAgICA8c3BhbiBjbGFzcz1cImJ1dHRvbi10aXRsZVwiPnt7IHRpdGxlIH19PC9zcGFuPlxuICAgIH1cbjwvYnV0dG9uPlxuIl19
@@ -16,4 +16,7 @@ export * from './lib/snackbar/snackbar.component';
16
16
  export { getUserStatusFromRoles } from './lib/contact-utils';
17
17
  export { ADVANCED_SEARCH_QUALIFIER_MAP, ADVANCED_SEARCH_FIELD_MAP, ADVANCED_SEARCH_OPTIONS, } from './lib/ss-search-bar/constants';
18
18
  export * from './lib/status-button/status-button.component';
19
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2NvbXBvbmVudHMvc3JjL3B1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLHlDQUF5QyxDQUFDO0FBQ3hELGNBQWMsc0NBQXNDLENBQUM7QUFDckQsY0FBYyx5Q0FBeUMsQ0FBQztBQUN4RCxjQUFjLHFFQUFxRSxDQUFDO0FBQ3BGLGNBQWMscURBQXFELENBQUM7QUFDcEUsY0FBYywyREFBMkQsQ0FBQztBQUMxRSxjQUFjLDZDQUE2QyxDQUFDO0FBQzVELGNBQWMsa0RBQWtELENBQUM7QUFDakUsY0FBYywrQ0FBK0MsQ0FBQztBQUM5RCxjQUFjLGdEQUFnRCxDQUFDO0FBQy9ELGNBQWMsaUNBQWlDLENBQUM7QUFDaEQsY0FBYyxtQ0FBbUMsQ0FBQztBQUNsRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUM3RCxPQUFPLEVBQ0gsNkJBQTZCLEVBQzdCLHlCQUF5QixFQUN6Qix1QkFBdUIsR0FDMUIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2QyxjQUFjLDZDQUE2QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBjb21wb25lbnRzXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvaGJsbC1oZWFkZXIvaGJsbC1oZWFkZXIuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3BpcGVzL2hibGwtaXRlbS10eXBlLWljb24ucGlwZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9oYmxsLWZvb3Rlci9oYmxsLWZvb3Rlci5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvaGVhZGVyLXdpdGgtaW1wZXJzb25hdGlvbi9oZWFkZXItd2l0aC1pbXBlcnNvbmF0aW9uLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9pbXBlcnNvbmF0ZS1tb2RhbC9pbXBlcnNvbmF0ZS1tb2RhbC5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvaW1wZXJzb25hdGlvbi1iYW5uZXIvaW1wZXJzb25hdGlvbi1iYW5uZXIuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NzLXNlYXJjaC1iYXIvc3Mtc2VhcmNoLWJhci5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc3Mtc2VhcmNoLWJhci9tb2RlbHMvYWR2YW5jZWQtc2VhcmNoLm1vZGVsJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NzLXNlYXJjaC1iYXIvbW9kZWxzL3NlYXJjaC1zY29wZS5tb2RlbCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9zcy1zZWFyY2gtYmFyL21vZGVscy9zZWFyY2gtY29uZmlnLm1vZGVsJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NuYWNrYmFyL3NuYWNrYmFyLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc25hY2tiYXIvc25hY2tiYXIuY29tcG9uZW50JztcbmV4cG9ydCB7IGdldFVzZXJTdGF0dXNGcm9tUm9sZXMgfSBmcm9tICcuL2xpYi9jb250YWN0LXV0aWxzJztcbmV4cG9ydCB7XG4gICAgQURWQU5DRURfU0VBUkNIX1FVQUxJRklFUl9NQVAsXG4gICAgQURWQU5DRURfU0VBUkNIX0ZJRUxEX01BUCxcbiAgICBBRFZBTkNFRF9TRUFSQ0hfT1BUSU9OUyxcbn0gZnJvbSAnLi9saWIvc3Mtc2VhcmNoLWJhci9jb25zdGFudHMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc3RhdHVzLWJ1dHRvbi9zdGF0dXMtYnV0dG9uLmNvbXBvbmVudCc7XG4iXX0=
19
+ export * from './lib/button/button.component';
20
+ export * from './lib/button-group/button-group.component';
21
+ export * from './lib/subatomic-components/button-group-item/button-group-item.component';
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2NvbXBvbmVudHMvc3JjL3B1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLHlDQUF5QyxDQUFDO0FBQ3hELGNBQWMsc0NBQXNDLENBQUM7QUFDckQsY0FBYyx5Q0FBeUMsQ0FBQztBQUN4RCxjQUFjLHFFQUFxRSxDQUFDO0FBQ3BGLGNBQWMscURBQXFELENBQUM7QUFDcEUsY0FBYywyREFBMkQsQ0FBQztBQUMxRSxjQUFjLDZDQUE2QyxDQUFDO0FBQzVELGNBQWMsa0RBQWtELENBQUM7QUFDakUsY0FBYywrQ0FBK0MsQ0FBQztBQUM5RCxjQUFjLGdEQUFnRCxDQUFDO0FBQy9ELGNBQWMsaUNBQWlDLENBQUM7QUFDaEQsY0FBYyxtQ0FBbUMsQ0FBQztBQUNsRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUM3RCxPQUFPLEVBQ0gsNkJBQTZCLEVBQzdCLHlCQUF5QixFQUN6Qix1QkFBdUIsR0FDMUIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2QyxjQUFjLDZDQUE2QyxDQUFDO0FBQzVELGNBQWMsK0JBQStCLENBQUM7QUFDOUMsY0FBYywyQ0FBMkMsQ0FBQztBQUMxRCxjQUFjLDBFQUEwRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBjb21wb25lbnRzXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvaGJsbC1oZWFkZXIvaGJsbC1oZWFkZXIuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3BpcGVzL2hibGwtaXRlbS10eXBlLWljb24ucGlwZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9oYmxsLWZvb3Rlci9oYmxsLWZvb3Rlci5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvaGVhZGVyLXdpdGgtaW1wZXJzb25hdGlvbi9oZWFkZXItd2l0aC1pbXBlcnNvbmF0aW9uLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9pbXBlcnNvbmF0ZS1tb2RhbC9pbXBlcnNvbmF0ZS1tb2RhbC5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvaW1wZXJzb25hdGlvbi1iYW5uZXIvaW1wZXJzb25hdGlvbi1iYW5uZXIuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NzLXNlYXJjaC1iYXIvc3Mtc2VhcmNoLWJhci5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc3Mtc2VhcmNoLWJhci9tb2RlbHMvYWR2YW5jZWQtc2VhcmNoLm1vZGVsJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NzLXNlYXJjaC1iYXIvbW9kZWxzL3NlYXJjaC1zY29wZS5tb2RlbCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9zcy1zZWFyY2gtYmFyL21vZGVscy9zZWFyY2gtY29uZmlnLm1vZGVsJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3NuYWNrYmFyL3NuYWNrYmFyLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc25hY2tiYXIvc25hY2tiYXIuY29tcG9uZW50JztcbmV4cG9ydCB7IGdldFVzZXJTdGF0dXNGcm9tUm9sZXMgfSBmcm9tICcuL2xpYi9jb250YWN0LXV0aWxzJztcbmV4cG9ydCB7XG4gICAgQURWQU5DRURfU0VBUkNIX1FVQUxJRklFUl9NQVAsXG4gICAgQURWQU5DRURfU0VBUkNIX0ZJRUxEX01BUCxcbiAgICBBRFZBTkNFRF9TRUFSQ0hfT1BUSU9OUyxcbn0gZnJvbSAnLi9saWIvc3Mtc2VhcmNoLWJhci9jb25zdGFudHMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc3RhdHVzLWJ1dHRvbi9zdGF0dXMtYnV0dG9uLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9idXR0b24vYnV0dG9uLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9idXR0b24tZ3JvdXAvYnV0dG9uLWdyb3VwLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9zdWJhdG9taWMtY29tcG9uZW50cy9idXR0b24tZ3JvdXAtaXRlbS9idXR0b24tZ3JvdXAtaXRlbS5jb21wb25lbnQnO1xuIl19
@@ -3,7 +3,7 @@ import { CommonModule, DatePipe, DOCUMENT, LowerCasePipe, NgIf, NgClass } from '
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, createComponent, Injectable } from '@angular/core';
6
+ import { Component, ChangeDetectionStrategy, ViewChild, Input, input, EventEmitter, Output, inject, computed, ViewChildren, Pipe, Renderer2, viewChild, HostListener, ElementRef, Injector, runInInjectionContext, effect, ViewEncapsulation, booleanAttribute, createComponent, Injectable, signal, ContentChildren } 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';
@@ -1104,7 +1104,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
1104
1104
  }] } });
1105
1105
 
1106
1106
  const defaultOidcBaseUri = 'https://keycloak.lib.byu.edu/';
1107
- const defaultOidcDefaultIdp = 'byu-realm';
1107
+ const defaultOidcDefaultIdp = 'ces';
1108
1108
  class ImpersonateUserPipe {
1109
1109
  transform(user) {
1110
1110
  return `${user.name} (${user.netId || 'Unknown'})${user.restricted ? ' — Restricted' : ''}`;
@@ -1302,6 +1302,93 @@ class HeaderWithImpersonationComponent {
1302
1302
  : false);
1303
1303
  this.showImpersonationModal = false;
1304
1304
  this.isImpersonating = computed(() => !!this.parsedToken()?.['impersonator']);
1305
+ // Inactivity timeout for impersonation
1306
+ this.activityEvents = [
1307
+ 'keydown',
1308
+ 'pointerdown',
1309
+ 'wheel',
1310
+ 'scroll',
1311
+ ];
1312
+ this.inactivityTimerId = null;
1313
+ this.inactivityTimeoutMs = 5 * 60 * 1000; // 5 minutes
1314
+ this.debounceTimerId = null;
1315
+ this.debounceDelayMs = 250;
1316
+ this.trackingActive = false;
1317
+ this.injector = inject(Injector);
1318
+ /** Reset the inactivity countdown (no-op if not impersonating) */
1319
+ this.resetInactivityTimer = () => {
1320
+ if (!this.isImpersonating())
1321
+ return;
1322
+ if (this.inactivityTimerId)
1323
+ clearTimeout(this.inactivityTimerId);
1324
+ this.inactivityTimerId = window.setTimeout(() => {
1325
+ this.endImpersonation.emit();
1326
+ this.stopInactivityTracking();
1327
+ }, this.inactivityTimeoutMs);
1328
+ };
1329
+ /** Debounce activity to avoid hammering resets during event storms */
1330
+ this.debouncedResetTimer = () => {
1331
+ if (this.debounceTimerId)
1332
+ clearTimeout(this.debounceTimerId);
1333
+ this.debounceTimerId = window.setTimeout(() => {
1334
+ this.resetInactivityTimer();
1335
+ }, this.debounceDelayMs);
1336
+ };
1337
+ }
1338
+ ngOnInit() {
1339
+ // effect can only be used within an injection context (ex: constructor)
1340
+ runInInjectionContext(this.injector, () => {
1341
+ effect(() => {
1342
+ const impersonating = this.isImpersonating();
1343
+ const token = this.parsedToken();
1344
+ // when token refreshes after 5 minutes, it leaves a small moment where there is no token
1345
+ // this prevents dropping inactivtiy timer during that blip
1346
+ if (!token)
1347
+ return;
1348
+ if (impersonating) {
1349
+ if (!this.trackingActive)
1350
+ this.startInactivityTracking();
1351
+ }
1352
+ else {
1353
+ if (this.trackingActive)
1354
+ this.stopInactivityTracking();
1355
+ }
1356
+ });
1357
+ });
1358
+ }
1359
+ ngOnDestroy() {
1360
+ this.stopInactivityTracking();
1361
+ }
1362
+ /** Begin listening and start countdown */
1363
+ startInactivityTracking() {
1364
+ this.activityEvents.forEach((event) => {
1365
+ // 'scroll' on document doesn't bubble; use window + capture to catch nested scrolls
1366
+ const target = event === 'scroll' ? window : document;
1367
+ const options = event === 'scroll'
1368
+ ? { passive: true, capture: true }
1369
+ : { passive: true };
1370
+ target.addEventListener(event, this.debouncedResetTimer, options);
1371
+ });
1372
+ this.trackingActive = true;
1373
+ this.resetInactivityTimer();
1374
+ }
1375
+ /** Remove listeners and clear timers */
1376
+ stopInactivityTracking() {
1377
+ this.activityEvents.forEach((event) => {
1378
+ const target = event === 'scroll' ? window : document;
1379
+ // IMPORTANT: capture must match how it was added for scroll
1380
+ const options = event === 'scroll' ? { capture: true } : undefined;
1381
+ target.removeEventListener(event, this.debouncedResetTimer, options);
1382
+ });
1383
+ if (this.inactivityTimerId) {
1384
+ clearTimeout(this.inactivityTimerId);
1385
+ this.inactivityTimerId = null;
1386
+ }
1387
+ if (this.debounceTimerId) {
1388
+ clearTimeout(this.debounceTimerId);
1389
+ this.debounceTimerId = null;
1390
+ }
1391
+ this.trackingActive = false;
1305
1392
  }
1306
1393
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: HeaderWithImpersonationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1307
1394
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.1.0", type: HeaderWithImpersonationComponent, isStandalone: true, selector: "lib-header-with-impersonation", inputs: { accessTokenPayload: { classPropertyName: "accessTokenPayload", publicName: "accessTokenPayload", isSignal: true, isRequired: true, transformFunction: null }, oidcBaseUri: { classPropertyName: "oidcBaseUri", publicName: "oidcBaseUri", isSignal: true, isRequired: false, transformFunction: null }, oidcDefaultIdp: { classPropertyName: "oidcDefaultIdp", publicName: "oidcDefaultIdp", isSignal: true, isRequired: false, transformFunction: null }, mainSiteBaseUrl: { classPropertyName: "mainSiteBaseUrl", publicName: "mainSiteBaseUrl", isSignal: true, isRequired: false, transformFunction: null }, personBaseUri: { classPropertyName: "personBaseUri", publicName: "personBaseUri", isSignal: true, isRequired: false, transformFunction: null }, myAccountApiBaseUri: { classPropertyName: "myAccountApiBaseUri", publicName: "myAccountApiBaseUri", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { login: "login", logout: "logout", endImpersonation: "endImpersonation" }, ngImport: i0, template: "<lib-impersonation-banner\n [accessTokenPayload]=\"accessTokenPayload()\"\n (endImpersonation)=\"endImpersonation.emit()\"\n [personBaseUri]=\"personBaseUri()\"\n [myAccountApiBaseUri]=\"myAccountApiBaseUri()\"\n></lib-impersonation-banner>\n<lib-hbll-header\n [name]=\"name()\"\n [showImpersonateButton]=\"showImpersonateButton()\"\n (openImpersonationModal)=\"showImpersonationModal = true\"\n (login)=\"login.emit()\"\n (logout)=\"logout.emit()\"\n [mainsitebaseurl]=\"mainSiteBaseUrl()\"\n/>\n<lib-impersonate-modal\n [showModal]=\"showImpersonationModal\"\n [oidcBaseUri]=\"oidcBaseUri()\"\n [oidcDefaultIdp]=\"oidcDefaultIdp()\"\n [accessTokenPayload]=\"accessTokenPayload()\"\n (dismiss)=\"showImpersonationModal = false\"\n (init)=\"showImpersonationModal = true\"\n></lib-impersonate-modal>\n", styles: [""], dependencies: [{ kind: "component", type: HbllHeaderComponent, selector: "lib-hbll-header", inputs: ["name", "mainsitebaseurl", "showImpersonateButton"], outputs: ["openImpersonationModal", "login", "logout"] }, { kind: "component", type: ImpersonationBannerComponent, selector: "lib-impersonation-banner", inputs: ["accessTokenPayload", "personBaseUri", "myAccountApiBaseUri"], outputs: ["endImpersonation"] }, { kind: "component", type: ImpersonateModalComponent, selector: "lib-impersonate-modal", inputs: ["showModal", "oidcBaseUri", "oidcDefaultIdp", "accessTokenPayload"], outputs: ["dismiss", "init"] }] }); }
@@ -2622,6 +2709,271 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
2622
2709
  args: [{ providedIn: 'root' }]
2623
2710
  }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
2624
2711
 
2712
+ /**
2713
+ * A flexible, reusable button component that supports multiple button types
2714
+ * and various content combinations (icon before, title, icon after).
2715
+ *
2716
+ * @example
2717
+ * ```html
2718
+ * <!-- Primary button with icon and title -->
2719
+ * <lib-button
2720
+ * buttonType="primary"
2721
+ * title="Copy Citation"
2722
+ * iconBefore="content_copy"
2723
+ * (buttonClick)="copyCitation()">
2724
+ * </lib-button>
2725
+ *
2726
+ * <!-- Secondary button with title only -->
2727
+ * <lib-button
2728
+ * buttonType="secondary"
2729
+ * title="Cancel"
2730
+ * (buttonClick)="cancelAction()">
2731
+ * </lib-button>
2732
+ *
2733
+ * <!-- Transparent button with icon after title -->
2734
+ * <lib-button
2735
+ * buttonType="transparent"
2736
+ * title="Download"
2737
+ * iconAfter="download"
2738
+ * (buttonClick)="downloadFile()">
2739
+ * </lib-button>
2740
+ *
2741
+ * <!-- Thin button -->
2742
+ * <lib-button
2743
+ * buttonType="primary"
2744
+ * title="Submit"
2745
+ * [isThin]="true"
2746
+ * (buttonClick)="submitForm()">
2747
+ * </lib-button>
2748
+ * ```
2749
+ */
2750
+ class ButtonComponent {
2751
+ constructor() {
2752
+ this.buttonType = 'primary';
2753
+ this.disabled = false;
2754
+ this.isThin = false;
2755
+ this.buttonClick = new EventEmitter();
2756
+ }
2757
+ /**
2758
+ * Handles button click events and emits the buttonClick event if the button is not disabled.
2759
+ */
2760
+ onButtonClick() {
2761
+ if (!this.disabled) {
2762
+ this.buttonClick.emit();
2763
+ }
2764
+ }
2765
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2766
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: ButtonComponent, isStandalone: true, selector: "lib-button", inputs: { buttonType: "buttonType", title: "title", iconBefore: "iconBefore", iconAfter: "iconAfter", disabled: "disabled", isThin: "isThin", ariaLabel: "ariaLabel" }, outputs: { buttonClick: "buttonClick" }, ngImport: i0, template: "<button\n type=\"button\"\n [class]=\"'btn btn-' + buttonType + (isThin ? ' btn-thin' : '') + (title ? '' : ' btn-icon-only')\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel ? ariaLabel : null\"\n (click)=\"onButtonClick()\"\n [attr.tabindex]=\"disabled ? -1 : 0\"\n>\n @if (iconBefore) {\n <span class=\"icon material-symbols-outlined\" [ngClass]=\"{ 'icon-before': title }\">{{ iconBefore }}</span>\n }\n\n @if (title) {\n <span class=\"button-title\">{{ title }}</span>\n }\n\n @if (iconAfter) {\n <span class=\"icon icon-after material-symbols-outlined\">{{ iconAfter }}</span>\n }\n</button>\n", styles: [".btn{padding:.75rem 1.5rem;border-radius:.25rem;font-size:1rem;font-weight:600;cursor:pointer;transition:all .2s ease;border:none;display:inline-flex;align-items:center;outline:none;line-height:1.5rem}.btn.btn-thin{padding:.25rem 2.25rem;border-radius:.5rem;font-weight:400}.btn.btn-thin .icon img{height:1.25rem}.btn:disabled{cursor:not-allowed;color:#767676}.btn:disabled:not(.btn-transparent){background-color:#e7e7e7;border:.0625rem solid #767676}.btn:focus-visible{outline:.125rem solid #b967c7;outline-offset:.125rem}.btn .icon{display:flex;align-items:center;justify-content:center}.btn .icon img{height:1.5rem;width:auto}.btn .icon.icon-before{margin-right:.25rem}.btn .icon.icon-after{margin-left:.25rem}.btn .button-title{flex-shrink:0}.btn-icon-only{padding:.75rem}.btn-primary{background-color:#0047ba;color:#fff;border:.0625rem solid #0047ba}.btn-primary:hover:not(:disabled){background-color:#003995}.btn-secondary{background-color:#fff;color:#00245d;border:.0625rem solid #0047ba}.btn-secondary:hover:not(:disabled){background-color:#e5edf8}.btn-transparent{background-color:transparent;color:#00245d}.btn-transparent:hover:not(:disabled){background-color:#e5edf8}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
2767
+ }
2768
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonComponent, decorators: [{
2769
+ type: Component,
2770
+ args: [{ selector: 'lib-button', standalone: true, imports: [CommonModule], template: "<button\n type=\"button\"\n [class]=\"'btn btn-' + buttonType + (isThin ? ' btn-thin' : '') + (title ? '' : ' btn-icon-only')\"\n [disabled]=\"disabled\"\n [attr.aria-label]=\"ariaLabel ? ariaLabel : null\"\n (click)=\"onButtonClick()\"\n [attr.tabindex]=\"disabled ? -1 : 0\"\n>\n @if (iconBefore) {\n <span class=\"icon material-symbols-outlined\" [ngClass]=\"{ 'icon-before': title }\">{{ iconBefore }}</span>\n }\n\n @if (title) {\n <span class=\"button-title\">{{ title }}</span>\n }\n\n @if (iconAfter) {\n <span class=\"icon icon-after material-symbols-outlined\">{{ iconAfter }}</span>\n }\n</button>\n", styles: [".btn{padding:.75rem 1.5rem;border-radius:.25rem;font-size:1rem;font-weight:600;cursor:pointer;transition:all .2s ease;border:none;display:inline-flex;align-items:center;outline:none;line-height:1.5rem}.btn.btn-thin{padding:.25rem 2.25rem;border-radius:.5rem;font-weight:400}.btn.btn-thin .icon img{height:1.25rem}.btn:disabled{cursor:not-allowed;color:#767676}.btn:disabled:not(.btn-transparent){background-color:#e7e7e7;border:.0625rem solid #767676}.btn:focus-visible{outline:.125rem solid #b967c7;outline-offset:.125rem}.btn .icon{display:flex;align-items:center;justify-content:center}.btn .icon img{height:1.5rem;width:auto}.btn .icon.icon-before{margin-right:.25rem}.btn .icon.icon-after{margin-left:.25rem}.btn .button-title{flex-shrink:0}.btn-icon-only{padding:.75rem}.btn-primary{background-color:#0047ba;color:#fff;border:.0625rem solid #0047ba}.btn-primary:hover:not(:disabled){background-color:#003995}.btn-secondary{background-color:#fff;color:#00245d;border:.0625rem solid #0047ba}.btn-secondary:hover:not(:disabled){background-color:#e5edf8}.btn-transparent{background-color:transparent;color:#00245d}.btn-transparent:hover:not(:disabled){background-color:#e5edf8}\n"] }]
2771
+ }], propDecorators: { buttonType: [{
2772
+ type: Input
2773
+ }], title: [{
2774
+ type: Input
2775
+ }], iconBefore: [{
2776
+ type: Input
2777
+ }], iconAfter: [{
2778
+ type: Input
2779
+ }], disabled: [{
2780
+ type: Input
2781
+ }], isThin: [{
2782
+ type: Input
2783
+ }], ariaLabel: [{
2784
+ type: Input
2785
+ }], buttonClick: [{
2786
+ type: Output
2787
+ }] } });
2788
+
2789
+ class ButtonGroupItemComponent {
2790
+ constructor() {
2791
+ this.disabled = false;
2792
+ this.buttonClick = new EventEmitter();
2793
+ // Set by parent button group after content projection
2794
+ this.isActive = false;
2795
+ }
2796
+ /**
2797
+ * Handles the button click event and emits the button's ID to the parent component.
2798
+ */
2799
+ onClick() {
2800
+ this.buttonClick.emit(this.id);
2801
+ }
2802
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonGroupItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2803
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.1.0", type: ButtonGroupItemComponent, isStandalone: true, selector: "lib-button-group-item", inputs: { id: "id", title: "title", icon: "icon", ariaLabel: "ariaLabel", disabled: "disabled", position: "position" }, outputs: { buttonClick: "buttonClick" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"tab-btn\"\n [class.first]=\"position === 'first'\"\n [class.last]=\"position === 'last'\"\n [class.active]=\"isActive\"\n [disabled]=\"disabled\"\n (click)=\"onClick()\"\n role=\"tab\"\n [attr.aria-pressed]=\"isActive\"\n [attr.aria-label]=\"ariaLabel ? ariaLabel : null\"\n [attr.tabindex]=\"disabled ? -1 : 0\"\n>\n @if (icon) {\n <span class=\"icon material-symbols-outlined\">{{ icon }}</span>\n }\n\n @if (title) {\n <span class=\"button-title\">{{ title }}</span>\n }\n</button>\n", styles: [".tab-btn{padding:.5rem 1rem;font-size:1rem;font-weight:400;line-height:1.5rem;color:#00245d;background-color:#fff;cursor:pointer;position:relative;border:.0625rem solid #d0d0d0;border-left:none;border-radius:0;transition:all .2s ease;display:inline-flex;align-items:center;justify-content:center;height:2.5rem}.tab-btn:not(:disabled):hover{background-color:#e5edf8}.tab-btn.active{background-color:#0047ba;color:#fff;z-index:2}.tab-btn.active:not(:disabled):hover{background-color:#003995}.tab-btn:focus-visible{outline:.125rem solid #b967c7;outline-offset:.125rem;z-index:3}.tab-btn:disabled{cursor:not-allowed;color:#767676;background-color:#e7e7e7;border-color:#767676}.tab-btn .icon{display:flex;align-items:center;justify-content:center}.tab-btn .icon img{height:1.5rem;width:auto}.tab-btn .button-title{flex-shrink:0}.tab-btn.first{border-radius:.25rem 0 0 .25rem;border-left:.0625rem solid #d0d0d0}.tab-btn.first:disabled{border-left:.0625rem solid #767676}.tab-btn.last{border-radius:0 .25rem .25rem 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
2804
+ }
2805
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonGroupItemComponent, decorators: [{
2806
+ type: Component,
2807
+ args: [{ selector: 'lib-button-group-item', standalone: true, imports: [CommonModule], template: "<button\n type=\"button\"\n class=\"tab-btn\"\n [class.first]=\"position === 'first'\"\n [class.last]=\"position === 'last'\"\n [class.active]=\"isActive\"\n [disabled]=\"disabled\"\n (click)=\"onClick()\"\n role=\"tab\"\n [attr.aria-pressed]=\"isActive\"\n [attr.aria-label]=\"ariaLabel ? ariaLabel : null\"\n [attr.tabindex]=\"disabled ? -1 : 0\"\n>\n @if (icon) {\n <span class=\"icon material-symbols-outlined\">{{ icon }}</span>\n }\n\n @if (title) {\n <span class=\"button-title\">{{ title }}</span>\n }\n</button>\n", styles: [".tab-btn{padding:.5rem 1rem;font-size:1rem;font-weight:400;line-height:1.5rem;color:#00245d;background-color:#fff;cursor:pointer;position:relative;border:.0625rem solid #d0d0d0;border-left:none;border-radius:0;transition:all .2s ease;display:inline-flex;align-items:center;justify-content:center;height:2.5rem}.tab-btn:not(:disabled):hover{background-color:#e5edf8}.tab-btn.active{background-color:#0047ba;color:#fff;z-index:2}.tab-btn.active:not(:disabled):hover{background-color:#003995}.tab-btn:focus-visible{outline:.125rem solid #b967c7;outline-offset:.125rem;z-index:3}.tab-btn:disabled{cursor:not-allowed;color:#767676;background-color:#e7e7e7;border-color:#767676}.tab-btn .icon{display:flex;align-items:center;justify-content:center}.tab-btn .icon img{height:1.5rem;width:auto}.tab-btn .button-title{flex-shrink:0}.tab-btn.first{border-radius:.25rem 0 0 .25rem;border-left:.0625rem solid #d0d0d0}.tab-btn.first:disabled{border-left:.0625rem solid #767676}.tab-btn.last{border-radius:0 .25rem .25rem 0}\n"] }]
2808
+ }], propDecorators: { id: [{
2809
+ type: Input,
2810
+ args: [{ required: true }]
2811
+ }], title: [{
2812
+ type: Input
2813
+ }], icon: [{
2814
+ type: Input
2815
+ }], ariaLabel: [{
2816
+ type: Input
2817
+ }], disabled: [{
2818
+ type: Input
2819
+ }], position: [{
2820
+ type: Input
2821
+ }], buttonClick: [{
2822
+ type: Output
2823
+ }] } });
2824
+
2825
+ class ButtonGroupComponent {
2826
+ constructor() {
2827
+ this.activeButtonChange = new EventEmitter();
2828
+ this.elementRef = inject(ElementRef);
2829
+ this.activeButtonId = signal('');
2830
+ this.subscriptions = [];
2831
+ }
2832
+ /**
2833
+ * Angular lifecycle hook called after content projection is initialized.
2834
+ * Sets up the initial active button and subscribes to button click events from all button items.
2835
+ */
2836
+ ngAfterContentInit() {
2837
+ // Handle both Angular components (via ContentChildren) and custom elements (via DOM)
2838
+ if (this.buttonItems.length > 0) {
2839
+ // Angular component usage
2840
+ this.initializeActiveButton();
2841
+ this.buttonItems.forEach((item) => {
2842
+ const sub = item.buttonClick.subscribe((id) => this.onButtonClick(id));
2843
+ this.subscriptions.push(sub);
2844
+ });
2845
+ }
2846
+ else {
2847
+ // Custom element usage - delay slightly to ensure custom elements are fully initialized
2848
+ setTimeout(() => {
2849
+ this.initializeCustomElements();
2850
+ }, 0);
2851
+ }
2852
+ }
2853
+ /**
2854
+ * Initializes custom element children when used as web components.
2855
+ */
2856
+ initializeCustomElements() {
2857
+ const hostElement = this.elementRef.nativeElement;
2858
+ const customElementChildren = Array.from(hostElement.querySelectorAll('hbll-button-group-item, lib-button-group-item'));
2859
+ if (customElementChildren.length > 0) {
2860
+ // Set position attributes - first and last explicitly, rest are middle
2861
+ customElementChildren[0].setAttribute('position', 'first');
2862
+ if (customElementChildren.length > 1) {
2863
+ customElementChildren[customElementChildren.length - 1].setAttribute('position', 'last');
2864
+ }
2865
+ for (let i = 1; i < customElementChildren.length - 1; i++) {
2866
+ customElementChildren[i].setAttribute('position', 'middle');
2867
+ }
2868
+ const initialId = this.initialActiveId;
2869
+ if (initialId) {
2870
+ this.activeButtonId.set(initialId);
2871
+ customElementChildren.forEach((item) => {
2872
+ const itemId = item.getAttribute('id');
2873
+ if (itemId === initialId) {
2874
+ this.setActiveState(item, true);
2875
+ }
2876
+ else {
2877
+ this.setActiveState(item, false);
2878
+ }
2879
+ });
2880
+ }
2881
+ // Listen to clicks on custom elements
2882
+ customElementChildren.forEach((item) => {
2883
+ item.addEventListener('click', () => {
2884
+ const itemId = item.getAttribute('id');
2885
+ if (itemId && !item.hasAttribute('disabled')) {
2886
+ this.handleCustomElementClick(itemId, customElementChildren);
2887
+ }
2888
+ });
2889
+ });
2890
+ }
2891
+ }
2892
+ /**
2893
+ * Sets the active state on a custom element by toggling the active class on its button.
2894
+ */
2895
+ setActiveState(element, isActive) {
2896
+ const button = element.querySelector('.tab-btn');
2897
+ if (button) {
2898
+ if (isActive) {
2899
+ button.classList.add('active');
2900
+ }
2901
+ else {
2902
+ button.classList.remove('active');
2903
+ }
2904
+ }
2905
+ }
2906
+ /**
2907
+ * Handles click events for custom element children.
2908
+ */
2909
+ handleCustomElementClick(buttonId, children) {
2910
+ this.activeButtonId.set(buttonId);
2911
+ this.activeButtonChange.emit(buttonId);
2912
+ children.forEach((item) => {
2913
+ const itemId = item.getAttribute('id');
2914
+ const isActive = itemId === buttonId;
2915
+ this.setActiveState(item, isActive);
2916
+ });
2917
+ }
2918
+ /**
2919
+ * Angular lifecycle hook called when the component is destroyed.
2920
+ * Cleans up all subscriptions to prevent memory leaks.
2921
+ */
2922
+ ngOnDestroy() {
2923
+ this.subscriptions.forEach((sub) => sub.unsubscribe());
2924
+ }
2925
+ /**
2926
+ * Initializes the active button state based on the initialActiveId input.
2927
+ * Sets the active state on the matching button item if an initial ID is provided.
2928
+ */
2929
+ initializeActiveButton() {
2930
+ const items = this.buttonItems.toArray();
2931
+ const initialId = this.initialActiveId;
2932
+ // Set position - first and last explicitly, rest are middle
2933
+ if (items.length > 0) {
2934
+ items[0].position = 'first';
2935
+ if (items.length > 1) {
2936
+ items[items.length - 1].position = 'last';
2937
+ }
2938
+ for (let i = 1; i < items.length - 1; i++) {
2939
+ items[i].position = 'middle';
2940
+ }
2941
+ }
2942
+ // Set active state
2943
+ if (initialId) {
2944
+ items.forEach((item) => {
2945
+ item.isActive = item.id === initialId;
2946
+ });
2947
+ this.activeButtonId.set(initialId);
2948
+ }
2949
+ }
2950
+ /**
2951
+ * Handles button click events from child button items.
2952
+ * Updates the active button state and emits the activeButtonChange event.
2953
+ * @param buttonId - The ID of the clicked button
2954
+ */
2955
+ onButtonClick(buttonId) {
2956
+ this.activeButtonId.set(buttonId);
2957
+ this.activeButtonChange.emit(buttonId);
2958
+ this.buttonItems.forEach((item) => {
2959
+ item.isActive = item.id === buttonId;
2960
+ });
2961
+ }
2962
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2963
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.1.0", type: ButtonGroupComponent, isStandalone: true, selector: "lib-button-group", inputs: { initialActiveId: "initialActiveId" }, outputs: { activeButtonChange: "activeButtonChange" }, queries: [{ propertyName: "buttonItems", predicate: ButtonGroupItemComponent }], ngImport: i0, template: "<div class=\"button-group\" role=\"tablist\">\n <ng-content></ng-content>\n</div>\n", styles: [".button-group{display:flex;overflow-x:auto;overflow-y:visible;-webkit-overflow-scrolling:touch;padding:.25rem}\n"] }); }
2964
+ }
2965
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImport: i0, type: ButtonGroupComponent, decorators: [{
2966
+ type: Component,
2967
+ args: [{ selector: 'lib-button-group', standalone: true, imports: [ButtonGroupItemComponent], template: "<div class=\"button-group\" role=\"tablist\">\n <ng-content></ng-content>\n</div>\n", styles: [".button-group{display:flex;overflow-x:auto;overflow-y:visible;-webkit-overflow-scrolling:touch;padding:.25rem}\n"] }]
2968
+ }], propDecorators: { initialActiveId: [{
2969
+ type: Input
2970
+ }], activeButtonChange: [{
2971
+ type: Output
2972
+ }], buttonItems: [{
2973
+ type: ContentChildren,
2974
+ args: [ButtonGroupItemComponent]
2975
+ }] } });
2976
+
2625
2977
  /*
2626
2978
  * Public API Surface of components
2627
2979
  */
@@ -2630,5 +2982,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.0", ngImpor
2630
2982
  * Generated bundle index. Do not edit.
2631
2983
  */
2632
2984
 
2633
- 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 };
2985
+ export { ADVANCED_SEARCH_FIELD_MAP, ADVANCED_SEARCH_OPTIONS, ADVANCED_SEARCH_QUALIFIER_MAP, ButtonComponent, ButtonGroupComponent, ButtonGroupItemComponent, HbllFooterComponent, HbllHeaderComponent, HbllItemTypeIconPipe, HeaderWithImpersonationComponent, ImpersonateModalComponent, ImpersonateUserPipe, ImpersonationBannerComponent, LIBRARY_HOURS_API_URL, SnackbarComponent, SnackbarService, SsSearchBarComponent, StatusButtonComponent, defaultOidcBaseUri, defaultOidcDefaultIdp, getUserStatusFromRoles, isAdvancedSearchExternalFieldOption, isAdvancedSearchFieldOption, isAdvancedSearchLocalFieldOption, isSearchScope };
2634
2986
  //# sourceMappingURL=byuhbll-components.mjs.map