@balinasoftware/balinaui-components 3.3.9 → 3.3.11

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.
@@ -18,26 +18,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
18
18
  class Navbar {
19
19
  elementRef;
20
20
  // Brand
21
- brand = 'Aero';
22
- logoAlt = 'Aero logo';
21
+ brand = '';
22
+ logoAlt = '';
23
23
  image = '';
24
24
  // Navigation
25
25
  links = [];
26
26
  // Authentication
27
27
  initiallyLoggedIn = false;
28
28
  // User profile
29
- user = {
30
- username: 'Guest User',
31
- email: 'guest@example.com',
32
- image: '',
33
- role: 'Guest',
34
- name: undefined
35
- };
29
+ user;
36
30
  // Icons
37
- notificationIcon = 'notifications';
38
- profileIcon = 'account_circle';
39
- userIcon = 'person';
40
- logoutIcon = 'logout';
31
+ notificationIcon = '';
32
+ profileIcon = '';
33
+ userIcon = '';
34
+ logoutIcon = '';
41
35
  // Events
42
36
  login = new EventEmitter();
43
37
  logout = new EventEmitter();
@@ -68,11 +62,11 @@ class Navbar {
68
62
  }
69
63
  }
70
64
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Navbar, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
71
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: Navbar, isStandalone: true, selector: "lib-navbar", inputs: { brand: "brand", logoAlt: "logoAlt", image: "image", links: "links", initiallyLoggedIn: "initiallyLoggedIn", user: "user", notificationIcon: "notificationIcon", profileIcon: "profileIcon", userIcon: "userIcon", logoutIcon: "logoutIcon" }, outputs: { login: "login", logout: "logout" }, host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, ngImport: i0, template: "<header class=\"anv-navbar\">\n\n <!--TOP STRIPE-->\n <div class=\"anv-topbar\"></div>\n <!--NAVBAR-->\n <div class=\"anv-stripes\">\n <div class=\"anv-content\">\n\n <!--BRAND / LOGO-->\n <img *ngIf=\"image\" [src]=\"image\" [alt]=\"logoAlt\" class=\"anv-brand-icon\" />\n <span *ngIf=\"brand\" class=\"anv-brand-name\">\n {{ brand }}\n </span>\n\n <!--NAVIGATION LINKS-->\n <nav class=\"anv-links\" aria-label=\"Main navigation\">\n <a *ngFor=\"let link of links\" [routerLink]=\"link.url\" routerLinkActive=\"anv-link-active\"\n [routerLinkActiveOptions]=\"{ exact: true }\" class=\"anv-link\">\n {{ link.label }}\n </a>\n </nav>\n\n\n <!--ACTIONS-->\n <div class=\"anv-actions\">\n <!--NOTIFICATION-->\n <button type=\"button\" class=\"anv-icon-btn\" aria-label=\"Notifications\">\n <span class=\"material-icons\">\n {{ notificationIcon }}\n </span>\n </button>\n\n \n <!--DIVIDER-->\n <span class=\"anv-divider\"></span>\n\n <!--LOGIN-->\n <button *ngIf=\"!isLoggedIn\" type=\"button\" class=\"anv-login-btn\" (click)=\"handleLoginClick()\">\n Login\n </button>\n\n <!--PROFILE-->\n <div *ngIf=\"isLoggedIn\" class=\"anv-profile-wrap\">\n\n <!-- PROFILE BUTTON -->\n <button type=\"button\" class=\"anv-profile-btn\" (click)=\"handleProfileClick()\"\n [attr.aria-expanded]=\"isDropdownOpen\" aria-haspopup=\"true\" aria-label=\"User profile\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" class=\"anv-profile-image\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ profileIcon }}\n </span>\n \n </button>\n\n <!-- PROFILE DROPDOWN-->\n\n <div *ngIf=\"isDropdownOpen\" class=\"anv-dropdown\">\n <!-- USER INFORMATION -->\n <div class=\"anv-dropdown-header\">\n <!-- USER IMAGE -->\n <div class=\"anv-dropdown-avatar\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ userIcon }}\n </span>\n </div>\n\n <!-- USER DETAILS -->\n\n <div class=\"anv-dropdown-info\">\n <span class=\"anv-dropdown-name\">\n {{ user.name }}\n </span>\n <span class=\"anv-dropdown-email\">\n {{ user.email }}\n </span>\n <span *ngIf=\"user.role\" class=\"anv-dropdown-role\">\n {{ user.role }}\n </span>\n </div>\n </div>\n\n <!-- DIVIDER -->\n <hr class=\"anv-dropdown-sep\">\n <!-- LOGOUT -->\n <button type=\"button\" class=\"anv-dropdown-item anv-logout\" (click)=\"handleLogoutClick()\">\n <span class=\"material-icons\">\n {{ logoutIcon }}\n </span>\n <span>\n Log out\n </span>\n </button>\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</header>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*,*:before,*:after{box-sizing:border-box}.anv-navbar{display:flex;font-family:Inter,Arial,sans-serif;background:#fff;position:relative;z-index:1000}.anv-stripes{width:100%;background:#fff;border-bottom:1px solid #e6e6e6;box-shadow:0 2px 12px #0000000d}.anv-content{width:min(1350px,100%);margin:auto 20px auto auto;display:flex;align-items:center;justify-content:space-between;gap:30px;padding:18px clamp(50px,3vw,60px)}.anv-brand{display:flex;align-items:center;gap:12px;flex-shrink:0}.anv-brand-icon{width:clamp(60px,7vw,100px);height:auto;object-fit:contain;transition:.3s}.anv-brand-icon:hover{transform:scale(1.08)}.anv-brand-name{font-size:22px;font-weight:700;color:#1f4d4a;white-space:nowrap}.anv-links{display:flex;justify-content:right;align-items:center;flex:1;gap:clamp(18px,3vw,40px);min-width:0}.anv-link{position:relative;text-decoration:none;color:#555;font-size:17px;font-weight:600;transition:.3s;white-space:nowrap}.anv-link:hover{color:#1f4d4a}.anv-link:after{content:\"\";position:absolute;left:0;bottom:-8px;width:0;height:2px;background:#1f4d4a;transition:.3s}.anv-link:hover:after{width:100%}.anv-actions{display:flex;align-items:center;gap:18px;flex-shrink:0;margin-left:auto}.anv-icon-btn{width:42px;height:42px;display:flex;justify-content:center;align-items:center;border:none;background:none;cursor:pointer;transition:.3s;border-radius:50%}.anv-icon-btn:hover{background:#f4f4f4;transform:translateY(-2px)}.anv-divider{width:1px;height:32px;background:#d8d8d8}.anv-login-btn{padding:10px 24px;border:none;border-radius:30px;background:#1f4d4a;color:#fff;font-size:15px;font-weight:600;cursor:pointer;transition:.3s}.anv-login-btn:hover{background:#163836;transform:translateY(-2px);box-shadow:0 8px 18px #0000002e}.anv-login-btn:active{transform:scale(.96)}.anv-profile-wrap{position:relative}.anv-profile-btn{width:48px;height:48px;border:none;border-radius:50%;background:#111;color:#fff;cursor:pointer;display:flex;justify-content:center;align-items:center;transition:.3s}.anv-profile-btn:hover{transform:scale(1.08);box-shadow:0 8px 18px #00000026}.anv-dropdown{position:absolute;top:calc(100% + 12px);right:0;width:260px;background:#fff;border-radius:14px;box-shadow:0 12px 30px #0000002e;overflow:hidden;animation:dropdown .25s ease;z-index:999}@keyframes dropdown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.anv-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px}.anv-dropdown-avatar{width:45px;height:45px;border-radius:50%;background:#111;color:#fff;display:flex;justify-content:center;align-items:center;font-weight:700}.anv-dropdown-info{display:flex;flex-direction:column;overflow:hidden}.anv-dropdown-name{font-weight:700;font-size:15px}.anv-dropdown-email{font-size:13px;color:#777;overflow:hidden;text-overflow:ellipsis}.anv-dropdown-sep{border:none;border-top:1px solid #eee;margin:0}.anv-dropdown-item{width:100%;padding:14px 18px;background:none;border:none;cursor:pointer;text-align:left;font-size:15px;transition:.3s}.anv-dropdown-item:hover{background:#f7f7f7}.anv-logout{color:#d32f2f;font-weight:600}@media(max-width:992px){.anv-content{display:flex;align-items:center;justify-content:space-between;width:100%;padding:14px 20px;gap:12px}.anv-brand{flex-shrink:0}.anv-brand-icon{width:90px}.anv-links{flex:1;display:flex;justify-content:center;gap:18px;min-width:0;overflow:hidden}.anv-link{font-size:14px}.anv-actions{display:flex;align-items:center;gap:10px;flex-shrink:0;margin-left:auto}.anv-login-btn{padding:8px 16px;font-size:13px}.anv-profile-btn{width:40px;height:40px}}@media(max-width:768px){.anv-content{padding:12px 16px;gap:10px}.anv-brand-icon{width:80px}.anv-link{font-size:13px}.anv-links{gap:10px;overflow-x:auto;scrollbar-width:none}.anv-links::-webkit-scrollbar{display:none}.anv-login-btn{padding:7px 12px;font-size:12px}.anv-profile-btn{width:36px;height:36px}}.anv-navbar,.anv-stripes{width:100%;background:#fff}.anv-content{width:100%;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: i2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: MatIconModule }] });
65
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: Navbar, isStandalone: true, selector: "lib-navbar", inputs: { brand: "brand", logoAlt: "logoAlt", image: "image", links: "links", initiallyLoggedIn: "initiallyLoggedIn", user: "user", notificationIcon: "notificationIcon", profileIcon: "profileIcon", userIcon: "userIcon", logoutIcon: "logoutIcon" }, outputs: { login: "login", logout: "logout" }, host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, ngImport: i0, template: "<header class=\"anv-navbar\">\n\n <!--TOP STRIPE-->\n <div class=\"anv-topbar\"></div>\n <!--NAVBAR-->\n <div class=\"anv-stripes\">\n <div class=\"anv-content\">\n\n <!--BRAND / LOGO-->\n <img *ngIf=\"image\" [src]=\"image\" [alt]=\"logoAlt\" class=\"anv-brand-icon\" />\n <span *ngIf=\"brand\" class=\"anv-brand-name\">\n {{ brand }}\n </span>\n\n <!--NAVIGATION LINKS-->\n <nav class=\"anv-links\" aria-label=\"Main navigation\">\n <a *ngFor=\"let link of links\" [routerLink]=\"link.url\" routerLinkActive=\"anv-link-active\"\n [routerLinkActiveOptions]=\"{ exact: true }\" class=\"anv-link\">\n {{ link.label }}\n </a>\n </nav>\n\n\n <!--ACTIONS-->\n <div class=\"anv-actions\">\n <!--NOTIFICATION-->\n <button type=\"button\" class=\"anv-icon-btn\" aria-label=\"Notifications\">\n <span class=\"material-icons\">\n {{ notificationIcon }}\n </span>\n </button>\n\n \n <!--DIVIDER-->\n <span class=\"anv-divider\"></span>\n\n <!--LOGIN-->\n <button *ngIf=\"!isLoggedIn\" type=\"button\" class=\"anv-login-btn\" (click)=\"handleLoginClick()\">\n Login\n </button>\n\n <!--PROFILE-->\n <div *ngIf=\"isLoggedIn\" class=\"anv-profile-wrap\">\n\n <!-- PROFILE BUTTON -->\n <button type=\"button\" class=\"anv-profile-btn\" (click)=\"handleProfileClick()\"\n [attr.aria-expanded]=\"isDropdownOpen\" aria-haspopup=\"true\" aria-label=\"User profile\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" class=\"anv-profile-image\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ profileIcon }}\n </span>\n \n </button>\n\n <!-- PROFILE DROPDOWN-->\n\n <div *ngIf=\"isDropdownOpen\" class=\"anv-dropdown\">\n <!-- USER INFORMATION -->\n <div class=\"anv-dropdown-header\">\n <!-- USER IMAGE -->\n <div class=\"anv-dropdown-avatar\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ userIcon }}\n </span>\n </div>\n\n <!-- USER DETAILS -->\n\n <div class=\"anv-dropdown-info\">\n <span class=\"anv-dropdown-name\">\n {{ user.name }}\n </span>\n <span class=\"anv-dropdown-email\">\n {{ user.email }}\n </span>\n <span *ngIf=\"user.role\" class=\"anv-dropdown-role\">\n {{ user.role }}\n </span>\n </div>\n </div>\n\n <!-- DIVIDER -->\n <hr class=\"anv-dropdown-sep\">\n <!-- LOGOUT -->\n <button type=\"button\" class=\"anv-dropdown-item anv-logout\" (click)=\"handleLogoutClick()\">\n <span class=\"material-icons\">\n {{ logoutIcon }}\n </span>\n <span>\n Log out\n </span>\n </button>\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</header>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*,*:before,*:after{box-sizing:border-box}.anv-navbar{display:flex;font-family:Inter,Arial,sans-serif;background:#fff;position:relative;z-index:1000}.anv-stripes{width:100%;background:#fff;border-bottom:1px solid #e6e6e6;box-shadow:0 2px 12px #0000000d}.anv-content{width:min(1350px,100%);margin:auto 20px auto auto;display:flex;align-items:center;justify-content:space-between;gap:30px;padding:18px}.anv-brand{display:flex;align-items:center;gap:12px;flex-shrink:0}.anv-brand-icon{width:clamp(60px,7vw,100px);height:auto;object-fit:contain;transition:.3s}.anv-brand-icon:hover{transform:scale(1.08)}.anv-brand-name{font-size:22px;font-weight:700;color:#1f4d4a;white-space:nowrap}.anv-links{display:flex;justify-content:right;align-items:center;flex:1;gap:clamp(18px,3vw,40px);min-width:0}.anv-link{position:relative;text-decoration:none;color:#555;font-size:17px;font-weight:600;transition:.3s;white-space:nowrap}.anv-link:hover{color:#1f4d4a}.anv-link:after{content:\"\";position:absolute;left:0;bottom:-8px;width:0;height:2px;background:#1f4d4a;transition:.3s}.anv-link:hover:after{width:100%}.anv-actions{display:flex;align-items:center;gap:18px;flex-shrink:0;margin-left:auto}.anv-icon-btn{width:42px;height:42px;display:flex;justify-content:center;align-items:center;border:none;background:none;cursor:pointer;transition:.3s;border-radius:50%}.anv-icon-btn:hover{background:#f4f4f4;transform:translateY(-2px)}.anv-divider{width:1px;height:32px;background:#d8d8d8}.anv-login-btn{padding:10px 24px;border:none;border-radius:30px;background:#1f4d4a;color:#fff;font-size:15px;font-weight:600;cursor:pointer;transition:.3s}.anv-login-btn:hover{background:#163836;transform:translateY(-2px);box-shadow:0 8px 18px #0000002e}.anv-login-btn:active{transform:scale(.96)}.anv-profile-wrap{position:relative}.anv-profile-btn{width:48px;height:48px;border:none;border-radius:50%;background:#111;color:#fff;cursor:pointer;display:flex;justify-content:center;align-items:center;transition:.3s}.anv-profile-btn:hover{transform:scale(1.08);box-shadow:0 8px 18px #00000026}.anv-dropdown{position:absolute;top:calc(100% + 12px);right:0;width:260px;background:#fff;border-radius:14px;box-shadow:0 12px 30px #0000002e;overflow:hidden;animation:dropdown .25s ease;z-index:999}@keyframes dropdown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.anv-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px}.anv-dropdown-avatar{width:45px;height:45px;border-radius:50%;background:#111;color:#fff;display:flex;justify-content:center;align-items:center;font-weight:700}.anv-dropdown-info{display:flex;flex-direction:column;overflow:hidden}.anv-dropdown-name{font-weight:700;font-size:15px}.anv-dropdown-email{font-size:13px;color:#777;overflow:hidden;text-overflow:ellipsis}.anv-dropdown-sep{border:none;border-top:1px solid #eee;margin:0}.anv-dropdown-item{width:100%;padding:14px 18px;background:none;border:none;cursor:pointer;text-align:left;font-size:15px;transition:.3s}.anv-dropdown-item:hover{background:#f7f7f7}.anv-logout{color:#d32f2f;font-weight:600}@media(max-width:992px){.anv-content{display:flex;align-items:center;justify-content:space-between;width:100%;padding:14px 20px;gap:12px}.anv-brand{flex-shrink:0}.anv-brand-icon{width:90px}.anv-links{flex:1;display:flex;justify-content:center;gap:18px;min-width:0;overflow:hidden}.anv-link{font-size:14px}.anv-actions{display:flex;align-items:center;gap:10px;flex-shrink:0;margin-left:auto}.anv-login-btn{padding:8px 16px;font-size:13px}.anv-profile-btn{width:40px;height:40px}}@media(max-width:768px){.anv-content{padding:12px 16px;gap:10px}.anv-brand-icon{width:80px}.anv-link{font-size:13px}.anv-links{gap:10px;overflow-x:auto;scrollbar-width:none}.anv-links::-webkit-scrollbar{display:none}.anv-login-btn{padding:7px 12px;font-size:12px}.anv-profile-btn{width:36px;height:36px}}.anv-navbar,.anv-stripes{width:100%;background:#fff}.anv-content{width:100%;box-sizing:border-box}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: i2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: MatIconModule }] });
72
66
  }
73
67
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Navbar, decorators: [{
74
68
  type: Component,
75
- args: [{ selector: 'lib-navbar', standalone: true, imports: [CommonModule, RouterModule, MatIconModule], template: "<header class=\"anv-navbar\">\n\n <!--TOP STRIPE-->\n <div class=\"anv-topbar\"></div>\n <!--NAVBAR-->\n <div class=\"anv-stripes\">\n <div class=\"anv-content\">\n\n <!--BRAND / LOGO-->\n <img *ngIf=\"image\" [src]=\"image\" [alt]=\"logoAlt\" class=\"anv-brand-icon\" />\n <span *ngIf=\"brand\" class=\"anv-brand-name\">\n {{ brand }}\n </span>\n\n <!--NAVIGATION LINKS-->\n <nav class=\"anv-links\" aria-label=\"Main navigation\">\n <a *ngFor=\"let link of links\" [routerLink]=\"link.url\" routerLinkActive=\"anv-link-active\"\n [routerLinkActiveOptions]=\"{ exact: true }\" class=\"anv-link\">\n {{ link.label }}\n </a>\n </nav>\n\n\n <!--ACTIONS-->\n <div class=\"anv-actions\">\n <!--NOTIFICATION-->\n <button type=\"button\" class=\"anv-icon-btn\" aria-label=\"Notifications\">\n <span class=\"material-icons\">\n {{ notificationIcon }}\n </span>\n </button>\n\n \n <!--DIVIDER-->\n <span class=\"anv-divider\"></span>\n\n <!--LOGIN-->\n <button *ngIf=\"!isLoggedIn\" type=\"button\" class=\"anv-login-btn\" (click)=\"handleLoginClick()\">\n Login\n </button>\n\n <!--PROFILE-->\n <div *ngIf=\"isLoggedIn\" class=\"anv-profile-wrap\">\n\n <!-- PROFILE BUTTON -->\n <button type=\"button\" class=\"anv-profile-btn\" (click)=\"handleProfileClick()\"\n [attr.aria-expanded]=\"isDropdownOpen\" aria-haspopup=\"true\" aria-label=\"User profile\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" class=\"anv-profile-image\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ profileIcon }}\n </span>\n \n </button>\n\n <!-- PROFILE DROPDOWN-->\n\n <div *ngIf=\"isDropdownOpen\" class=\"anv-dropdown\">\n <!-- USER INFORMATION -->\n <div class=\"anv-dropdown-header\">\n <!-- USER IMAGE -->\n <div class=\"anv-dropdown-avatar\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ userIcon }}\n </span>\n </div>\n\n <!-- USER DETAILS -->\n\n <div class=\"anv-dropdown-info\">\n <span class=\"anv-dropdown-name\">\n {{ user.name }}\n </span>\n <span class=\"anv-dropdown-email\">\n {{ user.email }}\n </span>\n <span *ngIf=\"user.role\" class=\"anv-dropdown-role\">\n {{ user.role }}\n </span>\n </div>\n </div>\n\n <!-- DIVIDER -->\n <hr class=\"anv-dropdown-sep\">\n <!-- LOGOUT -->\n <button type=\"button\" class=\"anv-dropdown-item anv-logout\" (click)=\"handleLogoutClick()\">\n <span class=\"material-icons\">\n {{ logoutIcon }}\n </span>\n <span>\n Log out\n </span>\n </button>\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</header>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*,*:before,*:after{box-sizing:border-box}.anv-navbar{display:flex;font-family:Inter,Arial,sans-serif;background:#fff;position:relative;z-index:1000}.anv-stripes{width:100%;background:#fff;border-bottom:1px solid #e6e6e6;box-shadow:0 2px 12px #0000000d}.anv-content{width:min(1350px,100%);margin:auto 20px auto auto;display:flex;align-items:center;justify-content:space-between;gap:30px;padding:18px clamp(50px,3vw,60px)}.anv-brand{display:flex;align-items:center;gap:12px;flex-shrink:0}.anv-brand-icon{width:clamp(60px,7vw,100px);height:auto;object-fit:contain;transition:.3s}.anv-brand-icon:hover{transform:scale(1.08)}.anv-brand-name{font-size:22px;font-weight:700;color:#1f4d4a;white-space:nowrap}.anv-links{display:flex;justify-content:right;align-items:center;flex:1;gap:clamp(18px,3vw,40px);min-width:0}.anv-link{position:relative;text-decoration:none;color:#555;font-size:17px;font-weight:600;transition:.3s;white-space:nowrap}.anv-link:hover{color:#1f4d4a}.anv-link:after{content:\"\";position:absolute;left:0;bottom:-8px;width:0;height:2px;background:#1f4d4a;transition:.3s}.anv-link:hover:after{width:100%}.anv-actions{display:flex;align-items:center;gap:18px;flex-shrink:0;margin-left:auto}.anv-icon-btn{width:42px;height:42px;display:flex;justify-content:center;align-items:center;border:none;background:none;cursor:pointer;transition:.3s;border-radius:50%}.anv-icon-btn:hover{background:#f4f4f4;transform:translateY(-2px)}.anv-divider{width:1px;height:32px;background:#d8d8d8}.anv-login-btn{padding:10px 24px;border:none;border-radius:30px;background:#1f4d4a;color:#fff;font-size:15px;font-weight:600;cursor:pointer;transition:.3s}.anv-login-btn:hover{background:#163836;transform:translateY(-2px);box-shadow:0 8px 18px #0000002e}.anv-login-btn:active{transform:scale(.96)}.anv-profile-wrap{position:relative}.anv-profile-btn{width:48px;height:48px;border:none;border-radius:50%;background:#111;color:#fff;cursor:pointer;display:flex;justify-content:center;align-items:center;transition:.3s}.anv-profile-btn:hover{transform:scale(1.08);box-shadow:0 8px 18px #00000026}.anv-dropdown{position:absolute;top:calc(100% + 12px);right:0;width:260px;background:#fff;border-radius:14px;box-shadow:0 12px 30px #0000002e;overflow:hidden;animation:dropdown .25s ease;z-index:999}@keyframes dropdown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.anv-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px}.anv-dropdown-avatar{width:45px;height:45px;border-radius:50%;background:#111;color:#fff;display:flex;justify-content:center;align-items:center;font-weight:700}.anv-dropdown-info{display:flex;flex-direction:column;overflow:hidden}.anv-dropdown-name{font-weight:700;font-size:15px}.anv-dropdown-email{font-size:13px;color:#777;overflow:hidden;text-overflow:ellipsis}.anv-dropdown-sep{border:none;border-top:1px solid #eee;margin:0}.anv-dropdown-item{width:100%;padding:14px 18px;background:none;border:none;cursor:pointer;text-align:left;font-size:15px;transition:.3s}.anv-dropdown-item:hover{background:#f7f7f7}.anv-logout{color:#d32f2f;font-weight:600}@media(max-width:992px){.anv-content{display:flex;align-items:center;justify-content:space-between;width:100%;padding:14px 20px;gap:12px}.anv-brand{flex-shrink:0}.anv-brand-icon{width:90px}.anv-links{flex:1;display:flex;justify-content:center;gap:18px;min-width:0;overflow:hidden}.anv-link{font-size:14px}.anv-actions{display:flex;align-items:center;gap:10px;flex-shrink:0;margin-left:auto}.anv-login-btn{padding:8px 16px;font-size:13px}.anv-profile-btn{width:40px;height:40px}}@media(max-width:768px){.anv-content{padding:12px 16px;gap:10px}.anv-brand-icon{width:80px}.anv-link{font-size:13px}.anv-links{gap:10px;overflow-x:auto;scrollbar-width:none}.anv-links::-webkit-scrollbar{display:none}.anv-login-btn{padding:7px 12px;font-size:12px}.anv-profile-btn{width:36px;height:36px}}.anv-navbar,.anv-stripes{width:100%;background:#fff}.anv-content{width:100%;box-sizing:border-box}\n"] }]
69
+ args: [{ selector: 'lib-navbar', standalone: true, imports: [CommonModule, RouterModule, MatIconModule], template: "<header class=\"anv-navbar\">\n\n <!--TOP STRIPE-->\n <div class=\"anv-topbar\"></div>\n <!--NAVBAR-->\n <div class=\"anv-stripes\">\n <div class=\"anv-content\">\n\n <!--BRAND / LOGO-->\n <img *ngIf=\"image\" [src]=\"image\" [alt]=\"logoAlt\" class=\"anv-brand-icon\" />\n <span *ngIf=\"brand\" class=\"anv-brand-name\">\n {{ brand }}\n </span>\n\n <!--NAVIGATION LINKS-->\n <nav class=\"anv-links\" aria-label=\"Main navigation\">\n <a *ngFor=\"let link of links\" [routerLink]=\"link.url\" routerLinkActive=\"anv-link-active\"\n [routerLinkActiveOptions]=\"{ exact: true }\" class=\"anv-link\">\n {{ link.label }}\n </a>\n </nav>\n\n\n <!--ACTIONS-->\n <div class=\"anv-actions\">\n <!--NOTIFICATION-->\n <button type=\"button\" class=\"anv-icon-btn\" aria-label=\"Notifications\">\n <span class=\"material-icons\">\n {{ notificationIcon }}\n </span>\n </button>\n\n \n <!--DIVIDER-->\n <span class=\"anv-divider\"></span>\n\n <!--LOGIN-->\n <button *ngIf=\"!isLoggedIn\" type=\"button\" class=\"anv-login-btn\" (click)=\"handleLoginClick()\">\n Login\n </button>\n\n <!--PROFILE-->\n <div *ngIf=\"isLoggedIn\" class=\"anv-profile-wrap\">\n\n <!-- PROFILE BUTTON -->\n <button type=\"button\" class=\"anv-profile-btn\" (click)=\"handleProfileClick()\"\n [attr.aria-expanded]=\"isDropdownOpen\" aria-haspopup=\"true\" aria-label=\"User profile\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" class=\"anv-profile-image\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ profileIcon }}\n </span>\n \n </button>\n\n <!-- PROFILE DROPDOWN-->\n\n <div *ngIf=\"isDropdownOpen\" class=\"anv-dropdown\">\n <!-- USER INFORMATION -->\n <div class=\"anv-dropdown-header\">\n <!-- USER IMAGE -->\n <div class=\"anv-dropdown-avatar\">\n <img *ngIf=\"user.image\" [src]=\"user.image\" [alt]=\"user.name\" />\n <span *ngIf=\"!user.image\" class=\"material-icons\">\n {{ userIcon }}\n </span>\n </div>\n\n <!-- USER DETAILS -->\n\n <div class=\"anv-dropdown-info\">\n <span class=\"anv-dropdown-name\">\n {{ user.name }}\n </span>\n <span class=\"anv-dropdown-email\">\n {{ user.email }}\n </span>\n <span *ngIf=\"user.role\" class=\"anv-dropdown-role\">\n {{ user.role }}\n </span>\n </div>\n </div>\n\n <!-- DIVIDER -->\n <hr class=\"anv-dropdown-sep\">\n <!-- LOGOUT -->\n <button type=\"button\" class=\"anv-dropdown-item anv-logout\" (click)=\"handleLogoutClick()\">\n <span class=\"material-icons\">\n {{ logoutIcon }}\n </span>\n <span>\n Log out\n </span>\n </button>\n\n </div>\n </div>\n </div>\n </div>\n </div>\n</header>", styles: ["@import\"https://fonts.googleapis.com/icon?family=Material+Icons\";*,*:before,*:after{box-sizing:border-box}.anv-navbar{display:flex;font-family:Inter,Arial,sans-serif;background:#fff;position:relative;z-index:1000}.anv-stripes{width:100%;background:#fff;border-bottom:1px solid #e6e6e6;box-shadow:0 2px 12px #0000000d}.anv-content{width:min(1350px,100%);margin:auto 20px auto auto;display:flex;align-items:center;justify-content:space-between;gap:30px;padding:18px}.anv-brand{display:flex;align-items:center;gap:12px;flex-shrink:0}.anv-brand-icon{width:clamp(60px,7vw,100px);height:auto;object-fit:contain;transition:.3s}.anv-brand-icon:hover{transform:scale(1.08)}.anv-brand-name{font-size:22px;font-weight:700;color:#1f4d4a;white-space:nowrap}.anv-links{display:flex;justify-content:right;align-items:center;flex:1;gap:clamp(18px,3vw,40px);min-width:0}.anv-link{position:relative;text-decoration:none;color:#555;font-size:17px;font-weight:600;transition:.3s;white-space:nowrap}.anv-link:hover{color:#1f4d4a}.anv-link:after{content:\"\";position:absolute;left:0;bottom:-8px;width:0;height:2px;background:#1f4d4a;transition:.3s}.anv-link:hover:after{width:100%}.anv-actions{display:flex;align-items:center;gap:18px;flex-shrink:0;margin-left:auto}.anv-icon-btn{width:42px;height:42px;display:flex;justify-content:center;align-items:center;border:none;background:none;cursor:pointer;transition:.3s;border-radius:50%}.anv-icon-btn:hover{background:#f4f4f4;transform:translateY(-2px)}.anv-divider{width:1px;height:32px;background:#d8d8d8}.anv-login-btn{padding:10px 24px;border:none;border-radius:30px;background:#1f4d4a;color:#fff;font-size:15px;font-weight:600;cursor:pointer;transition:.3s}.anv-login-btn:hover{background:#163836;transform:translateY(-2px);box-shadow:0 8px 18px #0000002e}.anv-login-btn:active{transform:scale(.96)}.anv-profile-wrap{position:relative}.anv-profile-btn{width:48px;height:48px;border:none;border-radius:50%;background:#111;color:#fff;cursor:pointer;display:flex;justify-content:center;align-items:center;transition:.3s}.anv-profile-btn:hover{transform:scale(1.08);box-shadow:0 8px 18px #00000026}.anv-dropdown{position:absolute;top:calc(100% + 12px);right:0;width:260px;background:#fff;border-radius:14px;box-shadow:0 12px 30px #0000002e;overflow:hidden;animation:dropdown .25s ease;z-index:999}@keyframes dropdown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.anv-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px}.anv-dropdown-avatar{width:45px;height:45px;border-radius:50%;background:#111;color:#fff;display:flex;justify-content:center;align-items:center;font-weight:700}.anv-dropdown-info{display:flex;flex-direction:column;overflow:hidden}.anv-dropdown-name{font-weight:700;font-size:15px}.anv-dropdown-email{font-size:13px;color:#777;overflow:hidden;text-overflow:ellipsis}.anv-dropdown-sep{border:none;border-top:1px solid #eee;margin:0}.anv-dropdown-item{width:100%;padding:14px 18px;background:none;border:none;cursor:pointer;text-align:left;font-size:15px;transition:.3s}.anv-dropdown-item:hover{background:#f7f7f7}.anv-logout{color:#d32f2f;font-weight:600}@media(max-width:992px){.anv-content{display:flex;align-items:center;justify-content:space-between;width:100%;padding:14px 20px;gap:12px}.anv-brand{flex-shrink:0}.anv-brand-icon{width:90px}.anv-links{flex:1;display:flex;justify-content:center;gap:18px;min-width:0;overflow:hidden}.anv-link{font-size:14px}.anv-actions{display:flex;align-items:center;gap:10px;flex-shrink:0;margin-left:auto}.anv-login-btn{padding:8px 16px;font-size:13px}.anv-profile-btn{width:40px;height:40px}}@media(max-width:768px){.anv-content{padding:12px 16px;gap:10px}.anv-brand-icon{width:80px}.anv-link{font-size:13px}.anv-links{gap:10px;overflow-x:auto;scrollbar-width:none}.anv-links::-webkit-scrollbar{display:none}.anv-login-btn{padding:7px 12px;font-size:12px}.anv-profile-btn{width:36px;height:36px}}.anv-navbar,.anv-stripes{width:100%;background:#fff}.anv-content{width:100%;box-sizing:border-box}\n"] }]
76
70
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { brand: [{
77
71
  type: Input
78
72
  }], logoAlt: [{
@@ -103,36 +97,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
103
97
  }] } });
104
98
 
105
99
  class Button {
106
- // =========================================
107
100
  // INPUTS
108
- // =========================================
109
- label = 'Button';
101
+ label = '';
110
102
  type = 'button';
111
103
  disabled = false;
112
104
  loading = false;
105
+ clickable = true;
113
106
  customClass = '';
114
- // =========================================
107
+ // HOST CLASSES
108
+ get buttonClickable() {
109
+ return (this.clickable &&
110
+ !this.disabled &&
111
+ !this.loading);
112
+ }
113
+ get buttonDisabled() {
114
+ return (this.disabled ||
115
+ this.loading);
116
+ }
115
117
  // OUTPUTS
116
- // =========================================
117
118
  clicked = new EventEmitter();
118
- // =========================================
119
- // CLICK
120
- // =========================================
119
+ // CLICK HANDLER
121
120
  onClick(event) {
122
121
  if (this.disabled ||
123
- this.loading) {
122
+ this.loading ||
123
+ !this.clickable) {
124
124
  event.preventDefault();
125
+ event.stopPropagation();
125
126
  return;
126
127
  }
127
- // Developer event
128
128
  this.clicked.emit(event);
129
129
  }
130
130
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Button, deps: [], target: i0.ɵɵFactoryTarget.Component });
131
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: Button, isStandalone: true, selector: "lib-button", inputs: { label: "label", type: "type", disabled: "disabled", loading: "loading", customClass: "customClass" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n class=\"balina-button\"\n [class]=\"customClass\"\n [type]=\"type\"\n [disabled]=\"disabled || loading\"\n [attr.aria-busy]=\"loading\"\n (click)=\"onClick($event)\"\n>\n\n @if (loading) {\n\n <span\n class=\"button-spinner\"\n aria-hidden=\"true\"\n ></span>\n\n <span>\n Loading...\n </span>\n\n } @else {\n\n <span class=\"button-label\">\n {{ label }}\n </span>\n\n }\n\n</button>", styles: [".balina-button{--button-width: auto;--button-height: 44px;--button-padding: 0 22px;--button-background: #68479b;--button-background-hover: #593b84;--button-background-active: #4b326f;--button-text-color: #ffffff;--button-border: 1px solid #68479b;--button-radius: 6px;--button-font-family: Arial, Helvetica, sans-serif;--button-font-size: 14px;--button-font-weight: 600;--button-gap: 8px;--button-shadow: 0 2px 5px rgba(0, 0, 0, .08);--button-disabled-background: #dddddd;--button-disabled-text: #999999;--button-disabled-border: #dddddd;width:var(--button-width);min-height:var(--button-height);padding:var(--button-padding);display:inline-flex;align-items:center;justify-content:center;gap:var(--button-gap);box-sizing:border-box;border:var(--button-border);border-radius:var(--button-radius);background:var(--button-background);color:var(--button-text-color);font-family:var(--button-font-family);font-size:var(--button-font-size);font-weight:var(--button-font-weight);box-shadow:var(--button-shadow);outline:none;cursor:pointer;-webkit-user-select:none;user-select:none;transition:background-color .2s ease,border-color .2s ease,box-shadow .2s ease,transform .1s ease}.balina-button:hover:not(:disabled){background:var(--button-background-hover)}.balina-button:active:not(:disabled){background:var(--button-background-active);transform:translateY(1px)}.balina-button:focus-visible{box-shadow:0 0 0 3px #68479b33}.balina-button:disabled{background:var(--button-disabled-background);color:var(--button-disabled-text);border-color:var(--button-disabled-border);cursor:not-allowed;box-shadow:none;transform:none}.balina-button[aria-busy=true]{cursor:wait}.button-spinner{width:16px;height:16px;box-sizing:border-box;border:2px solid rgba(255,255,255,.4);border-top-color:var(--button-text-color);border-radius:50%;animation:button-spin .7s linear infinite}@keyframes button-spin{to{transform:rotate(360deg)}}.button-label{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap}@media(max-width:768px){.balina-button{min-height:var(--button-height);font-size:var(--button-font-size)}}\n"] });
131
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: Button, isStandalone: true, selector: "lib-button", inputs: { label: "label", type: "type", disabled: "disabled", loading: "loading", clickable: "clickable", customClass: "customClass" }, outputs: { clicked: "clicked" }, host: { properties: { "class": "this.customClass", "class.button-clickable": "this.buttonClickable", "class.button-disabled": "this.buttonDisabled" } }, ngImport: i0, template: "<button class=\"balina-button\" [type]=\"type\" [disabled]=\"\n disabled ||\n loading ||\n !clickable\n \" [attr.aria-disabled]=\"\n disabled ||\n loading ||\n !clickable\n \" [attr.aria-busy]=\"loading\" (click)=\"onClick($event)\">\n\n\n @if (loading) {\n\n <span class=\"button-spinner\" aria-hidden=\"true\"></span>\n\n <span class=\"button-loading-text\">\n Loading...\n </span>\n\n }\n @else {\n\n <span class=\"button-label\">\n {{ label }}\n </span>\n\n }\n\n</button>", styles: [":host{--button-width: auto;--button-height: 44px;--button-padding: 0 22px;--button-background: #68479b;--button-background-hover: #593b84;--button-background-active: #4b326f;--button-text-color: #ffffff;--button-border: 1px solid #68479b;--button-radius: 6px;--button-font-family: Arial, Helvetica, sans-serif;--button-font-size: 14px;--button-font-weight: 600;--button-gap: 8px;--button-shadow: 0 2px 5px rgba(0, 0, 0, .08);--button-disabled-background: #dddddd;--button-disabled-text: #999999;--button-disabled-border: #dddddd;--button-focus-ring: rgba(104, 71, 155, .2);--button-spinner-size: 16px;--button-spinner-border: 2px;display:inline-block;width:var(--button-width);box-sizing:border-box;font-family:var(--button-font-family)}.balina-button{width:100%;min-height:var(--button-height);padding:var(--button-padding);display:inline-flex;align-items:center;justify-content:center;gap:var(--button-gap);box-sizing:border-box;border:var(--button-border);border-radius:var(--button-radius);background:var(--button-background);color:var(--button-text-color);font-family:var(--button-font-family);font-size:var(--button-font-size);font-weight:var(--button-font-weight);line-height:1;box-shadow:var(--button-shadow);outline:none;cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap;transition:background-color .2s ease,border-color .2s ease,box-shadow .2s ease,transform .1s ease,color .2s ease}:host(.button-clickable) .balina-button{cursor:pointer}:host(:not(.button-clickable)) .balina-button{cursor:default}:host(.button-clickable) .balina-button:hover{background:var(--button-background-hover)}:host(.button-clickable) .balina-button:active{background:var(--button-background-active);transform:translateY(1px)}.balina-button:focus-visible{box-shadow:0 0 0 3px var(--button-focus-ring)}:host(.button-disabled) .balina-button{background:var(--button-disabled-background);color:var(--button-disabled-text);border-color:var(--button-disabled-border);cursor:not-allowed;box-shadow:none;transform:none}.balina-button[aria-busy=true]{cursor:wait}.button-label{display:inline-flex;align-items:center;justify-content:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.button-loading-text{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap}.button-spinner{width:var(--button-spinner-size);height:var(--button-spinner-size);flex:0 0 auto;box-sizing:border-box;border:var(--button-spinner-border) solid rgba(255,255,255,.4);border-top-color:var(--button-text-color);border-radius:50%;animation:button-spin .7s linear infinite}@keyframes button-spin{to{transform:rotate(360deg)}}@media(max-width:768px){:host{width:var(--button-width)}.balina-button{min-height:var(--button-height);font-size:var(--button-font-size)}}\n"] });
132
132
  }
133
133
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Button, decorators: [{
134
134
  type: Component,
135
- args: [{ selector: 'lib-button', standalone: true, imports: [], template: "<button\n class=\"balina-button\"\n [class]=\"customClass\"\n [type]=\"type\"\n [disabled]=\"disabled || loading\"\n [attr.aria-busy]=\"loading\"\n (click)=\"onClick($event)\"\n>\n\n @if (loading) {\n\n <span\n class=\"button-spinner\"\n aria-hidden=\"true\"\n ></span>\n\n <span>\n Loading...\n </span>\n\n } @else {\n\n <span class=\"button-label\">\n {{ label }}\n </span>\n\n }\n\n</button>", styles: [".balina-button{--button-width: auto;--button-height: 44px;--button-padding: 0 22px;--button-background: #68479b;--button-background-hover: #593b84;--button-background-active: #4b326f;--button-text-color: #ffffff;--button-border: 1px solid #68479b;--button-radius: 6px;--button-font-family: Arial, Helvetica, sans-serif;--button-font-size: 14px;--button-font-weight: 600;--button-gap: 8px;--button-shadow: 0 2px 5px rgba(0, 0, 0, .08);--button-disabled-background: #dddddd;--button-disabled-text: #999999;--button-disabled-border: #dddddd;width:var(--button-width);min-height:var(--button-height);padding:var(--button-padding);display:inline-flex;align-items:center;justify-content:center;gap:var(--button-gap);box-sizing:border-box;border:var(--button-border);border-radius:var(--button-radius);background:var(--button-background);color:var(--button-text-color);font-family:var(--button-font-family);font-size:var(--button-font-size);font-weight:var(--button-font-weight);box-shadow:var(--button-shadow);outline:none;cursor:pointer;-webkit-user-select:none;user-select:none;transition:background-color .2s ease,border-color .2s ease,box-shadow .2s ease,transform .1s ease}.balina-button:hover:not(:disabled){background:var(--button-background-hover)}.balina-button:active:not(:disabled){background:var(--button-background-active);transform:translateY(1px)}.balina-button:focus-visible{box-shadow:0 0 0 3px #68479b33}.balina-button:disabled{background:var(--button-disabled-background);color:var(--button-disabled-text);border-color:var(--button-disabled-border);cursor:not-allowed;box-shadow:none;transform:none}.balina-button[aria-busy=true]{cursor:wait}.button-spinner{width:16px;height:16px;box-sizing:border-box;border:2px solid rgba(255,255,255,.4);border-top-color:var(--button-text-color);border-radius:50%;animation:button-spin .7s linear infinite}@keyframes button-spin{to{transform:rotate(360deg)}}.button-label{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap}@media(max-width:768px){.balina-button{min-height:var(--button-height);font-size:var(--button-font-size)}}\n"] }]
135
+ args: [{ selector: 'lib-button', standalone: true, imports: [], template: "<button class=\"balina-button\" [type]=\"type\" [disabled]=\"\n disabled ||\n loading ||\n !clickable\n \" [attr.aria-disabled]=\"\n disabled ||\n loading ||\n !clickable\n \" [attr.aria-busy]=\"loading\" (click)=\"onClick($event)\">\n\n\n @if (loading) {\n\n <span class=\"button-spinner\" aria-hidden=\"true\"></span>\n\n <span class=\"button-loading-text\">\n Loading...\n </span>\n\n }\n @else {\n\n <span class=\"button-label\">\n {{ label }}\n </span>\n\n }\n\n</button>", styles: [":host{--button-width: auto;--button-height: 44px;--button-padding: 0 22px;--button-background: #68479b;--button-background-hover: #593b84;--button-background-active: #4b326f;--button-text-color: #ffffff;--button-border: 1px solid #68479b;--button-radius: 6px;--button-font-family: Arial, Helvetica, sans-serif;--button-font-size: 14px;--button-font-weight: 600;--button-gap: 8px;--button-shadow: 0 2px 5px rgba(0, 0, 0, .08);--button-disabled-background: #dddddd;--button-disabled-text: #999999;--button-disabled-border: #dddddd;--button-focus-ring: rgba(104, 71, 155, .2);--button-spinner-size: 16px;--button-spinner-border: 2px;display:inline-block;width:var(--button-width);box-sizing:border-box;font-family:var(--button-font-family)}.balina-button{width:100%;min-height:var(--button-height);padding:var(--button-padding);display:inline-flex;align-items:center;justify-content:center;gap:var(--button-gap);box-sizing:border-box;border:var(--button-border);border-radius:var(--button-radius);background:var(--button-background);color:var(--button-text-color);font-family:var(--button-font-family);font-size:var(--button-font-size);font-weight:var(--button-font-weight);line-height:1;box-shadow:var(--button-shadow);outline:none;cursor:pointer;-webkit-user-select:none;user-select:none;white-space:nowrap;transition:background-color .2s ease,border-color .2s ease,box-shadow .2s ease,transform .1s ease,color .2s ease}:host(.button-clickable) .balina-button{cursor:pointer}:host(:not(.button-clickable)) .balina-button{cursor:default}:host(.button-clickable) .balina-button:hover{background:var(--button-background-hover)}:host(.button-clickable) .balina-button:active{background:var(--button-background-active);transform:translateY(1px)}.balina-button:focus-visible{box-shadow:0 0 0 3px var(--button-focus-ring)}:host(.button-disabled) .balina-button{background:var(--button-disabled-background);color:var(--button-disabled-text);border-color:var(--button-disabled-border);cursor:not-allowed;box-shadow:none;transform:none}.balina-button[aria-busy=true]{cursor:wait}.button-label{display:inline-flex;align-items:center;justify-content:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.button-loading-text{display:inline-flex;align-items:center;justify-content:center;white-space:nowrap}.button-spinner{width:var(--button-spinner-size);height:var(--button-spinner-size);flex:0 0 auto;box-sizing:border-box;border:var(--button-spinner-border) solid rgba(255,255,255,.4);border-top-color:var(--button-text-color);border-radius:50%;animation:button-spin .7s linear infinite}@keyframes button-spin{to{transform:rotate(360deg)}}@media(max-width:768px){:host{width:var(--button-width)}.balina-button{min-height:var(--button-height);font-size:var(--button-font-size)}}\n"] }]
136
136
  }], propDecorators: { label: [{
137
137
  type: Input
138
138
  }], type: [{
@@ -141,35 +141,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
141
141
  type: Input
142
142
  }], loading: [{
143
143
  type: Input
144
+ }], clickable: [{
145
+ type: Input
144
146
  }], customClass: [{
145
147
  type: Input
148
+ }, {
149
+ type: HostBinding,
150
+ args: ['class']
151
+ }], buttonClickable: [{
152
+ type: HostBinding,
153
+ args: ['class.button-clickable']
154
+ }], buttonDisabled: [{
155
+ type: HostBinding,
156
+ args: ['class.button-disabled']
146
157
  }], clicked: [{
147
158
  type: Output
148
159
  }] } });
149
160
 
150
161
  class Card {
151
- title = 'Last 24 hours';
152
- month = 'Jul';
153
- day = 9;
154
- description = '156 flights were monitored with 96.8% on-time performance. Minor delays occurred due to weather and air traffic.';
155
- cardClick = new EventEmitter();
162
+ // INPUTS
163
+ title = '';
164
+ month = '';
165
+ day = '';
166
+ description = '';
156
167
  customClass = '';
157
- clickable = false;
168
+ clickable = true;
158
169
  disabled = false;
170
+ // OUTPUTS
171
+ cardClick = new EventEmitter();
159
172
  clicked = new EventEmitter();
173
+ // CLICK HANDLER
160
174
  onClick(event) {
161
175
  if (!this.clickable ||
162
176
  this.disabled) {
177
+ event.preventDefault();
178
+ event.stopPropagation();
163
179
  return;
164
180
  }
181
+ // Standard developer event
165
182
  this.clicked.emit(event);
183
+ // Card-specific event
184
+ this.cardClick.emit();
166
185
  }
167
186
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Card, deps: [], target: i0.ɵɵFactoryTarget.Component });
168
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: Card, isStandalone: true, selector: "lib-card", inputs: { title: "title", month: "month", day: "day", description: "description", customClass: "customClass", clickable: "clickable", disabled: "disabled" }, outputs: { cardClick: "cardClick", clicked: "clicked" }, ngImport: i0, template: "<div\n class=\"balina-card\"\n [class]=\"customClass\"\n [class.card-clickable]=\"clickable\"\n [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\"\n>\n\n <!-- Title -->\n <h2 class=\"card-title\">\n {{ title }}\n </h2>\n\n <!-- Card Content -->\n <div class=\"card-content\">\n\n <!-- Date -->\n <div class=\"card-date\">\n\n <div class=\"card-month\">\n {{ month }}\n </div>\n\n <div class=\"card-line\"></div>\n\n <div class=\"card-day\">\n {{ day }}\n </div>\n\n </div>\n\n <!-- Description -->\n <div class=\"card-description\">\n {{ description }}\n </div>\n\n </div>\n\n</div>", styles: [".balina-card{--card-width: 100%;--card-height: 280px;--card-padding: 28px;--card-background: #ffffff;--card-border: 3px solid #dddddd;--card-radius: 12px;--card-title-color: #000000;--card-description-color: #222222;--card-date-background: #eef5ff;--card-month-color: #2962ff;--card-line-color: #b7b7b7;--card-title-size: 38px;--card-description-size: 20px;--card-month-size: 24px;--card-day-size: 24px;--card-font-family: Arial, Helvetica, sans-serif;width:var(--card-width);min-height:var(--card-height);box-sizing:border-box;padding:var(--card-padding);background:var(--card-background);border:var(--card-border);border-radius:var(--card-radius);font-family:var(--card-font-family);cursor:pointer;transition:box-shadow .2s ease,transform .2s ease}.balina-card:hover{box-shadow:0 4px 12px #00000014;transform:translateY(-1px)}.card-title{margin:0;color:var(--card-title-color);font-size:var(--card-title-size);font-weight:700;line-height:1.2}.card-content{display:flex;align-items:center;gap:28px;margin-top:36px}.card-date{width:92px;height:96px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;padding:8px;background:var(--card-date-background);border-radius:10px}.card-month{color:var(--card-month-color);font-size:var(--card-month-size);font-weight:700;line-height:1}.card-line{width:80%;height:2px;margin:7px 0;background:var(--card-line-color)}.card-day{color:#000;font-size:var(--card-day-size);font-weight:600;line-height:1}.card-description{flex:1;color:var(--card-description-color);font-size:var(--card-description-size);font-weight:600;line-height:1.4}@media(max-width:768px){.balina-card{--card-title-size: 30px;--card-description-size: 17px;--card-height: auto;padding:22px}.card-content{gap:18px;margin-top:28px}.card-date{width:80px;height:88px}}@media(max-width:480px){.balina-card{--card-title-size: 26px;--card-description-size: 15px;padding:18px}.card-content{align-items:flex-start;gap:14px}.card-date{width:70px;height:80px}.card-month,.card-day{font-size:20px}}\n"] });
187
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: Card, isStandalone: true, selector: "lib-card", inputs: { title: "title", month: "month", day: "day", description: "description", customClass: "customClass", clickable: "clickable", disabled: "disabled" }, outputs: { cardClick: "cardClick", clicked: "clicked" }, ngImport: i0, template: "<div class=\"balina-card\" [class]=\"customClass\" [class.card-clickable]=\"clickable\" [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\">\n\n\n <h2 class=\"card-title\">\n {{ title }}\n </h2>\n\n\n <div class=\"card-content\">\n\n <div class=\"card-date\">\n\n <div class=\"card-month\">\n {{ month }}\n </div>\n\n <div class=\"card-line\"></div>\n\n <div class=\"card-day\">\n {{ day }}\n </div>\n\n </div>\n\n\n <div class=\"card-description\">\n\n {{ description }}\n\n </div>\n\n </div>\n\n</div>", styles: [".balina-card{--card-width: 100%;--card-height: 280px;--card-padding: 28px;--card-background: #ffffff;--card-border: 3px solid #dddddd;--card-radius: 12px;--card-title-color: #000000;--card-description-color: #222222;--card-date-background: #eef5ff;--card-month-color: #2962ff;--card-day-color: #000000;--card-line-color: #b7b7b7;--card-title-size: 38px;--card-description-size: 20px;--card-month-size: 24px;--card-day-size: 24px;--card-font-family: Arial, Helvetica, sans-serif;--card-font-weight: 600;--card-hover-shadow: 0 4px 12px rgba(0, 0, 0, .08);--card-hover-transform: translateY(-1px);--card-disabled-background: #f5f5f5;--card-disabled-border: #d0d0d0;--card-disabled-text: #999999;width:var(--card-width);min-height:var(--card-height);padding:var(--card-padding);background:var(--card-background);border:var(--card-border);border-radius:var(--card-radius);font-family:var(--card-font-family);font-weight:var(--card-font-weight);transition:box-shadow .2s ease,transform .2s ease,background-color .2s ease,border-color .2s ease;box-sizing:border-box}.balina-card.card-clickable{cursor:pointer}.balina-card:not(.card-clickable){cursor:default}.balina-card.card-clickable:hover{box-shadow:var(--card-hover-shadow);transform:var(--card-hover-transform)}.balina-card.card-clickable:active{transform:translateY(0)}.card-title{margin:0;color:var(--card-title-color);font-size:var(--card-title-size);font-weight:700;line-height:1.2}.card-content{display:flex;align-items:center;gap:28px;margin-top:36px}.card-date{width:92px;height:96px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;padding:8px;background:var(--card-date-background);border-radius:10px}.card-month{color:var(--card-month-color);font-size:var(--card-month-size);font-weight:700;line-height:1}.card-line{width:80%;height:2px;margin:7px 0;background:var(--card-line-color)}.card-day{color:var(--card-day-color);font-size:var(--card-day-size);font-weight:600;line-height:1}.card-description{flex:1;color:var(--card-description-color);font-size:var(--card-description-size);font-weight:600;line-height:1.4}.balina-card.card-disabled{background:var(--card-disabled-background);border-color:var(--card-disabled-border);color:var(--card-disabled-text);cursor:not-allowed;box-shadow:none;transform:none}.balina-card.card-disabled:hover{box-shadow:none;transform:none}.balina-card.card-disabled .card-title,.balina-card.card-disabled .card-description{color:var(--card-disabled-text)}@media(max-width:768px){.balina-card{--card-title-size: 30px;--card-description-size: 17px;--card-height: auto;padding:22px}.card-content{gap:18px;margin-top:28px}.card-date{width:80px;height:88px}}@media(max-width:480px){.balina-card{--card-title-size: 26px;--card-description-size: 15px;padding:18px}.card-content{align-items:flex-start;gap:14px}.card-date{width:70px;height:80px}.card-month,.card-day{font-size:20px}}\n"] });
169
188
  }
170
189
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Card, decorators: [{
171
190
  type: Component,
172
- args: [{ selector: 'lib-card', standalone: true, imports: [], template: "<div\n class=\"balina-card\"\n [class]=\"customClass\"\n [class.card-clickable]=\"clickable\"\n [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\"\n>\n\n <!-- Title -->\n <h2 class=\"card-title\">\n {{ title }}\n </h2>\n\n <!-- Card Content -->\n <div class=\"card-content\">\n\n <!-- Date -->\n <div class=\"card-date\">\n\n <div class=\"card-month\">\n {{ month }}\n </div>\n\n <div class=\"card-line\"></div>\n\n <div class=\"card-day\">\n {{ day }}\n </div>\n\n </div>\n\n <!-- Description -->\n <div class=\"card-description\">\n {{ description }}\n </div>\n\n </div>\n\n</div>", styles: [".balina-card{--card-width: 100%;--card-height: 280px;--card-padding: 28px;--card-background: #ffffff;--card-border: 3px solid #dddddd;--card-radius: 12px;--card-title-color: #000000;--card-description-color: #222222;--card-date-background: #eef5ff;--card-month-color: #2962ff;--card-line-color: #b7b7b7;--card-title-size: 38px;--card-description-size: 20px;--card-month-size: 24px;--card-day-size: 24px;--card-font-family: Arial, Helvetica, sans-serif;width:var(--card-width);min-height:var(--card-height);box-sizing:border-box;padding:var(--card-padding);background:var(--card-background);border:var(--card-border);border-radius:var(--card-radius);font-family:var(--card-font-family);cursor:pointer;transition:box-shadow .2s ease,transform .2s ease}.balina-card:hover{box-shadow:0 4px 12px #00000014;transform:translateY(-1px)}.card-title{margin:0;color:var(--card-title-color);font-size:var(--card-title-size);font-weight:700;line-height:1.2}.card-content{display:flex;align-items:center;gap:28px;margin-top:36px}.card-date{width:92px;height:96px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;padding:8px;background:var(--card-date-background);border-radius:10px}.card-month{color:var(--card-month-color);font-size:var(--card-month-size);font-weight:700;line-height:1}.card-line{width:80%;height:2px;margin:7px 0;background:var(--card-line-color)}.card-day{color:#000;font-size:var(--card-day-size);font-weight:600;line-height:1}.card-description{flex:1;color:var(--card-description-color);font-size:var(--card-description-size);font-weight:600;line-height:1.4}@media(max-width:768px){.balina-card{--card-title-size: 30px;--card-description-size: 17px;--card-height: auto;padding:22px}.card-content{gap:18px;margin-top:28px}.card-date{width:80px;height:88px}}@media(max-width:480px){.balina-card{--card-title-size: 26px;--card-description-size: 15px;padding:18px}.card-content{align-items:flex-start;gap:14px}.card-date{width:70px;height:80px}.card-month,.card-day{font-size:20px}}\n"] }]
191
+ args: [{ selector: 'lib-card', standalone: true, imports: [], template: "<div class=\"balina-card\" [class]=\"customClass\" [class.card-clickable]=\"clickable\" [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\">\n\n\n <h2 class=\"card-title\">\n {{ title }}\n </h2>\n\n\n <div class=\"card-content\">\n\n <div class=\"card-date\">\n\n <div class=\"card-month\">\n {{ month }}\n </div>\n\n <div class=\"card-line\"></div>\n\n <div class=\"card-day\">\n {{ day }}\n </div>\n\n </div>\n\n\n <div class=\"card-description\">\n\n {{ description }}\n\n </div>\n\n </div>\n\n</div>", styles: [".balina-card{--card-width: 100%;--card-height: 280px;--card-padding: 28px;--card-background: #ffffff;--card-border: 3px solid #dddddd;--card-radius: 12px;--card-title-color: #000000;--card-description-color: #222222;--card-date-background: #eef5ff;--card-month-color: #2962ff;--card-day-color: #000000;--card-line-color: #b7b7b7;--card-title-size: 38px;--card-description-size: 20px;--card-month-size: 24px;--card-day-size: 24px;--card-font-family: Arial, Helvetica, sans-serif;--card-font-weight: 600;--card-hover-shadow: 0 4px 12px rgba(0, 0, 0, .08);--card-hover-transform: translateY(-1px);--card-disabled-background: #f5f5f5;--card-disabled-border: #d0d0d0;--card-disabled-text: #999999;width:var(--card-width);min-height:var(--card-height);padding:var(--card-padding);background:var(--card-background);border:var(--card-border);border-radius:var(--card-radius);font-family:var(--card-font-family);font-weight:var(--card-font-weight);transition:box-shadow .2s ease,transform .2s ease,background-color .2s ease,border-color .2s ease;box-sizing:border-box}.balina-card.card-clickable{cursor:pointer}.balina-card:not(.card-clickable){cursor:default}.balina-card.card-clickable:hover{box-shadow:var(--card-hover-shadow);transform:var(--card-hover-transform)}.balina-card.card-clickable:active{transform:translateY(0)}.card-title{margin:0;color:var(--card-title-color);font-size:var(--card-title-size);font-weight:700;line-height:1.2}.card-content{display:flex;align-items:center;gap:28px;margin-top:36px}.card-date{width:92px;height:96px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;padding:8px;background:var(--card-date-background);border-radius:10px}.card-month{color:var(--card-month-color);font-size:var(--card-month-size);font-weight:700;line-height:1}.card-line{width:80%;height:2px;margin:7px 0;background:var(--card-line-color)}.card-day{color:var(--card-day-color);font-size:var(--card-day-size);font-weight:600;line-height:1}.card-description{flex:1;color:var(--card-description-color);font-size:var(--card-description-size);font-weight:600;line-height:1.4}.balina-card.card-disabled{background:var(--card-disabled-background);border-color:var(--card-disabled-border);color:var(--card-disabled-text);cursor:not-allowed;box-shadow:none;transform:none}.balina-card.card-disabled:hover{box-shadow:none;transform:none}.balina-card.card-disabled .card-title,.balina-card.card-disabled .card-description{color:var(--card-disabled-text)}@media(max-width:768px){.balina-card{--card-title-size: 30px;--card-description-size: 17px;--card-height: auto;padding:22px}.card-content{gap:18px;margin-top:28px}.card-date{width:80px;height:88px}}@media(max-width:480px){.balina-card{--card-title-size: 26px;--card-description-size: 15px;padding:18px}.card-content{align-items:flex-start;gap:14px}.card-date{width:70px;height:80px}.card-month,.card-day{font-size:20px}}\n"] }]
173
192
  }], propDecorators: { title: [{
174
193
  type: Input
175
194
  }], month: [{
@@ -178,51 +197,81 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
178
197
  type: Input
179
198
  }], description: [{
180
199
  type: Input
181
- }], cardClick: [{
182
- type: Output
183
200
  }], customClass: [{
184
201
  type: Input
185
202
  }], clickable: [{
186
203
  type: Input
187
204
  }], disabled: [{
188
205
  type: Input
206
+ }], cardClick: [{
207
+ type: Output
189
208
  }], clicked: [{
190
209
  type: Output
191
210
  }] } });
192
211
 
193
212
  class TimeFilter {
213
+ // INPUTS
194
214
  label = '';
195
- value;
196
- selectedValue = '';
215
+ value = '';
216
+ selectedValue = null;
217
+ customClass = '';
218
+ clickable = true;
219
+ disabled = false;
220
+ // OUTPUTS
197
221
  selectedValueChange = new EventEmitter();
198
222
  clicked = new EventEmitter();
223
+ // INTERNAL STATE
224
+ internalSelected = false;
225
+ // SELECTED STATE
199
226
  get selected() {
200
- return this.value === this.selectedValue;
227
+ if (this.selectedValue !== null &&
228
+ this.selectedValue !== undefined) {
229
+ return this.value === this.selectedValue;
230
+ }
231
+ return this.internalSelected;
201
232
  }
233
+ // CLICK
202
234
  onClick(event) {
203
- // If already selected → unselect
235
+ if (this.disabled ||
236
+ !this.clickable) {
237
+ return;
238
+ }
239
+ // INDEPENDENT MODE
240
+ if (this.selectedValue === null ||
241
+ this.selectedValue === undefined) {
242
+ this.internalSelected =
243
+ !this.internalSelected;
244
+ this.clicked.emit(event);
245
+ return;
246
+ }
247
+ // CONNECTED / GROUP MODE
204
248
  if (this.selected) {
205
249
  this.selectedValueChange.emit('');
206
250
  }
207
- // If not selected → select
208
251
  else {
209
252
  this.selectedValueChange.emit(this.value);
210
253
  }
211
- // Developer custom event
254
+ // DEVELOPER CLICK EVENT
212
255
  this.clicked.emit(event);
213
256
  }
214
257
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: TimeFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
215
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: TimeFilter, isStandalone: true, selector: "lib-time-filter", inputs: { label: "label", value: "value", selectedValue: "selectedValue" }, outputs: { selectedValueChange: "selectedValueChange", clicked: "clicked" }, ngImport: i0, template: "<div class=\"time-filter\" (click)=\"onClick($event)\" role=\"button\" tabindex=\"0\">\n <div class=\"radio-circle\" [class.selected]=\"selected\">\n <div class=\"radio-dot\"></div>\n </div>\n\n <span class=\"label\">\n {{ label }}\n </span>\n</div>", styles: [".time-filter{display:flex;align-items:center;gap:16px;width:fit-content;cursor:pointer;-webkit-user-select:none;user-select:none}.radio-circle{width:24px;height:24px;border:2px solid #a6a6a6;border-radius:50%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;transition:border-color .2s ease}.radio-dot{width:12px;height:12px;border-radius:50%;background:transparent;transition:background .2s ease}.radio-circle.selected{border-color:#1976d2}.radio-circle.selected .radio-dot{background:#1976d2}.label{font-size:20px;font-weight:400;color:#000;line-height:1}.label:hover{color:#333}\n"] });
258
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: TimeFilter, isStandalone: true, selector: "lib-time-filter", inputs: { label: "label", value: "value", selectedValue: "selectedValue", customClass: "customClass", clickable: "clickable", disabled: "disabled" }, outputs: { selectedValueChange: "selectedValueChange", clicked: "clicked" }, ngImport: i0, template: "<div class=\"time-filter\" [class]=\"customClass\" [class.time-filter-clickable]=\"clickable\"\n [class.time-filter-disabled]=\"disabled\" [class.time-filter-selected]=\"selected\" (click)=\"onClick($event)\"\n role=\"button\" tabindex=\"0\">\n\n\n <div class=\"radio-circle\" [class.selected]=\"selected\">\n\n <div class=\"radio-dot\"></div>\n\n </div>\n\n\n <span class=\"label\">\n {{ label }}\n </span>\n\n</div>", styles: [".time-filter{--time-filter-gap: 16px;--time-filter-circle-size: 24px;--time-filter-circle-border-width: 2px;--time-filter-dot-size: 12px;--time-filter-border-color: #a6a6a6;--time-filter-selected-color: #1976d2;--time-filter-text-color: #000000;--time-filter-text-hover: #333333;--time-filter-font-family: Arial, Helvetica, sans-serif;--time-filter-font-size: 20px;--time-filter-font-weight: 400;--time-filter-disabled-color: #aaaaaa;display:flex;align-items:center;gap:var(--time-filter-gap);width:fit-content;box-sizing:border-box;font-family:var(--time-filter-font-family);-webkit-user-select:none;user-select:none;transition:opacity .2s ease}.time-filter-clickable{cursor:pointer}.radio-circle{width:var(--time-filter-circle-size);height:var(--time-filter-circle-size);flex-shrink:0;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border:var(--time-filter-circle-border-width) solid var(--time-filter-border-color);border-radius:50%;transition:border-color .2s ease,background-color .2s ease}.radio-dot{width:var(--time-filter-dot-size);height:var(--time-filter-dot-size);border-radius:50%;background:transparent;transition:background-color .2s ease,transform .2s ease}.radio-circle.selected{border-color:var(--time-filter-selected-color)}.radio-circle.selected .radio-dot{background:var(--time-filter-selected-color);transform:scale(1)}.label{color:var(--time-filter-text-color);font-size:var(--time-filter-font-size);font-weight:var(--time-filter-font-weight);line-height:1;transition:color .2s ease}.time-filter-clickable:hover .label{color:var(--time-filter-text-hover)}.time-filter-clickable:hover .radio-circle{border-color:var(--time-filter-selected-color)}.time-filter-disabled{opacity:.6;cursor:not-allowed}.time-filter-disabled .radio-circle{border-color:var(--time-filter-disabled-color)}.time-filter-disabled .label{color:var(--time-filter-disabled-color)}.time-filter-disabled .radio-circle.selected{border-color:var(--time-filter-disabled-color)}.time-filter-disabled .radio-circle.selected .radio-dot{background:var(--time-filter-disabled-color)}@media(max-width:768px){.time-filter{--time-filter-font-size: 18px;--time-filter-circle-size: 22px;--time-filter-dot-size: 10px;--time-filter-gap: 12px}}@media(max-width:480px){.time-filter{--time-filter-font-size: 16px;--time-filter-circle-size: 20px;--time-filter-dot-size: 9px;--time-filter-gap: 10px}}\n"] });
216
259
  }
217
260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: TimeFilter, decorators: [{
218
261
  type: Component,
219
- args: [{ selector: 'lib-time-filter', standalone: true, imports: [], template: "<div class=\"time-filter\" (click)=\"onClick($event)\" role=\"button\" tabindex=\"0\">\n <div class=\"radio-circle\" [class.selected]=\"selected\">\n <div class=\"radio-dot\"></div>\n </div>\n\n <span class=\"label\">\n {{ label }}\n </span>\n</div>", styles: [".time-filter{display:flex;align-items:center;gap:16px;width:fit-content;cursor:pointer;-webkit-user-select:none;user-select:none}.radio-circle{width:24px;height:24px;border:2px solid #a6a6a6;border-radius:50%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;transition:border-color .2s ease}.radio-dot{width:12px;height:12px;border-radius:50%;background:transparent;transition:background .2s ease}.radio-circle.selected{border-color:#1976d2}.radio-circle.selected .radio-dot{background:#1976d2}.label{font-size:20px;font-weight:400;color:#000;line-height:1}.label:hover{color:#333}\n"] }]
262
+ args: [{ selector: 'lib-time-filter', standalone: true, imports: [], template: "<div class=\"time-filter\" [class]=\"customClass\" [class.time-filter-clickable]=\"clickable\"\n [class.time-filter-disabled]=\"disabled\" [class.time-filter-selected]=\"selected\" (click)=\"onClick($event)\"\n role=\"button\" tabindex=\"0\">\n\n\n <div class=\"radio-circle\" [class.selected]=\"selected\">\n\n <div class=\"radio-dot\"></div>\n\n </div>\n\n\n <span class=\"label\">\n {{ label }}\n </span>\n\n</div>", styles: [".time-filter{--time-filter-gap: 16px;--time-filter-circle-size: 24px;--time-filter-circle-border-width: 2px;--time-filter-dot-size: 12px;--time-filter-border-color: #a6a6a6;--time-filter-selected-color: #1976d2;--time-filter-text-color: #000000;--time-filter-text-hover: #333333;--time-filter-font-family: Arial, Helvetica, sans-serif;--time-filter-font-size: 20px;--time-filter-font-weight: 400;--time-filter-disabled-color: #aaaaaa;display:flex;align-items:center;gap:var(--time-filter-gap);width:fit-content;box-sizing:border-box;font-family:var(--time-filter-font-family);-webkit-user-select:none;user-select:none;transition:opacity .2s ease}.time-filter-clickable{cursor:pointer}.radio-circle{width:var(--time-filter-circle-size);height:var(--time-filter-circle-size);flex-shrink:0;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border:var(--time-filter-circle-border-width) solid var(--time-filter-border-color);border-radius:50%;transition:border-color .2s ease,background-color .2s ease}.radio-dot{width:var(--time-filter-dot-size);height:var(--time-filter-dot-size);border-radius:50%;background:transparent;transition:background-color .2s ease,transform .2s ease}.radio-circle.selected{border-color:var(--time-filter-selected-color)}.radio-circle.selected .radio-dot{background:var(--time-filter-selected-color);transform:scale(1)}.label{color:var(--time-filter-text-color);font-size:var(--time-filter-font-size);font-weight:var(--time-filter-font-weight);line-height:1;transition:color .2s ease}.time-filter-clickable:hover .label{color:var(--time-filter-text-hover)}.time-filter-clickable:hover .radio-circle{border-color:var(--time-filter-selected-color)}.time-filter-disabled{opacity:.6;cursor:not-allowed}.time-filter-disabled .radio-circle{border-color:var(--time-filter-disabled-color)}.time-filter-disabled .label{color:var(--time-filter-disabled-color)}.time-filter-disabled .radio-circle.selected{border-color:var(--time-filter-disabled-color)}.time-filter-disabled .radio-circle.selected .radio-dot{background:var(--time-filter-disabled-color)}@media(max-width:768px){.time-filter{--time-filter-font-size: 18px;--time-filter-circle-size: 22px;--time-filter-dot-size: 10px;--time-filter-gap: 12px}}@media(max-width:480px){.time-filter{--time-filter-font-size: 16px;--time-filter-circle-size: 20px;--time-filter-dot-size: 9px;--time-filter-gap: 10px}}\n"] }]
220
263
  }], propDecorators: { label: [{
221
264
  type: Input
222
265
  }], value: [{
223
266
  type: Input
224
267
  }], selectedValue: [{
225
268
  type: Input
269
+ }], customClass: [{
270
+ type: Input
271
+ }], clickable: [{
272
+ type: Input
273
+ }], disabled: [{
274
+ type: Input
226
275
  }], selectedValueChange: [{
227
276
  type: Output
228
277
  }], clicked: [{
@@ -230,50 +279,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
230
279
  }] } });
231
280
 
232
281
  class TextBox {
233
- // =========================================
234
282
  // INPUTS
235
- // =========================================
236
283
  placeholder = '';
237
284
  value = '';
238
285
  type = 'text';
239
286
  disabled = false;
240
287
  readonly = false;
241
- /**
242
- * Developer custom CSS class.
243
- *
244
- * Example:
245
- *
246
- * customClass="flight-input"
247
- */
248
288
  customClass = '';
249
- // =========================================
250
289
  // OUTPUT EVENTS
251
- // =========================================
252
- /**
253
- * Emits the current value.
254
- */
255
290
  valueChange = new EventEmitter();
256
- /**
257
- * Emits whenever the user types.
258
- */
259
291
  inputChange = new EventEmitter();
260
- /**
261
- * Emits whenever the textbox is clicked.
262
- */
263
292
  clicked = new EventEmitter();
264
- // =========================================
265
293
  // PASSWORD VISIBILITY
266
- // =========================================
267
- /**
268
- * Controls password visibility.
269
- */
270
294
  showPassword = false;
271
- /**
272
- * Returns the actual input type.
273
- *
274
- * password + showPassword
275
- * becomes text.
276
- */
277
295
  get inputType() {
278
296
  if (this.type === 'password') {
279
297
  return this.showPassword
@@ -290,9 +308,7 @@ class TextBox {
290
308
  this.showPassword =
291
309
  !this.showPassword;
292
310
  }
293
- // =========================================
294
311
  // INPUT HANDLER
295
- // =========================================
296
312
  onInput(event) {
297
313
  const input = event.target;
298
314
  this.value = input.value;
@@ -301,18 +317,16 @@ class TextBox {
301
317
  // Emit input event
302
318
  this.inputChange.emit(this.value);
303
319
  }
304
- // =========================================
305
320
  // CLICK HANDLER
306
- // =========================================
307
321
  onClick(event) {
308
322
  this.clicked.emit(event);
309
323
  }
310
324
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: TextBox, deps: [], target: i0.ɵɵFactoryTarget.Component });
311
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: TextBox, isStandalone: true, selector: "lib-text-box", inputs: { placeholder: "placeholder", value: "value", type: "type", disabled: "disabled", readonly: "readonly", customClass: "customClass" }, outputs: { valueChange: "valueChange", inputChange: "inputChange", clicked: "clicked" }, host: { properties: { "class": "this.customClass" } }, ngImport: i0, template: "<div class=\"text-box-container\">\n\n <div class=\"text-box-input-wrapper\">\n\n <input\n class=\"text-box-input\"\n\n [type]=\"inputType\"\n\n [placeholder]=\"placeholder\"\n\n [value]=\"value\"\n\n [disabled]=\"disabled\"\n\n [readonly]=\"readonly\"\n\n (input)=\"onInput($event)\"\n\n (click)=\"onClick($event)\"\n />\n\n <!-- Password Eye Button -->\n @if (type === 'password') {\n\n <button\n type=\"button\"\n class=\"text-box-password-button\"\n\n [disabled]=\"disabled\"\n\n (click)=\"togglePassword($event)\"\n aria-label=\"Toggle password visibility\"\n >\n\n @if (showPassword) {\n\n <!-- Eye Off -->\n <svg\n class=\"text-box-password-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path\n d=\"M3 3l18 18\"\n />\n\n <path\n d=\"M10.6 10.6a2 2 0 1 0 2.8 2.8\"\n />\n\n <path\n d=\"M9.9 4.2A10.8 10.8 0 0 1 12 4c5 0 8.7 4.2 9.8 8a10.8 10.8 0 0 1-3.1 5.1\"\n />\n\n <path\n d=\"M6.2 6.2C4.5 7.4 3.2 9.2 2.2 12c1.1 3.8 4.8 8 9.8 8 1.7 0 3.3-.5 4.7-1.2\"\n />\n </svg>\n\n } @else {\n\n <!-- Eye -->\n <svg\n class=\"text-box-password-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path\n d=\"M2 12s3.5-7 10-7\n 10 7 10 7\n -3.5 7-10 7\n -10-7-10-7z\"\n />\n\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"3\"\n />\n </svg>\n\n }\n\n </button>\n\n }\n\n </div>\n\n</div>", styles: [":host{--textbox-width: 300px;--textbox-height: 44px;--textbox-background: #ffffff;--textbox-border: 1px solid #a9a9a9;--textbox-border-hover: #777777;--textbox-border-focus: #68479b;--textbox-radius: 6px;--textbox-text-color: #222222;--textbox-placeholder-color: #777777;--textbox-font-family: Arial, Helvetica, sans-serif;--textbox-font-size: 14px;--textbox-font-weight: 600;--textbox-padding: 0 18px;--textbox-focus-shadow: 0 0 0 1px rgba(104, 71, 155, .15);--textbox-disabled-background: #f5f5f5;--textbox-disabled-color: #999999;--textbox-disabled-border: #d0d0d0;--textbox-icon-color: #777777;--textbox-icon-hover-color: #333333;display:block;width:var(--textbox-width);height:var(--textbox-height);box-sizing:border-box}.text-box-container{width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input-wrapper{position:relative;width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input{width:100%;height:100%;box-sizing:border-box;padding:var(--textbox-padding);border:var(--textbox-border);border-radius:var(--textbox-radius);outline:none;background:var(--textbox-background);color:var(--textbox-text-color);font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight);transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease;cursor:text}.text-box-input[type=password]{padding-right:48px}.text-box-input::placeholder{color:var(--textbox-placeholder-color);opacity:1;font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight)}.text-box-input:hover:not(:disabled){border-color:var(--textbox-border-hover)}.text-box-input:focus{border-color:var(--textbox-border-focus);box-shadow:var(--textbox-focus-shadow)}.text-box-input:disabled{background:var(--textbox-disabled-background);color:var(--textbox-disabled-color);border-color:var(--textbox-disabled-border);cursor:not-allowed}.text-box-input:read-only{cursor:default}.text-box-password-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--textbox-icon-color);cursor:pointer;border-radius:4px;transition:color .2s ease,background-color .2s ease}.text-box-password-button:hover:not(:disabled){color:var(--textbox-icon-hover-color);background:#0000000d}.text-box-password-button:disabled{cursor:not-allowed;opacity:.5}.text-box-password-icon{width:19px;height:19px;display:block}@media(max-width:768px){:host{width:100%}.text-box-input{font-size:var(--textbox-font-size)}}\n"] });
325
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: TextBox, isStandalone: true, selector: "lib-text-box", inputs: { placeholder: "placeholder", value: "value", type: "type", disabled: "disabled", readonly: "readonly", customClass: "customClass" }, outputs: { valueChange: "valueChange", inputChange: "inputChange", clicked: "clicked" }, host: { properties: { "class": "this.customClass" } }, ngImport: i0, template: "<div class=\"text-box-container\">\n\n <div class=\"text-box-input-wrapper\">\n\n <input class=\"text-box-input\" [type]=\"inputType\" [placeholder]=\"placeholder\" [value]=\"value\" [disabled]=\"disabled\"\n [readonly]=\"readonly\" (input)=\"onInput($event)\" (click)=\"onClick($event)\" />\n\n <!-- Password Eye Button -->\n @if (type === 'password') {\n\n <button type=\"button\" class=\"text-box-password-button\" [disabled]=\"disabled\" (click)=\"togglePassword($event)\"\n aria-label=\"Toggle password visibility\">\n\n @if (showPassword) {\n\n <!-- Eye Off -->\n <svg class=\"text-box-password-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3 3l18 18\" />\n\n <path d=\"M10.6 10.6a2 2 0 1 0 2.8 2.8\" />\n\n <path d=\"M9.9 4.2A10.8 10.8 0 0 1 12 4c5 0 8.7 4.2 9.8 8a10.8 10.8 0 0 1-3.1 5.1\" />\n\n <path d=\"M6.2 6.2C4.5 7.4 3.2 9.2 2.2 12c1.1 3.8 4.8 8 9.8 8 1.7 0 3.3-.5 4.7-1.2\" />\n </svg>\n\n } @else {\n\n <!-- Eye -->\n <svg class=\"text-box-password-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M2 12s3.5-7 10-7\n 10 7 10 7\n -3.5 7-10 7\n -10-7-10-7z\" />\n\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n\n }\n\n </button>\n\n }\n\n </div>\n\n</div>", styles: [":host{--textbox-width: 300px;--textbox-height: 44px;--textbox-background: #ffffff;--textbox-border: 1px solid #a9a9a9;--textbox-border-hover: #777777;--textbox-border-focus: #68479b;--textbox-radius: 6px;--textbox-text-color: #222222;--textbox-placeholder-color: #777777;--textbox-font-family: Arial, Helvetica, sans-serif;--textbox-font-size: 14px;--textbox-font-weight: 600;--textbox-padding: 0 18px;--textbox-focus-shadow: 0 0 0 1px rgba(104, 71, 155, .15);--textbox-disabled-background: #f5f5f5;--textbox-disabled-color: #999999;--textbox-disabled-border: #d0d0d0;--textbox-icon-color: #777777;--textbox-icon-hover-color: #333333;display:block;width:var(--textbox-width);height:var(--textbox-height);box-sizing:border-box}.text-box-container{width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input-wrapper{position:relative;width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input{width:100%;height:100%;box-sizing:border-box;padding:var(--textbox-padding);border:var(--textbox-border);border-radius:var(--textbox-radius);outline:none;background:var(--textbox-background);color:var(--textbox-text-color);font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight);transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease;cursor:text}.text-box-input[type=password]{padding-right:48px}.text-box-input::placeholder{color:var(--textbox-placeholder-color);opacity:1;font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight)}.text-box-input:hover:not(:disabled){border-color:var(--textbox-border-hover)}.text-box-input:focus{border-color:var(--textbox-border-focus);box-shadow:var(--textbox-focus-shadow)}.text-box-input:disabled{background:var(--textbox-disabled-background);color:var(--textbox-disabled-color);border-color:var(--textbox-disabled-border);cursor:not-allowed}.text-box-input:read-only{cursor:default}.text-box-password-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--textbox-icon-color);cursor:pointer;border-radius:4px;transition:color .2s ease,background-color .2s ease}.text-box-password-button:hover:not(:disabled){color:var(--textbox-icon-hover-color);background:#0000000d}.text-box-password-button:disabled{cursor:not-allowed;opacity:.5}.text-box-password-icon{width:19px;height:19px;display:block}@media(max-width:768px){:host{width:100%}.text-box-input{font-size:var(--textbox-font-size)}}\n"] });
312
326
  }
313
327
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: TextBox, decorators: [{
314
328
  type: Component,
315
- args: [{ selector: 'lib-text-box', standalone: true, imports: [], template: "<div class=\"text-box-container\">\n\n <div class=\"text-box-input-wrapper\">\n\n <input\n class=\"text-box-input\"\n\n [type]=\"inputType\"\n\n [placeholder]=\"placeholder\"\n\n [value]=\"value\"\n\n [disabled]=\"disabled\"\n\n [readonly]=\"readonly\"\n\n (input)=\"onInput($event)\"\n\n (click)=\"onClick($event)\"\n />\n\n <!-- Password Eye Button -->\n @if (type === 'password') {\n\n <button\n type=\"button\"\n class=\"text-box-password-button\"\n\n [disabled]=\"disabled\"\n\n (click)=\"togglePassword($event)\"\n aria-label=\"Toggle password visibility\"\n >\n\n @if (showPassword) {\n\n <!-- Eye Off -->\n <svg\n class=\"text-box-password-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path\n d=\"M3 3l18 18\"\n />\n\n <path\n d=\"M10.6 10.6a2 2 0 1 0 2.8 2.8\"\n />\n\n <path\n d=\"M9.9 4.2A10.8 10.8 0 0 1 12 4c5 0 8.7 4.2 9.8 8a10.8 10.8 0 0 1-3.1 5.1\"\n />\n\n <path\n d=\"M6.2 6.2C4.5 7.4 3.2 9.2 2.2 12c1.1 3.8 4.8 8 9.8 8 1.7 0 3.3-.5 4.7-1.2\"\n />\n </svg>\n\n } @else {\n\n <!-- Eye -->\n <svg\n class=\"text-box-password-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path\n d=\"M2 12s3.5-7 10-7\n 10 7 10 7\n -3.5 7-10 7\n -10-7-10-7z\"\n />\n\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"3\"\n />\n </svg>\n\n }\n\n </button>\n\n }\n\n </div>\n\n</div>", styles: [":host{--textbox-width: 300px;--textbox-height: 44px;--textbox-background: #ffffff;--textbox-border: 1px solid #a9a9a9;--textbox-border-hover: #777777;--textbox-border-focus: #68479b;--textbox-radius: 6px;--textbox-text-color: #222222;--textbox-placeholder-color: #777777;--textbox-font-family: Arial, Helvetica, sans-serif;--textbox-font-size: 14px;--textbox-font-weight: 600;--textbox-padding: 0 18px;--textbox-focus-shadow: 0 0 0 1px rgba(104, 71, 155, .15);--textbox-disabled-background: #f5f5f5;--textbox-disabled-color: #999999;--textbox-disabled-border: #d0d0d0;--textbox-icon-color: #777777;--textbox-icon-hover-color: #333333;display:block;width:var(--textbox-width);height:var(--textbox-height);box-sizing:border-box}.text-box-container{width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input-wrapper{position:relative;width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input{width:100%;height:100%;box-sizing:border-box;padding:var(--textbox-padding);border:var(--textbox-border);border-radius:var(--textbox-radius);outline:none;background:var(--textbox-background);color:var(--textbox-text-color);font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight);transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease;cursor:text}.text-box-input[type=password]{padding-right:48px}.text-box-input::placeholder{color:var(--textbox-placeholder-color);opacity:1;font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight)}.text-box-input:hover:not(:disabled){border-color:var(--textbox-border-hover)}.text-box-input:focus{border-color:var(--textbox-border-focus);box-shadow:var(--textbox-focus-shadow)}.text-box-input:disabled{background:var(--textbox-disabled-background);color:var(--textbox-disabled-color);border-color:var(--textbox-disabled-border);cursor:not-allowed}.text-box-input:read-only{cursor:default}.text-box-password-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--textbox-icon-color);cursor:pointer;border-radius:4px;transition:color .2s ease,background-color .2s ease}.text-box-password-button:hover:not(:disabled){color:var(--textbox-icon-hover-color);background:#0000000d}.text-box-password-button:disabled{cursor:not-allowed;opacity:.5}.text-box-password-icon{width:19px;height:19px;display:block}@media(max-width:768px){:host{width:100%}.text-box-input{font-size:var(--textbox-font-size)}}\n"] }]
329
+ args: [{ selector: 'lib-text-box', standalone: true, imports: [], template: "<div class=\"text-box-container\">\n\n <div class=\"text-box-input-wrapper\">\n\n <input class=\"text-box-input\" [type]=\"inputType\" [placeholder]=\"placeholder\" [value]=\"value\" [disabled]=\"disabled\"\n [readonly]=\"readonly\" (input)=\"onInput($event)\" (click)=\"onClick($event)\" />\n\n <!-- Password Eye Button -->\n @if (type === 'password') {\n\n <button type=\"button\" class=\"text-box-password-button\" [disabled]=\"disabled\" (click)=\"togglePassword($event)\"\n aria-label=\"Toggle password visibility\">\n\n @if (showPassword) {\n\n <!-- Eye Off -->\n <svg class=\"text-box-password-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M3 3l18 18\" />\n\n <path d=\"M10.6 10.6a2 2 0 1 0 2.8 2.8\" />\n\n <path d=\"M9.9 4.2A10.8 10.8 0 0 1 12 4c5 0 8.7 4.2 9.8 8a10.8 10.8 0 0 1-3.1 5.1\" />\n\n <path d=\"M6.2 6.2C4.5 7.4 3.2 9.2 2.2 12c1.1 3.8 4.8 8 9.8 8 1.7 0 3.3-.5 4.7-1.2\" />\n </svg>\n\n } @else {\n\n <!-- Eye -->\n <svg class=\"text-box-password-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M2 12s3.5-7 10-7\n 10 7 10 7\n -3.5 7-10 7\n -10-7-10-7z\" />\n\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n\n }\n\n </button>\n\n }\n\n </div>\n\n</div>", styles: [":host{--textbox-width: 300px;--textbox-height: 44px;--textbox-background: #ffffff;--textbox-border: 1px solid #a9a9a9;--textbox-border-hover: #777777;--textbox-border-focus: #68479b;--textbox-radius: 6px;--textbox-text-color: #222222;--textbox-placeholder-color: #777777;--textbox-font-family: Arial, Helvetica, sans-serif;--textbox-font-size: 14px;--textbox-font-weight: 600;--textbox-padding: 0 18px;--textbox-focus-shadow: 0 0 0 1px rgba(104, 71, 155, .15);--textbox-disabled-background: #f5f5f5;--textbox-disabled-color: #999999;--textbox-disabled-border: #d0d0d0;--textbox-icon-color: #777777;--textbox-icon-hover-color: #333333;display:block;width:var(--textbox-width);height:var(--textbox-height);box-sizing:border-box}.text-box-container{width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input-wrapper{position:relative;width:100%;height:100%;display:flex;align-items:center;box-sizing:border-box}.text-box-input{width:100%;height:100%;box-sizing:border-box;padding:var(--textbox-padding);border:var(--textbox-border);border-radius:var(--textbox-radius);outline:none;background:var(--textbox-background);color:var(--textbox-text-color);font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight);transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease;cursor:text}.text-box-input[type=password]{padding-right:48px}.text-box-input::placeholder{color:var(--textbox-placeholder-color);opacity:1;font-family:var(--textbox-font-family);font-size:var(--textbox-font-size);font-weight:var(--textbox-font-weight)}.text-box-input:hover:not(:disabled){border-color:var(--textbox-border-hover)}.text-box-input:focus{border-color:var(--textbox-border-focus);box-shadow:var(--textbox-focus-shadow)}.text-box-input:disabled{background:var(--textbox-disabled-background);color:var(--textbox-disabled-color);border-color:var(--textbox-disabled-border);cursor:not-allowed}.text-box-input:read-only{cursor:default}.text-box-password-button{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:32px;height:32px;display:flex;align-items:center;justify-content:center;padding:0;border:none;background:transparent;color:var(--textbox-icon-color);cursor:pointer;border-radius:4px;transition:color .2s ease,background-color .2s ease}.text-box-password-button:hover:not(:disabled){color:var(--textbox-icon-hover-color);background:#0000000d}.text-box-password-button:disabled{cursor:not-allowed;opacity:.5}.text-box-password-icon{width:19px;height:19px;display:block}@media(max-width:768px){:host{width:100%}.text-box-input{font-size:var(--textbox-font-size)}}\n"] }]
316
330
  }], propDecorators: { placeholder: [{
317
331
  type: Input
318
332
  }], value: [{
@@ -337,30 +351,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
337
351
  }] } });
338
352
 
339
353
  class DateInput {
340
- // =========================================
354
+ elementRef;
341
355
  // INPUTS
342
- // =========================================
343
356
  label = '';
344
- placeholder = 'Select date';
357
+ placeholder = '';
345
358
  value = '';
346
359
  disabled = false;
347
360
  readonly = false;
361
+ /**
362
+ * Developer custom CSS class.
363
+ *
364
+ * Example:
365
+ *
366
+ * customClass="flight-date"
367
+ */
348
368
  customClass = '';
349
- // =========================================
350
369
  // OUTPUTS
351
- // =========================================
370
+ /**
371
+ * Emits the selected date as:
372
+ *
373
+ * YYYY-MM-DD
374
+ */
352
375
  valueChange = new EventEmitter();
376
+ /**
377
+ * Emits the selected Date object.
378
+ */
353
379
  dateChange = new EventEmitter();
380
+ /**
381
+ * Emits when the calendar opens/closes.
382
+ */
354
383
  openedChange = new EventEmitter();
384
+ /**
385
+ * Developer click event.
386
+ */
355
387
  clicked = new EventEmitter();
356
- // =========================================
357
388
  // INTERNAL STATE
358
- // =========================================
359
389
  isOpen = false;
360
390
  currentDate = new Date();
361
- // =========================================
391
+ constructor(elementRef) {
392
+ this.elementRef = elementRef;
393
+ }
394
+ // INITIALIZE VALUE
395
+ ngOnInit() {
396
+ if (this.value) {
397
+ const parsedDate = this.parseDate(this.value);
398
+ if (parsedDate) {
399
+ this.currentDate =
400
+ new Date(parsedDate.getFullYear(), parsedDate.getMonth(), 1);
401
+ }
402
+ }
403
+ }
362
404
  // CALENDAR DAYS
363
- // =========================================
364
405
  get calendarDays() {
365
406
  const year = this.currentDate.getFullYear();
366
407
  const month = this.currentDate.getMonth();
@@ -368,33 +409,32 @@ class DateInput {
368
409
  const lastDay = new Date(year, month + 1, 0);
369
410
  const days = [];
370
411
  const startDay = firstDay.getDay();
412
+ // PREVIOUS MONTH DAYS
371
413
  for (let i = 0; i < startDay; i++) {
372
- const previousDate = new Date(year, month, i - startDay + 1);
373
- days.push(previousDate);
414
+ days.push(new Date(year, month, i - startDay + 1));
374
415
  }
416
+ // CURRENT MONTH DAYS
375
417
  for (let day = 1; day <= lastDay.getDate(); day++) {
376
418
  days.push(new Date(year, month, day));
377
419
  }
420
+ // NEXT MONTH DAYS
378
421
  const remaining = 42 - days.length;
379
422
  for (let i = 1; i <= remaining; i++) {
380
423
  days.push(new Date(year, month + 1, i));
381
424
  }
382
425
  return days;
383
426
  }
384
- // =========================================
385
427
  // MONTH NAME
386
- // =========================================
387
428
  get monthName() {
388
429
  return this.currentDate.toLocaleString('default', {
389
430
  month: 'long'
390
431
  });
391
432
  }
433
+ // YEAR
392
434
  get year() {
393
435
  return this.currentDate.getFullYear();
394
436
  }
395
- // =========================================
396
- // OPEN / CLOSE
397
- // =========================================
437
+ // TOGGLE CALENDAR
398
438
  toggleCalendar(event) {
399
439
  if (this.disabled ||
400
440
  this.readonly) {
@@ -403,93 +443,124 @@ class DateInput {
403
443
  if (event) {
404
444
  this.clicked.emit(event);
405
445
  }
406
- this.isOpen = !this.isOpen;
446
+ this.isOpen =
447
+ !this.isOpen;
407
448
  this.openedChange.emit(this.isOpen);
408
449
  }
409
- // =========================================
410
450
  // PREVIOUS MONTH
411
- // =========================================
412
- previousMonth() {
451
+ previousMonth(event) {
452
+ event?.stopPropagation();
413
453
  this.currentDate =
414
454
  new Date(this.year, this.currentDate.getMonth() - 1, 1);
415
455
  }
416
- // =========================================
417
456
  // NEXT MONTH
418
- // =========================================
419
- nextMonth() {
457
+ nextMonth(event) {
458
+ event?.stopPropagation();
420
459
  this.currentDate =
421
460
  new Date(this.year, this.currentDate.getMonth() + 1, 1);
422
461
  }
423
- // =========================================
424
462
  // SELECT DATE
425
- // =========================================
426
463
  selectDate(date, event) {
427
- if (this.disabled) {
464
+ event.stopPropagation();
465
+ if (this.disabled ||
466
+ this.readonly) {
428
467
  return;
429
468
  }
469
+ /*
470
+ * Create a clean Date object.
471
+ */
472
+ const selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
473
+ // UPDATE VALUE
430
474
  this.value =
431
- this.formatDate(date);
475
+ this.formatDate(selectedDate);
476
+ // EMIT EVENTS
432
477
  this.valueChange.emit(this.value);
433
- this.dateChange.emit(date);
478
+ this.dateChange.emit(selectedDate);
434
479
  this.clicked.emit(event);
480
+ // CLOSE
435
481
  this.isOpen = false;
436
482
  this.openedChange.emit(false);
437
483
  }
438
- // =========================================
439
484
  // FORMAT DATE
440
- // =========================================
441
485
  formatDate(date) {
442
- const day = String(date.getDate())
443
- .padStart(2, '0');
444
- const month = String(date.getMonth() + 1)
445
- .padStart(2, '0');
486
+ const day = String(date.getDate()).padStart(2, '0');
487
+ const month = String(date.getMonth() + 1).padStart(2, '0');
446
488
  const year = date.getFullYear();
447
489
  return `${year}-${month}-${day}`;
448
490
  }
449
- // =========================================
450
- // CHECK CURRENT MONTH
451
- // =========================================
491
+ // PARSE DATE
492
+ parseDate(value) {
493
+ const parts = value.split('-');
494
+ if (parts.length !== 3) {
495
+ return null;
496
+ }
497
+ const year = Number(parts[0]);
498
+ const month = Number(parts[1]);
499
+ const day = Number(parts[2]);
500
+ if (!year ||
501
+ !month ||
502
+ !day) {
503
+ return null;
504
+ }
505
+ const date = new Date(year, month - 1, day);
506
+ /*
507
+ * Validate the date.
508
+ */
509
+ if (date.getFullYear() !== year ||
510
+ date.getMonth() !== month - 1 ||
511
+ date.getDate() !== day) {
512
+ return null;
513
+ }
514
+ return date;
515
+ }
516
+ // CURRENT MONTH
452
517
  isCurrentMonth(date) {
453
518
  return (date.getMonth() ===
454
519
  this.currentDate.getMonth() &&
455
520
  date.getFullYear() ===
456
521
  this.currentDate.getFullYear());
457
522
  }
458
- // =========================================
459
- // CHECK TODAY
460
- // =========================================
523
+ // TODAY
461
524
  isToday(date) {
462
525
  const today = new Date();
463
- return (date.getDate() === today.getDate() &&
464
- date.getMonth() === today.getMonth() &&
465
- date.getFullYear() === today.getFullYear());
526
+ return (date.getDate() ===
527
+ today.getDate() &&
528
+ date.getMonth() ===
529
+ today.getMonth() &&
530
+ date.getFullYear() ===
531
+ today.getFullYear());
466
532
  }
467
- // =========================================
468
- // CHECK SELECTED DATE
469
- // =========================================
533
+ // SELECTED DATE
470
534
  isSelected(date) {
471
535
  return (this.value ===
472
536
  this.formatDate(date));
473
537
  }
474
- // =========================================
475
538
  // OUTSIDE CLICK
476
- // =========================================
477
539
  onDocumentClick(event) {
540
+ if (!this.isOpen) {
541
+ return;
542
+ }
478
543
  const target = event.target;
479
- const dateInput = target.closest('lib-date-input');
480
- if (!dateInput &&
481
- this.isOpen) {
482
- this.isOpen = false;
483
- this.openedChange.emit(false);
544
+ const host = this.elementRef.nativeElement;
545
+ if (!host.contains(target)) {
546
+ this.closeCalendar();
547
+ }
548
+ }
549
+ // CLOSE CALENDAR
550
+ closeCalendar() {
551
+ if (!this.isOpen) {
552
+ return;
484
553
  }
554
+ this.isOpen = false;
555
+ this.openedChange.emit(false);
485
556
  }
486
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: DateInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
487
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: DateInput, isStandalone: true, selector: "lib-date-input", inputs: { label: "label", placeholder: "placeholder", value: "value", disabled: "disabled", readonly: "readonly", customClass: "customClass" }, outputs: { valueChange: "valueChange", dateChange: "dateChange", openedChange: "openedChange", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: "<div\n class=\"date-input-container\"\n [class]=\"customClass\"\n [class.date-input-disabled]=\"disabled\"\n [class.date-input-open]=\"isOpen\"\n>\n\n <!-- INPUT -->\n\n <div\n class=\"date-input-field\"\n (click)=\"toggleCalendar($event)\"\n >\n\n @if (label) {\n <label class=\"date-input-label\">\n {{ label }}\n </label>\n }\n\n <span\n class=\"date-input-value\"\n [class.date-input-placeholder]=\"!value\"\n >\n {{ value || placeholder }}\n </span>\n\n <!-- Calendar Icon -->\n\n <span class=\"calendar-icon\">\n\n <span class=\"calendar-top\"></span>\n\n <span class=\"calendar-body\"></span>\n\n </span>\n\n </div>\n\n\n <!-- DATE PICKER -->\n\n @if (isOpen) {\n\n <div\n class=\"date-picker\"\n (click)=\"$event.stopPropagation()\"\n >\n\n <!-- HEADER -->\n\n <div class=\"date-picker-header\">\n\n <button\n type=\"button\"\n class=\"month-button\"\n (click)=\"previousMonth()\"\n >\n \u2039\n </button>\n\n <span class=\"month-title\">\n {{ monthName }} {{ year }}\n </span>\n\n <button\n type=\"button\"\n class=\"month-button\"\n (click)=\"nextMonth()\"\n >\n \u203A\n </button>\n\n </div>\n\n\n <!-- WEEK DAYS -->\n\n <div class=\"week-days\">\n\n <span>Sun</span>\n <span>Mon</span>\n <span>Tue</span>\n <span>Wed</span>\n <span>Thu</span>\n <span>Fri</span>\n <span>Sat</span>\n\n </div>\n\n\n <!-- DAYS -->\n\n <div class=\"calendar-days\">\n\n @for (\n date of calendarDays;\n track date.getTime()\n ) {\n\n <button\n type=\"button\"\n\n class=\"calendar-day\"\n\n [class.other-month]=\"\n !isCurrentMonth(date)\n \"\n\n [class.today]=\"\n isToday(date)\n \"\n\n [class.selected]=\"\n isSelected(date)\n \"\n\n (click)=\"\n selectDate(date, $event)\n \"\n >\n\n {{ date.getDate() }}\n\n </button>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [".date-input-container{--date-width: 300px;--date-height: 44px;--date-background: #ffffff;--date-border: 1px solid #a9a9a9;--date-border-hover: #777777;--date-border-focus: #68479b;--date-radius: 6px;--date-text: #222222;--date-placeholder: #777777;--date-primary: #68479b;--date-hover: #f3f0f7;--date-selected: #68479b;--date-selected-text: #ffffff;--date-font-family: Arial, Helvetica, sans-serif;--date-font-size: 14px;--date-shadow: 0 4px 12px rgba(0, 0, 0, .12);position:relative;width:var(--date-width);font-family:var(--date-font-family);box-sizing:border-box}.date-input-field{position:relative;width:100%;height:var(--date-height);display:flex;align-items:center;box-sizing:border-box;padding:0 50px 0 18px;border:var(--date-border);border-radius:var(--date-radius);background:var(--date-background);color:var(--date-text);font-size:var(--date-font-size);font-weight:600;cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease}.date-input-field:hover{border-color:var(--date-border-hover)}.date-input-open .date-input-field{border-color:var(--date-border-focus);box-shadow:0 0 0 1px #68479b1f}.date-input-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--date-background);color:var(--date-border-focus);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.date-input-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.date-input-placeholder{color:var(--date-placeholder)}.calendar-icon{position:absolute;right:17px;width:18px;height:18px;box-sizing:border-box;border:1.8px solid #555;border-radius:3px}.calendar-top{position:absolute;left:0;top:4px;width:100%;border-top:1.8px solid #555}.calendar-icon:before,.calendar-icon:after{content:\"\";position:absolute;top:-4px;width:2px;height:6px;background:#555;border-radius:2px}.calendar-icon:before{left:4px}.calendar-icon:after{right:4px}.date-picker{position:absolute;top:calc(100% + 6px);left:0;width:100%;min-width:300px;z-index:1000;padding:14px;box-sizing:border-box;background:#fff;border:1px solid #d5d5d5;border-radius:var(--date-radius);box-shadow:var(--date-shadow)}.date-picker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.month-title{font-size:15px;font-weight:700;color:var(--date-text)}.month-button{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:#555;font-size:24px;line-height:1;cursor:pointer}.month-button:hover{background:var(--date-hover);color:var(--date-primary)}.week-days{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:6px;text-align:center;color:#777;font-size:12px;font-weight:600}.calendar-days{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.calendar-day{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:var(--date-text);font-size:13px;cursor:pointer;transition:background-color .15s ease,color .15s ease}.calendar-day:hover{background:var(--date-hover)}.calendar-day.other-month{color:silver}.calendar-day.today{border:1px solid var(--date-primary);color:var(--date-primary)}.calendar-day.selected{background:var(--date-selected);color:var(--date-selected-text);border:none}.date-input-disabled .date-input-field{background:#f5f5f5;border-color:#d0d0d0;color:#999;cursor:not-allowed}@media(max-width:768px){.date-input-container{width:100%}.date-picker{min-width:100%}}\n"] });
557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: DateInput, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: DateInput, isStandalone: true, selector: "lib-date-input", inputs: { label: "label", placeholder: "placeholder", value: "value", disabled: "disabled", readonly: "readonly", customClass: "customClass" }, outputs: { valueChange: "valueChange", dateChange: "dateChange", openedChange: "openedChange", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, properties: { "class": "this.customClass" } }, ngImport: i0, template: "<div class=\"date-input-container\" [class.date-input-disabled]=\"disabled\" [class.date-input-open]=\"isOpen\">\n <div class=\"date-input-field\" (click)=\"toggleCalendar($event)\">\n\n <!-- LABEL -->\n\n @if (label) {\n\n <label class=\"date-input-label\">\n\n {{ label }}\n\n </label>\n\n }\n\n\n <!-- VALUE -->\n\n <span class=\"date-input-value\" [class.date-input-placeholder]=\"!value\">\n\n {{ value || placeholder }}\n\n </span>\n\n\n <!-- CALENDAR ICON -->\n\n <span class=\"calendar-icon\">\n\n <span class=\"calendar-top\"></span>\n\n <span class=\"calendar-body\"></span>\n\n </span>\n\n </div>\n\n\n\n @if (isOpen) {\n\n <div class=\"date-picker\" (click)=\"$event.stopPropagation()\">\n\n\n <div class=\"date-picker-header\">\n\n <button type=\"button\" class=\"month-button\" aria-label=\"Previous month\" (click)=\"previousMonth($event)\">\n\n \u2039\n\n </button>\n\n\n <span class=\"month-title\">\n\n {{ monthName }} {{ year }}\n\n </span>\n\n\n <button type=\"button\" class=\"month-button\" aria-label=\"Next month\" (click)=\"nextMonth($event)\">\n\n \u203A\n\n </button>\n\n </div>\n\n\n <div class=\"week-days\">\n\n <span>Sun</span>\n\n <span>Mon</span>\n\n <span>Tue</span>\n\n <span>Wed</span>\n\n <span>Thu</span>\n\n <span>Fri</span>\n\n <span>Sat</span>\n\n </div>\n\n\n\n <div class=\"calendar-days\">\n\n @for (\n date of calendarDays;\n track date.getTime()\n ) {\n\n <button type=\"button\" class=\"calendar-day\" [class.other-month]=\"\n !isCurrentMonth(date)\n \" [class.today]=\"\n isToday(date)\n \" [class.selected]=\"\n isSelected(date)\n \" (click)=\"\n selectDate(date, $event)\n \">\n\n {{ date.getDate() }}\n\n </button>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [":host{--date-width: 300px;--date-height: 44px;--date-background: #ffffff;--date-border: 1px solid #a9a9a9;--date-border-hover: #777777;--date-border-focus: #68479b;--date-radius: 6px;--date-text: #222222;--date-placeholder: #777777;--date-primary: #68479b;--date-hover: #f3f0f7;--date-selected: #68479b;--date-selected-text: #ffffff;--date-font-family: Arial, Helvetica, sans-serif;--date-font-size: 14px;--date-font-weight: 600;--date-shadow: 0 4px 12px rgba(0, 0, 0, .12);--date-icon-color: #555555;--date-disabled-background: #f5f5f5;--date-disabled-border: #d0d0d0;--date-disabled-text: #999999;display:block;position:relative;width:var(--date-width);box-sizing:border-box;font-family:var(--date-font-family)}.date-input-container{position:relative;width:100%;box-sizing:border-box}.date-input-field{position:relative;width:100%;height:var(--date-height);display:flex;align-items:center;box-sizing:border-box;padding:0 50px 0 18px;border:var(--date-border);border-radius:var(--date-radius);background:var(--date-background);color:var(--date-text);font-size:var(--date-font-size);font-weight:var(--date-font-weight);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease}.date-input-field:hover{border-color:var(--date-border-hover)}.date-input-open .date-input-field{border-color:var(--date-border-focus);box-shadow:0 0 0 1px #68479b1f}.date-input-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--date-background);color:var(--date-border-focus);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.date-input-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--date-text)}.date-input-placeholder{color:var(--date-placeholder)}.calendar-icon{position:absolute;right:17px;width:18px;height:18px;box-sizing:border-box;border:1.8px solid var(--date-icon-color);border-radius:3px}.calendar-top{position:absolute;left:0;top:4px;width:100%;border-top:1.8px solid var(--date-icon-color)}.calendar-icon:before,.calendar-icon:after{content:\"\";position:absolute;top:-4px;width:2px;height:6px;background:var(--date-icon-color);border-radius:2px}.calendar-icon:before{left:4px}.calendar-icon:after{right:4px}.date-picker{position:absolute;top:calc(100% + 6px);left:0;width:100%;min-width:300px;z-index:1000;padding:14px;box-sizing:border-box;background:#fff;border:1px solid #d5d5d5;border-radius:var(--date-radius);box-shadow:var(--date-shadow)}.date-picker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.month-title{font-size:15px;font-weight:700;color:var(--date-text)}.month-button{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:#555;font-size:24px;line-height:1;cursor:pointer;transition:background-color .15s ease,color .15s ease}.month-button:hover{background:var(--date-hover);color:var(--date-primary)}.week-days{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:6px;text-align:center;color:#777;font-size:12px;font-weight:600}.calendar-days{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.calendar-day{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:var(--date-text);font-family:var(--date-font-family);font-size:13px;cursor:pointer;transition:background-color .15s ease,color .15s ease}.calendar-day:hover{background:var(--date-hover)}.calendar-day.other-month{color:silver}.calendar-day.today{border:1px solid var(--date-primary);color:var(--date-primary)}.calendar-day.selected{background:var(--date-selected);color:var(--date-selected-text);border:none}.calendar-day.selected.today{background:var(--date-selected);color:var(--date-selected-text)}.date-input-disabled .date-input-field{background:var(--date-disabled-background);border-color:var(--date-disabled-border);color:var(--date-disabled-text);cursor:not-allowed}@media(max-width:768px){:host{width:100%}.date-picker{min-width:100%}}\n"] });
488
559
  }
489
560
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: DateInput, decorators: [{
490
561
  type: Component,
491
- args: [{ selector: 'lib-date-input', standalone: true, imports: [], template: "<div\n class=\"date-input-container\"\n [class]=\"customClass\"\n [class.date-input-disabled]=\"disabled\"\n [class.date-input-open]=\"isOpen\"\n>\n\n <!-- INPUT -->\n\n <div\n class=\"date-input-field\"\n (click)=\"toggleCalendar($event)\"\n >\n\n @if (label) {\n <label class=\"date-input-label\">\n {{ label }}\n </label>\n }\n\n <span\n class=\"date-input-value\"\n [class.date-input-placeholder]=\"!value\"\n >\n {{ value || placeholder }}\n </span>\n\n <!-- Calendar Icon -->\n\n <span class=\"calendar-icon\">\n\n <span class=\"calendar-top\"></span>\n\n <span class=\"calendar-body\"></span>\n\n </span>\n\n </div>\n\n\n <!-- DATE PICKER -->\n\n @if (isOpen) {\n\n <div\n class=\"date-picker\"\n (click)=\"$event.stopPropagation()\"\n >\n\n <!-- HEADER -->\n\n <div class=\"date-picker-header\">\n\n <button\n type=\"button\"\n class=\"month-button\"\n (click)=\"previousMonth()\"\n >\n \u2039\n </button>\n\n <span class=\"month-title\">\n {{ monthName }} {{ year }}\n </span>\n\n <button\n type=\"button\"\n class=\"month-button\"\n (click)=\"nextMonth()\"\n >\n \u203A\n </button>\n\n </div>\n\n\n <!-- WEEK DAYS -->\n\n <div class=\"week-days\">\n\n <span>Sun</span>\n <span>Mon</span>\n <span>Tue</span>\n <span>Wed</span>\n <span>Thu</span>\n <span>Fri</span>\n <span>Sat</span>\n\n </div>\n\n\n <!-- DAYS -->\n\n <div class=\"calendar-days\">\n\n @for (\n date of calendarDays;\n track date.getTime()\n ) {\n\n <button\n type=\"button\"\n\n class=\"calendar-day\"\n\n [class.other-month]=\"\n !isCurrentMonth(date)\n \"\n\n [class.today]=\"\n isToday(date)\n \"\n\n [class.selected]=\"\n isSelected(date)\n \"\n\n (click)=\"\n selectDate(date, $event)\n \"\n >\n\n {{ date.getDate() }}\n\n </button>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [".date-input-container{--date-width: 300px;--date-height: 44px;--date-background: #ffffff;--date-border: 1px solid #a9a9a9;--date-border-hover: #777777;--date-border-focus: #68479b;--date-radius: 6px;--date-text: #222222;--date-placeholder: #777777;--date-primary: #68479b;--date-hover: #f3f0f7;--date-selected: #68479b;--date-selected-text: #ffffff;--date-font-family: Arial, Helvetica, sans-serif;--date-font-size: 14px;--date-shadow: 0 4px 12px rgba(0, 0, 0, .12);position:relative;width:var(--date-width);font-family:var(--date-font-family);box-sizing:border-box}.date-input-field{position:relative;width:100%;height:var(--date-height);display:flex;align-items:center;box-sizing:border-box;padding:0 50px 0 18px;border:var(--date-border);border-radius:var(--date-radius);background:var(--date-background);color:var(--date-text);font-size:var(--date-font-size);font-weight:600;cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease}.date-input-field:hover{border-color:var(--date-border-hover)}.date-input-open .date-input-field{border-color:var(--date-border-focus);box-shadow:0 0 0 1px #68479b1f}.date-input-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--date-background);color:var(--date-border-focus);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.date-input-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.date-input-placeholder{color:var(--date-placeholder)}.calendar-icon{position:absolute;right:17px;width:18px;height:18px;box-sizing:border-box;border:1.8px solid #555;border-radius:3px}.calendar-top{position:absolute;left:0;top:4px;width:100%;border-top:1.8px solid #555}.calendar-icon:before,.calendar-icon:after{content:\"\";position:absolute;top:-4px;width:2px;height:6px;background:#555;border-radius:2px}.calendar-icon:before{left:4px}.calendar-icon:after{right:4px}.date-picker{position:absolute;top:calc(100% + 6px);left:0;width:100%;min-width:300px;z-index:1000;padding:14px;box-sizing:border-box;background:#fff;border:1px solid #d5d5d5;border-radius:var(--date-radius);box-shadow:var(--date-shadow)}.date-picker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.month-title{font-size:15px;font-weight:700;color:var(--date-text)}.month-button{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:#555;font-size:24px;line-height:1;cursor:pointer}.month-button:hover{background:var(--date-hover);color:var(--date-primary)}.week-days{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:6px;text-align:center;color:#777;font-size:12px;font-weight:600}.calendar-days{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.calendar-day{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:var(--date-text);font-size:13px;cursor:pointer;transition:background-color .15s ease,color .15s ease}.calendar-day:hover{background:var(--date-hover)}.calendar-day.other-month{color:silver}.calendar-day.today{border:1px solid var(--date-primary);color:var(--date-primary)}.calendar-day.selected{background:var(--date-selected);color:var(--date-selected-text);border:none}.date-input-disabled .date-input-field{background:#f5f5f5;border-color:#d0d0d0;color:#999;cursor:not-allowed}@media(max-width:768px){.date-input-container{width:100%}.date-picker{min-width:100%}}\n"] }]
492
- }], propDecorators: { label: [{
562
+ args: [{ selector: 'lib-date-input', standalone: true, imports: [], template: "<div class=\"date-input-container\" [class.date-input-disabled]=\"disabled\" [class.date-input-open]=\"isOpen\">\n <div class=\"date-input-field\" (click)=\"toggleCalendar($event)\">\n\n <!-- LABEL -->\n\n @if (label) {\n\n <label class=\"date-input-label\">\n\n {{ label }}\n\n </label>\n\n }\n\n\n <!-- VALUE -->\n\n <span class=\"date-input-value\" [class.date-input-placeholder]=\"!value\">\n\n {{ value || placeholder }}\n\n </span>\n\n\n <!-- CALENDAR ICON -->\n\n <span class=\"calendar-icon\">\n\n <span class=\"calendar-top\"></span>\n\n <span class=\"calendar-body\"></span>\n\n </span>\n\n </div>\n\n\n\n @if (isOpen) {\n\n <div class=\"date-picker\" (click)=\"$event.stopPropagation()\">\n\n\n <div class=\"date-picker-header\">\n\n <button type=\"button\" class=\"month-button\" aria-label=\"Previous month\" (click)=\"previousMonth($event)\">\n\n \u2039\n\n </button>\n\n\n <span class=\"month-title\">\n\n {{ monthName }} {{ year }}\n\n </span>\n\n\n <button type=\"button\" class=\"month-button\" aria-label=\"Next month\" (click)=\"nextMonth($event)\">\n\n \u203A\n\n </button>\n\n </div>\n\n\n <div class=\"week-days\">\n\n <span>Sun</span>\n\n <span>Mon</span>\n\n <span>Tue</span>\n\n <span>Wed</span>\n\n <span>Thu</span>\n\n <span>Fri</span>\n\n <span>Sat</span>\n\n </div>\n\n\n\n <div class=\"calendar-days\">\n\n @for (\n date of calendarDays;\n track date.getTime()\n ) {\n\n <button type=\"button\" class=\"calendar-day\" [class.other-month]=\"\n !isCurrentMonth(date)\n \" [class.today]=\"\n isToday(date)\n \" [class.selected]=\"\n isSelected(date)\n \" (click)=\"\n selectDate(date, $event)\n \">\n\n {{ date.getDate() }}\n\n </button>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [":host{--date-width: 300px;--date-height: 44px;--date-background: #ffffff;--date-border: 1px solid #a9a9a9;--date-border-hover: #777777;--date-border-focus: #68479b;--date-radius: 6px;--date-text: #222222;--date-placeholder: #777777;--date-primary: #68479b;--date-hover: #f3f0f7;--date-selected: #68479b;--date-selected-text: #ffffff;--date-font-family: Arial, Helvetica, sans-serif;--date-font-size: 14px;--date-font-weight: 600;--date-shadow: 0 4px 12px rgba(0, 0, 0, .12);--date-icon-color: #555555;--date-disabled-background: #f5f5f5;--date-disabled-border: #d0d0d0;--date-disabled-text: #999999;display:block;position:relative;width:var(--date-width);box-sizing:border-box;font-family:var(--date-font-family)}.date-input-container{position:relative;width:100%;box-sizing:border-box}.date-input-field{position:relative;width:100%;height:var(--date-height);display:flex;align-items:center;box-sizing:border-box;padding:0 50px 0 18px;border:var(--date-border);border-radius:var(--date-radius);background:var(--date-background);color:var(--date-text);font-size:var(--date-font-size);font-weight:var(--date-font-weight);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease,background-color .2s ease}.date-input-field:hover{border-color:var(--date-border-hover)}.date-input-open .date-input-field{border-color:var(--date-border-focus);box-shadow:0 0 0 1px #68479b1f}.date-input-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--date-background);color:var(--date-border-focus);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.date-input-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--date-text)}.date-input-placeholder{color:var(--date-placeholder)}.calendar-icon{position:absolute;right:17px;width:18px;height:18px;box-sizing:border-box;border:1.8px solid var(--date-icon-color);border-radius:3px}.calendar-top{position:absolute;left:0;top:4px;width:100%;border-top:1.8px solid var(--date-icon-color)}.calendar-icon:before,.calendar-icon:after{content:\"\";position:absolute;top:-4px;width:2px;height:6px;background:var(--date-icon-color);border-radius:2px}.calendar-icon:before{left:4px}.calendar-icon:after{right:4px}.date-picker{position:absolute;top:calc(100% + 6px);left:0;width:100%;min-width:300px;z-index:1000;padding:14px;box-sizing:border-box;background:#fff;border:1px solid #d5d5d5;border-radius:var(--date-radius);box-shadow:var(--date-shadow)}.date-picker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}.month-title{font-size:15px;font-weight:700;color:var(--date-text)}.month-button{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:#555;font-size:24px;line-height:1;cursor:pointer;transition:background-color .15s ease,color .15s ease}.month-button:hover{background:var(--date-hover);color:var(--date-primary)}.week-days{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:6px;text-align:center;color:#777;font-size:12px;font-weight:600}.calendar-days{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.calendar-day{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border:none;border-radius:50%;background:transparent;color:var(--date-text);font-family:var(--date-font-family);font-size:13px;cursor:pointer;transition:background-color .15s ease,color .15s ease}.calendar-day:hover{background:var(--date-hover)}.calendar-day.other-month{color:silver}.calendar-day.today{border:1px solid var(--date-primary);color:var(--date-primary)}.calendar-day.selected{background:var(--date-selected);color:var(--date-selected-text);border:none}.calendar-day.selected.today{background:var(--date-selected);color:var(--date-selected-text)}.date-input-disabled .date-input-field{background:var(--date-disabled-background);border-color:var(--date-disabled-border);color:var(--date-disabled-text);cursor:not-allowed}@media(max-width:768px){:host{width:100%}.date-picker{min-width:100%}}\n"] }]
563
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{
493
564
  type: Input
494
565
  }], placeholder: [{
495
566
  type: Input
@@ -501,6 +572,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
501
572
  type: Input
502
573
  }], customClass: [{
503
574
  type: Input
575
+ }, {
576
+ type: HostBinding,
577
+ args: ['class']
504
578
  }], valueChange: [{
505
579
  type: Output
506
580
  }], dateChange: [{
@@ -516,43 +590,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
516
590
  }] } });
517
591
 
518
592
  class Dropdown {
519
- // =========================================
593
+ elementRef;
520
594
  // INPUTS
521
- // =========================================
522
595
  label = '';
523
- placeholder = 'Select';
596
+ placeholder = '';
524
597
  options = [];
525
598
  value = '';
526
599
  disabled = false;
527
600
  searchable = true;
528
601
  customClass = '';
529
- // =========================================
530
602
  // OUTPUTS
531
- // =========================================
532
- /**
533
- * Emits the selected value.
534
- */
535
603
  valueChange = new EventEmitter();
536
- /**
537
- * Emits the complete selected option.
538
- */
539
604
  selectionChange = new EventEmitter();
540
- /**
541
- * Emits when the dropdown opens/closes.
542
- */
543
605
  openedChange = new EventEmitter();
544
- /**
545
- * Developer click event.
546
- */
547
606
  clicked = new EventEmitter();
548
- // =========================================
549
- // INTERNAL STATE
550
- // =========================================
607
+ // STATE
551
608
  isOpen = false;
552
609
  searchText = '';
553
- // =========================================
610
+ constructor(elementRef) {
611
+ this.elementRef = elementRef;
612
+ }
554
613
  // FILTERED OPTIONS
555
- // =========================================
556
614
  get filteredOptions() {
557
615
  const search = this.searchText
558
616
  .trim()
@@ -564,15 +622,11 @@ class Dropdown {
564
622
  .toLowerCase()
565
623
  .includes(search));
566
624
  }
567
- // =========================================
568
625
  // SELECTED OPTION
569
- // =========================================
570
626
  get selectedOption() {
571
627
  return this.options.find(option => option.value === this.value);
572
628
  }
573
- // =========================================
574
- // OPEN / CLOSE
575
- // =========================================
629
+ // TOGGLE
576
630
  toggleDropdown(event) {
577
631
  if (this.disabled) {
578
632
  return;
@@ -580,51 +634,60 @@ class Dropdown {
580
634
  if (event) {
581
635
  this.clicked.emit(event);
582
636
  }
583
- this.isOpen = !this.isOpen;
637
+ this.isOpen =
638
+ !this.isOpen;
584
639
  this.openedChange.emit(this.isOpen);
585
640
  if (!this.isOpen) {
586
641
  this.searchText = '';
587
642
  }
588
643
  }
644
+ // DOCUMENT CLICK
589
645
  onDocumentClick(event) {
646
+ if (!this.isOpen) {
647
+ return;
648
+ }
590
649
  const target = event.target;
591
- const dropdown = target.closest('lib-dropdown');
592
- if (!dropdown && this.isOpen) {
593
- this.isOpen = false;
594
- this.searchText = '';
595
- this.openedChange.emit(false);
650
+ const host = this.elementRef.nativeElement;
651
+ if (!host.contains(target)) {
652
+ this.closeDropdown();
596
653
  }
597
654
  }
598
- // =========================================
599
- // SELECT OPTION
600
- // =========================================
655
+ // CLOSE
656
+ closeDropdown() {
657
+ if (!this.isOpen) {
658
+ return;
659
+ }
660
+ this.isOpen = false;
661
+ this.searchText = '';
662
+ this.openedChange.emit(false);
663
+ }
664
+ // SELECT
601
665
  selectOption(option, event) {
602
666
  if (option.disabled) {
603
667
  return;
604
668
  }
605
- this.value = option.value;
669
+ this.value =
670
+ option.value;
606
671
  this.valueChange.emit(option.value);
607
672
  this.selectionChange.emit(option);
608
673
  this.clicked.emit(event);
609
674
  this.isOpen = false;
610
- this.openedChange.emit(false);
611
675
  this.searchText = '';
676
+ this.openedChange.emit(false);
612
677
  }
613
- // =========================================
614
678
  // SEARCH
615
- // =========================================
616
679
  onSearch(event) {
617
680
  const input = event.target;
618
681
  this.searchText =
619
682
  input.value;
620
683
  }
621
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Dropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
622
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: Dropdown, isStandalone: true, selector: "lib-dropdown", inputs: { label: "label", placeholder: "placeholder", options: "options", value: "value", disabled: "disabled", searchable: "searchable", customClass: "customClass" }, outputs: { valueChange: "valueChange", selectionChange: "selectionChange", openedChange: "openedChange", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: "<div\n class=\"dropdown-container\"\n [class]=\"customClass\"\n [class.dropdown-disabled]=\"disabled\"\n [class.dropdown-open]=\"isOpen\"\n>\n\n <!-- =====================================\n DROPDOWN FIELD\n ===================================== -->\n\n <div\n class=\"dropdown-field\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <!-- Label -->\n\n @if (label) {\n <label class=\"dropdown-label\">\n {{ label }}\n </label>\n }\n\n\n <!-- Selected value -->\n\n <span\n class=\"dropdown-value\"\n [class.dropdown-placeholder]=\"!selectedOption\"\n >\n {{\n selectedOption?.label ||\n placeholder\n }}\n </span>\n\n\n <!-- Arrow -->\n\n <span\n class=\"dropdown-arrow\"\n [class.arrow-up]=\"isOpen\"\n >\n </span>\n\n </div>\n\n\n <!-- =====================================\n DROPDOWN MENU\n ===================================== -->\n\n @if (isOpen) {\n\n <div\n class=\"dropdown-menu\"\n (click)=\"$event.stopPropagation()\"\n >\n\n <!-- Search -->\n\n @if (searchable) {\n\n <div class=\"dropdown-search\">\n\n <input\n type=\"text\"\n class=\"dropdown-search-input\"\n\n placeholder=\"Search...\"\n\n [value]=\"searchText\"\n\n (input)=\"onSearch($event)\"\n />\n\n </div>\n\n }\n\n\n <!-- Options -->\n\n <div class=\"dropdown-options\">\n\n @for (\n option of filteredOptions;\n track option.value\n ) {\n\n <div\n class=\"dropdown-option\"\n\n [class.option-disabled]=\"\n option.disabled\n \"\n\n [class.option-selected]=\"\n option.value === value\n \"\n\n (click)=\"\n selectOption(option, $event)\n \"\n >\n\n {{ option.label }}\n\n </div>\n\n }\n\n\n <!-- No result -->\n\n @if (filteredOptions.length === 0) {\n\n <div class=\"dropdown-no-result\">\n No results found\n </div>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [".dropdown-container{--dropdown-width: 300px;--dropdown-height: 44px;--dropdown-background: #ffffff;--dropdown-border: 1px solid #a9a9a9;--dropdown-border-hover: #777777;--dropdown-border-focus: #68479b;--dropdown-radius: 6px;--dropdown-text-color: #222222;--dropdown-placeholder-color: #777777;--dropdown-menu-background: #ffffff;--dropdown-option-hover: #f3f0f7;--dropdown-option-selected: #eee8f5;--dropdown-disabled: #f5f5f5;--dropdown-font-family: Arial, Helvetica, sans-serif;--dropdown-font-size: 14px;--dropdown-font-weight: 600;--dropdown-shadow: 0 4px 12px rgba(0, 0, 0, .12);position:relative;width:var(--dropdown-width);font-family:var(--dropdown-font-family);box-sizing:border-box}.dropdown-field{position:relative;width:100%;height:var(--dropdown-height);display:flex;align-items:center;box-sizing:border-box;padding:0 48px 0 18px;border:var(--dropdown-border);border-radius:var(--dropdown-radius);background:var(--dropdown-background);color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);font-weight:var(--dropdown-font-weight);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease}.dropdown-field:hover{border-color:var(--dropdown-border-hover)}.dropdown-open .dropdown-field{border-color:var(--dropdown-border-focus);box-shadow:0 0 0 1px #68479b1f}.dropdown-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--dropdown-background);color:var(--dropdown-border-focus);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.dropdown-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--dropdown-text-color)}.dropdown-placeholder{color:var(--dropdown-placeholder-color)}.dropdown-arrow{position:absolute;right:18px;top:50%;width:9px;height:9px;border-right:2px solid #555;border-bottom:2px solid #555;transform:translateY(-65%) rotate(45deg);transition:transform .2s ease}.dropdown-arrow.arrow-up{transform:translateY(-25%) rotate(225deg)}.dropdown-menu{position:absolute;top:calc(100% + 6px);left:0;width:100%;z-index:1000;overflow:hidden;background:var(--dropdown-menu-background);border:1px solid #d0d0d0;border-radius:var(--dropdown-radius);box-shadow:var(--dropdown-shadow)}.dropdown-search{padding:8px;border-bottom:1px solid #eeeeee}.dropdown-search-input{width:100%;height:38px;box-sizing:border-box;padding:0 12px;border:1px solid #cfcfcf;border-radius:5px;outline:none;background:#fff;font-family:var(--dropdown-font-family);font-size:14px}.dropdown-search-input:focus{border-color:var(--dropdown-border-focus)}.dropdown-options{max-height:240px;overflow-y:auto}.dropdown-option{min-height:42px;display:flex;align-items:center;padding:0 14px;box-sizing:border-box;color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);cursor:pointer;transition:background-color .15s ease}.dropdown-option:hover{background:var(--dropdown-option-hover)}.dropdown-option.option-selected{background:var(--dropdown-option-selected);color:var(--dropdown-border-focus);font-weight:600}.dropdown-option.option-disabled{color:#aaa;cursor:not-allowed;background:transparent}.dropdown-no-result{min-height:50px;display:flex;align-items:center;justify-content:center;padding:0 15px;color:#888;font-size:13px}.dropdown-disabled .dropdown-field{background:var(--dropdown-disabled);color:#999;border-color:#d0d0d0;cursor:not-allowed}.dropdown-options::-webkit-scrollbar{width:6px}.dropdown-options::-webkit-scrollbar-thumb{background:#c5c5c5;border-radius:10px}@media(max-width:768px){.dropdown-container{width:100%}.dropdown-field{height:var(--dropdown-height)}}\n"] });
684
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Dropdown, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
685
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: Dropdown, isStandalone: true, selector: "lib-dropdown", inputs: { label: "label", placeholder: "placeholder", options: "options", value: "value", disabled: "disabled", searchable: "searchable", customClass: "customClass" }, outputs: { valueChange: "valueChange", selectionChange: "selectionChange", openedChange: "openedChange", clicked: "clicked" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, properties: { "class": "this.customClass" } }, ngImport: i0, template: "<div class=\"dropdown-container\" [class.dropdown-disabled]=\"disabled\" [class.dropdown-open]=\"isOpen\">\n\n <div class=\"dropdown-field\" (click)=\"toggleDropdown($event)\">\n\n <!-- Label -->\n\n @if (label) {\n\n <label class=\"dropdown-label\">\n {{ label }}\n </label>\n\n }\n\n\n <!-- Selected Value -->\n\n <span class=\"dropdown-value\" [class.dropdown-placeholder]=\"\n !selectedOption\n \">\n\n {{\n selectedOption?.label ||\n placeholder\n }}\n\n </span>\n\n\n <!-- Arrow -->\n\n <span class=\"dropdown-arrow\" [class.arrow-up]=\"isOpen\"></span>\n\n </div>\n\n\n @if (isOpen) {\n\n <div class=\"dropdown-menu\" (click)=\"$event.stopPropagation()\">\n\n <!-- SEARCH -->\n\n @if (searchable) {\n\n <div class=\"dropdown-search\">\n\n <input type=\"text\" class=\"dropdown-search-input\" placeholder=\"Search...\" [value]=\"searchText\"\n (input)=\"onSearch($event)\" />\n\n </div>\n\n }\n\n\n <!-- OPTIONS -->\n\n <div class=\"dropdown-options\">\n\n @for (\n option of filteredOptions;\n track option.value\n ) {\n\n <div class=\"dropdown-option\" [class.option-disabled]=\"\n option.disabled\n \" [class.option-selected]=\"\n option.value === value\n \" (click)=\"\n selectOption(option, $event)\n \">\n\n {{ option.label }}\n\n </div>\n\n }\n\n\n <!-- NO RESULTS -->\n\n @if (\n filteredOptions.length === 0\n ) {\n\n <div class=\"dropdown-no-result\">\n\n No results found\n\n </div>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [":host{--dropdown-width: 300px;--dropdown-height: 44px;--dropdown-background: #ffffff;--dropdown-border: 1px solid #a9a9a9;--dropdown-border-hover: #777777;--dropdown-border-focus: #68479b;--dropdown-radius: 6px;--dropdown-text-color: #222222;--dropdown-placeholder-color: #777777;--dropdown-menu-background: #ffffff;--dropdown-option-hover: #f3f0f7;--dropdown-option-selected: #eee8f5;--dropdown-disabled: #f5f5f5;--dropdown-font-family: Arial, Helvetica, sans-serif;--dropdown-font-size: 14px;--dropdown-font-weight: 600;--dropdown-shadow: 0 4px 12px rgba(0, 0, 0, .12);--dropdown-label-color: #68479b;--dropdown-arrow-color: #555555;--dropdown-search-border: #cfcfcf;display:block;position:relative;width:var(--dropdown-width);box-sizing:border-box}.dropdown-container{position:relative;width:100%;font-family:var(--dropdown-font-family);box-sizing:border-box}.dropdown-field{position:relative;width:100%;height:var(--dropdown-height);display:flex;align-items:center;box-sizing:border-box;padding:0 48px 0 18px;border:var(--dropdown-border);border-radius:var(--dropdown-radius);background:var(--dropdown-background);color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);font-weight:var(--dropdown-font-weight);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease}.dropdown-field:hover{border-color:var(--dropdown-border-hover)}.dropdown-open .dropdown-field{border-color:var(--dropdown-border-focus);box-shadow:0 0 0 1px #68479b1f}.dropdown-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--dropdown-background);color:var(--dropdown-label-color);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.dropdown-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--dropdown-text-color)}.dropdown-placeholder{color:var(--dropdown-placeholder-color)}.dropdown-arrow{position:absolute;right:18px;top:50%;width:9px;height:9px;border-right:2px solid var(--dropdown-arrow-color);border-bottom:2px solid var(--dropdown-arrow-color);transform:translateY(-65%) rotate(45deg);transition:transform .2s ease}.dropdown-arrow.arrow-up{transform:translateY(-25%) rotate(225deg)}.dropdown-menu{position:absolute;top:calc(100% + 6px);left:0;width:100%;z-index:1000;overflow:hidden;background:var(--dropdown-menu-background);border:1px solid #d0d0d0;border-radius:var(--dropdown-radius);box-shadow:var(--dropdown-shadow)}.dropdown-search{padding:8px;border-bottom:1px solid #eeeeee}.dropdown-search-input{width:100%;height:38px;box-sizing:border-box;padding:0 12px;border:1px solid var(--dropdown-search-border);border-radius:5px;outline:none;background:#fff;color:var(--dropdown-text-color);font-family:var(--dropdown-font-family);font-size:14px}.dropdown-search-input:focus{border-color:var(--dropdown-border-focus)}.dropdown-options{max-height:240px;overflow-y:auto}.dropdown-option{min-height:42px;display:flex;align-items:center;padding:0 14px;box-sizing:border-box;color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);cursor:pointer;transition:background-color .15s ease}.dropdown-option:hover{background:var(--dropdown-option-hover)}.dropdown-option.option-selected{background:var(--dropdown-option-selected);color:var(--dropdown-border-focus);font-weight:600}.dropdown-option.option-disabled{color:#aaa;cursor:not-allowed;background:transparent}.dropdown-no-result{min-height:50px;display:flex;align-items:center;justify-content:center;padding:0 15px;color:#888;font-size:13px}.dropdown-disabled .dropdown-field{background:var(--dropdown-disabled);color:#999;border-color:#d0d0d0;cursor:not-allowed}.dropdown-options::-webkit-scrollbar{width:6px}.dropdown-options::-webkit-scrollbar-thumb{background:#c5c5c5;border-radius:10px}@media(max-width:768px){:host{width:100%}.dropdown-field{height:var(--dropdown-height)}}\n"] });
623
686
  }
624
687
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Dropdown, decorators: [{
625
688
  type: Component,
626
- args: [{ selector: 'lib-dropdown', standalone: true, imports: [], template: "<div\n class=\"dropdown-container\"\n [class]=\"customClass\"\n [class.dropdown-disabled]=\"disabled\"\n [class.dropdown-open]=\"isOpen\"\n>\n\n <!-- =====================================\n DROPDOWN FIELD\n ===================================== -->\n\n <div\n class=\"dropdown-field\"\n (click)=\"toggleDropdown($event)\"\n >\n\n <!-- Label -->\n\n @if (label) {\n <label class=\"dropdown-label\">\n {{ label }}\n </label>\n }\n\n\n <!-- Selected value -->\n\n <span\n class=\"dropdown-value\"\n [class.dropdown-placeholder]=\"!selectedOption\"\n >\n {{\n selectedOption?.label ||\n placeholder\n }}\n </span>\n\n\n <!-- Arrow -->\n\n <span\n class=\"dropdown-arrow\"\n [class.arrow-up]=\"isOpen\"\n >\n </span>\n\n </div>\n\n\n <!-- =====================================\n DROPDOWN MENU\n ===================================== -->\n\n @if (isOpen) {\n\n <div\n class=\"dropdown-menu\"\n (click)=\"$event.stopPropagation()\"\n >\n\n <!-- Search -->\n\n @if (searchable) {\n\n <div class=\"dropdown-search\">\n\n <input\n type=\"text\"\n class=\"dropdown-search-input\"\n\n placeholder=\"Search...\"\n\n [value]=\"searchText\"\n\n (input)=\"onSearch($event)\"\n />\n\n </div>\n\n }\n\n\n <!-- Options -->\n\n <div class=\"dropdown-options\">\n\n @for (\n option of filteredOptions;\n track option.value\n ) {\n\n <div\n class=\"dropdown-option\"\n\n [class.option-disabled]=\"\n option.disabled\n \"\n\n [class.option-selected]=\"\n option.value === value\n \"\n\n (click)=\"\n selectOption(option, $event)\n \"\n >\n\n {{ option.label }}\n\n </div>\n\n }\n\n\n <!-- No result -->\n\n @if (filteredOptions.length === 0) {\n\n <div class=\"dropdown-no-result\">\n No results found\n </div>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [".dropdown-container{--dropdown-width: 300px;--dropdown-height: 44px;--dropdown-background: #ffffff;--dropdown-border: 1px solid #a9a9a9;--dropdown-border-hover: #777777;--dropdown-border-focus: #68479b;--dropdown-radius: 6px;--dropdown-text-color: #222222;--dropdown-placeholder-color: #777777;--dropdown-menu-background: #ffffff;--dropdown-option-hover: #f3f0f7;--dropdown-option-selected: #eee8f5;--dropdown-disabled: #f5f5f5;--dropdown-font-family: Arial, Helvetica, sans-serif;--dropdown-font-size: 14px;--dropdown-font-weight: 600;--dropdown-shadow: 0 4px 12px rgba(0, 0, 0, .12);position:relative;width:var(--dropdown-width);font-family:var(--dropdown-font-family);box-sizing:border-box}.dropdown-field{position:relative;width:100%;height:var(--dropdown-height);display:flex;align-items:center;box-sizing:border-box;padding:0 48px 0 18px;border:var(--dropdown-border);border-radius:var(--dropdown-radius);background:var(--dropdown-background);color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);font-weight:var(--dropdown-font-weight);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease}.dropdown-field:hover{border-color:var(--dropdown-border-hover)}.dropdown-open .dropdown-field{border-color:var(--dropdown-border-focus);box-shadow:0 0 0 1px #68479b1f}.dropdown-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--dropdown-background);color:var(--dropdown-border-focus);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.dropdown-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--dropdown-text-color)}.dropdown-placeholder{color:var(--dropdown-placeholder-color)}.dropdown-arrow{position:absolute;right:18px;top:50%;width:9px;height:9px;border-right:2px solid #555;border-bottom:2px solid #555;transform:translateY(-65%) rotate(45deg);transition:transform .2s ease}.dropdown-arrow.arrow-up{transform:translateY(-25%) rotate(225deg)}.dropdown-menu{position:absolute;top:calc(100% + 6px);left:0;width:100%;z-index:1000;overflow:hidden;background:var(--dropdown-menu-background);border:1px solid #d0d0d0;border-radius:var(--dropdown-radius);box-shadow:var(--dropdown-shadow)}.dropdown-search{padding:8px;border-bottom:1px solid #eeeeee}.dropdown-search-input{width:100%;height:38px;box-sizing:border-box;padding:0 12px;border:1px solid #cfcfcf;border-radius:5px;outline:none;background:#fff;font-family:var(--dropdown-font-family);font-size:14px}.dropdown-search-input:focus{border-color:var(--dropdown-border-focus)}.dropdown-options{max-height:240px;overflow-y:auto}.dropdown-option{min-height:42px;display:flex;align-items:center;padding:0 14px;box-sizing:border-box;color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);cursor:pointer;transition:background-color .15s ease}.dropdown-option:hover{background:var(--dropdown-option-hover)}.dropdown-option.option-selected{background:var(--dropdown-option-selected);color:var(--dropdown-border-focus);font-weight:600}.dropdown-option.option-disabled{color:#aaa;cursor:not-allowed;background:transparent}.dropdown-no-result{min-height:50px;display:flex;align-items:center;justify-content:center;padding:0 15px;color:#888;font-size:13px}.dropdown-disabled .dropdown-field{background:var(--dropdown-disabled);color:#999;border-color:#d0d0d0;cursor:not-allowed}.dropdown-options::-webkit-scrollbar{width:6px}.dropdown-options::-webkit-scrollbar-thumb{background:#c5c5c5;border-radius:10px}@media(max-width:768px){.dropdown-container{width:100%}.dropdown-field{height:var(--dropdown-height)}}\n"] }]
627
- }], propDecorators: { label: [{
689
+ args: [{ selector: 'lib-dropdown', standalone: true, imports: [], template: "<div class=\"dropdown-container\" [class.dropdown-disabled]=\"disabled\" [class.dropdown-open]=\"isOpen\">\n\n <div class=\"dropdown-field\" (click)=\"toggleDropdown($event)\">\n\n <!-- Label -->\n\n @if (label) {\n\n <label class=\"dropdown-label\">\n {{ label }}\n </label>\n\n }\n\n\n <!-- Selected Value -->\n\n <span class=\"dropdown-value\" [class.dropdown-placeholder]=\"\n !selectedOption\n \">\n\n {{\n selectedOption?.label ||\n placeholder\n }}\n\n </span>\n\n\n <!-- Arrow -->\n\n <span class=\"dropdown-arrow\" [class.arrow-up]=\"isOpen\"></span>\n\n </div>\n\n\n @if (isOpen) {\n\n <div class=\"dropdown-menu\" (click)=\"$event.stopPropagation()\">\n\n <!-- SEARCH -->\n\n @if (searchable) {\n\n <div class=\"dropdown-search\">\n\n <input type=\"text\" class=\"dropdown-search-input\" placeholder=\"Search...\" [value]=\"searchText\"\n (input)=\"onSearch($event)\" />\n\n </div>\n\n }\n\n\n <!-- OPTIONS -->\n\n <div class=\"dropdown-options\">\n\n @for (\n option of filteredOptions;\n track option.value\n ) {\n\n <div class=\"dropdown-option\" [class.option-disabled]=\"\n option.disabled\n \" [class.option-selected]=\"\n option.value === value\n \" (click)=\"\n selectOption(option, $event)\n \">\n\n {{ option.label }}\n\n </div>\n\n }\n\n\n <!-- NO RESULTS -->\n\n @if (\n filteredOptions.length === 0\n ) {\n\n <div class=\"dropdown-no-result\">\n\n No results found\n\n </div>\n\n }\n\n </div>\n\n </div>\n\n }\n\n</div>", styles: [":host{--dropdown-width: 300px;--dropdown-height: 44px;--dropdown-background: #ffffff;--dropdown-border: 1px solid #a9a9a9;--dropdown-border-hover: #777777;--dropdown-border-focus: #68479b;--dropdown-radius: 6px;--dropdown-text-color: #222222;--dropdown-placeholder-color: #777777;--dropdown-menu-background: #ffffff;--dropdown-option-hover: #f3f0f7;--dropdown-option-selected: #eee8f5;--dropdown-disabled: #f5f5f5;--dropdown-font-family: Arial, Helvetica, sans-serif;--dropdown-font-size: 14px;--dropdown-font-weight: 600;--dropdown-shadow: 0 4px 12px rgba(0, 0, 0, .12);--dropdown-label-color: #68479b;--dropdown-arrow-color: #555555;--dropdown-search-border: #cfcfcf;display:block;position:relative;width:var(--dropdown-width);box-sizing:border-box}.dropdown-container{position:relative;width:100%;font-family:var(--dropdown-font-family);box-sizing:border-box}.dropdown-field{position:relative;width:100%;height:var(--dropdown-height);display:flex;align-items:center;box-sizing:border-box;padding:0 48px 0 18px;border:var(--dropdown-border);border-radius:var(--dropdown-radius);background:var(--dropdown-background);color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);font-weight:var(--dropdown-font-weight);cursor:pointer;transition:border-color .2s ease,box-shadow .2s ease}.dropdown-field:hover{border-color:var(--dropdown-border-hover)}.dropdown-open .dropdown-field{border-color:var(--dropdown-border-focus);box-shadow:0 0 0 1px #68479b1f}.dropdown-label{position:absolute;top:0;left:14px;transform:translateY(-50%);padding:0 6px;background:var(--dropdown-background);color:var(--dropdown-label-color);font-size:13px;font-weight:500;line-height:1;pointer-events:none}.dropdown-value{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color:var(--dropdown-text-color)}.dropdown-placeholder{color:var(--dropdown-placeholder-color)}.dropdown-arrow{position:absolute;right:18px;top:50%;width:9px;height:9px;border-right:2px solid var(--dropdown-arrow-color);border-bottom:2px solid var(--dropdown-arrow-color);transform:translateY(-65%) rotate(45deg);transition:transform .2s ease}.dropdown-arrow.arrow-up{transform:translateY(-25%) rotate(225deg)}.dropdown-menu{position:absolute;top:calc(100% + 6px);left:0;width:100%;z-index:1000;overflow:hidden;background:var(--dropdown-menu-background);border:1px solid #d0d0d0;border-radius:var(--dropdown-radius);box-shadow:var(--dropdown-shadow)}.dropdown-search{padding:8px;border-bottom:1px solid #eeeeee}.dropdown-search-input{width:100%;height:38px;box-sizing:border-box;padding:0 12px;border:1px solid var(--dropdown-search-border);border-radius:5px;outline:none;background:#fff;color:var(--dropdown-text-color);font-family:var(--dropdown-font-family);font-size:14px}.dropdown-search-input:focus{border-color:var(--dropdown-border-focus)}.dropdown-options{max-height:240px;overflow-y:auto}.dropdown-option{min-height:42px;display:flex;align-items:center;padding:0 14px;box-sizing:border-box;color:var(--dropdown-text-color);font-size:var(--dropdown-font-size);cursor:pointer;transition:background-color .15s ease}.dropdown-option:hover{background:var(--dropdown-option-hover)}.dropdown-option.option-selected{background:var(--dropdown-option-selected);color:var(--dropdown-border-focus);font-weight:600}.dropdown-option.option-disabled{color:#aaa;cursor:not-allowed;background:transparent}.dropdown-no-result{min-height:50px;display:flex;align-items:center;justify-content:center;padding:0 15px;color:#888;font-size:13px}.dropdown-disabled .dropdown-field{background:var(--dropdown-disabled);color:#999;border-color:#d0d0d0;cursor:not-allowed}.dropdown-options::-webkit-scrollbar{width:6px}.dropdown-options::-webkit-scrollbar-thumb{background:#c5c5c5;border-radius:10px}@media(max-width:768px){:host{width:100%}.dropdown-field{height:var(--dropdown-height)}}\n"] }]
690
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{
628
691
  type: Input
629
692
  }], placeholder: [{
630
693
  type: Input
@@ -638,6 +701,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
638
701
  type: Input
639
702
  }], customClass: [{
640
703
  type: Input
704
+ }, {
705
+ type: HostBinding,
706
+ args: ['class']
641
707
  }], valueChange: [{
642
708
  type: Output
643
709
  }], selectionChange: [{
@@ -648,7 +714,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
648
714
  type: Output
649
715
  }], onDocumentClick: [{
650
716
  type: HostListener,
651
- args: ['document:click', ['$event']]
717
+ args: ['document:click',
718
+ ['$event']]
719
+ }] } });
720
+
721
+ class GraphCard {
722
+ // =========================================
723
+ // INPUTS
724
+ // =========================================
725
+ title = 'GMT';
726
+ customClass = '';
727
+ clickable = false;
728
+ disabled = false;
729
+ // =========================================
730
+ // OUTPUT
731
+ // =========================================
732
+ clicked = new EventEmitter();
733
+ // =========================================
734
+ // CLICK
735
+ // =========================================
736
+ onClick(event) {
737
+ if (!this.clickable ||
738
+ this.disabled) {
739
+ return;
740
+ }
741
+ this.clicked.emit(event);
742
+ }
743
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: GraphCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
744
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: GraphCard, isStandalone: true, selector: "lib-graph-card", inputs: { title: "title", customClass: "customClass", clickable: "clickable", disabled: "disabled" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<div\n class=\"balina-card\"\n [class]=\"customClass\"\n [class.card-clickable]=\"clickable\"\n [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\"\n>\n\n <!-- =====================================\n TITLE\n ===================================== -->\n\n <h2 class=\"card-title\">\n {{ title }}\n </h2>\n\n\n <!-- =====================================\n DEVELOPER CONTENT\n ===================================== -->\n\n <div class=\"card-content\">\n\n <ng-content></ng-content>\n\n </div>\n\n</div>", styles: [".balina-card{--card-width: 100%;--card-min-height: 400px;--card-padding: 30px;--card-background: #ffffff;--card-border: 3px solid #cccccc;--card-title-color: #000000;--card-content-color: #000000;--card-radius: 12px;--card-title-size: 40px;--card-title-weight: 700;--card-title-line-height: 1.2;--card-content-gap: 20px;--card-title-content-gap: 25px;--card-font-family: Arial, Helvetica, sans-serif;width:var(--card-width);min-height:var(--card-min-height);height:auto;box-sizing:border-box;display:flex;flex-direction:column;padding:var(--card-padding);background:var(--card-background);border:var(--card-border);border-radius:var(--card-radius);color:var(--card-content-color);font-family:var(--card-font-family);overflow:hidden;transition:box-shadow .2s ease,transform .2s ease,opacity .2s ease}.card-title{flex:0 0 auto;margin:0;padding:0;color:var(--card-title-color);font-size:var(--card-title-size);font-weight:var(--card-title-weight);line-height:var(--card-title-line-height);word-break:break-word}.card-content{width:100%;min-width:0;display:flex;flex-direction:column;gap:var(--card-content-gap);margin-top:var(--card-title-content-gap);box-sizing:border-box}.card-content img{display:block;max-width:100%;height:auto;object-fit:contain;border-radius:8px}.card-content canvas{display:block;max-width:100%;height:auto}.card-content>*{max-width:100%;box-sizing:border-box}.card-content p{margin:0;color:var(--card-content-color);line-height:1.5;word-break:break-word}.card-content button{box-sizing:border-box;cursor:pointer}.card-clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.card-clickable:hover{transform:translateY(-1px);box-shadow:0 5px 15px #0000001f}.card-clickable:active{transform:translateY(0);box-shadow:0 2px 6px #0000001a}.card-disabled{opacity:.55;pointer-events:none;cursor:not-allowed;box-shadow:none;transform:none}.chart-card{--card-width: 500px;--card-min-height: 400px;--card-padding: 30px;--card-title-size: 40px}.image-card{--card-width: 500px;--card-min-height: 300px;--card-padding: 25px;--card-title-size: 32px}.large-card{--card-width: 800px;--card-min-height: 500px;--card-padding: 40px;--card-title-size: 42px}@media(max-width:768px){.balina-card{--card-min-height: 350px;--card-padding: 24px;--card-title-size: 32px;--card-content-gap: 16px;--card-title-content-gap: 20px}}@media(max-width:480px){.balina-card{--card-min-height: 300px;--card-padding: 18px;--card-title-size: 28px;--card-content-gap: 14px;--card-title-content-gap: 18px;--card-radius: 10px}}@media(max-width:360px){.balina-card{--card-padding: 14px;--card-title-size: 24px}}\n"] });
745
+ }
746
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: GraphCard, decorators: [{
747
+ type: Component,
748
+ args: [{ selector: 'lib-graph-card', standalone: true, imports: [], template: "<div\n class=\"balina-card\"\n [class]=\"customClass\"\n [class.card-clickable]=\"clickable\"\n [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\"\n>\n\n <!-- =====================================\n TITLE\n ===================================== -->\n\n <h2 class=\"card-title\">\n {{ title }}\n </h2>\n\n\n <!-- =====================================\n DEVELOPER CONTENT\n ===================================== -->\n\n <div class=\"card-content\">\n\n <ng-content></ng-content>\n\n </div>\n\n</div>", styles: [".balina-card{--card-width: 100%;--card-min-height: 400px;--card-padding: 30px;--card-background: #ffffff;--card-border: 3px solid #cccccc;--card-title-color: #000000;--card-content-color: #000000;--card-radius: 12px;--card-title-size: 40px;--card-title-weight: 700;--card-title-line-height: 1.2;--card-content-gap: 20px;--card-title-content-gap: 25px;--card-font-family: Arial, Helvetica, sans-serif;width:var(--card-width);min-height:var(--card-min-height);height:auto;box-sizing:border-box;display:flex;flex-direction:column;padding:var(--card-padding);background:var(--card-background);border:var(--card-border);border-radius:var(--card-radius);color:var(--card-content-color);font-family:var(--card-font-family);overflow:hidden;transition:box-shadow .2s ease,transform .2s ease,opacity .2s ease}.card-title{flex:0 0 auto;margin:0;padding:0;color:var(--card-title-color);font-size:var(--card-title-size);font-weight:var(--card-title-weight);line-height:var(--card-title-line-height);word-break:break-word}.card-content{width:100%;min-width:0;display:flex;flex-direction:column;gap:var(--card-content-gap);margin-top:var(--card-title-content-gap);box-sizing:border-box}.card-content img{display:block;max-width:100%;height:auto;object-fit:contain;border-radius:8px}.card-content canvas{display:block;max-width:100%;height:auto}.card-content>*{max-width:100%;box-sizing:border-box}.card-content p{margin:0;color:var(--card-content-color);line-height:1.5;word-break:break-word}.card-content button{box-sizing:border-box;cursor:pointer}.card-clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.card-clickable:hover{transform:translateY(-1px);box-shadow:0 5px 15px #0000001f}.card-clickable:active{transform:translateY(0);box-shadow:0 2px 6px #0000001a}.card-disabled{opacity:.55;pointer-events:none;cursor:not-allowed;box-shadow:none;transform:none}.chart-card{--card-width: 500px;--card-min-height: 400px;--card-padding: 30px;--card-title-size: 40px}.image-card{--card-width: 500px;--card-min-height: 300px;--card-padding: 25px;--card-title-size: 32px}.large-card{--card-width: 800px;--card-min-height: 500px;--card-padding: 40px;--card-title-size: 42px}@media(max-width:768px){.balina-card{--card-min-height: 350px;--card-padding: 24px;--card-title-size: 32px;--card-content-gap: 16px;--card-title-content-gap: 20px}}@media(max-width:480px){.balina-card{--card-min-height: 300px;--card-padding: 18px;--card-title-size: 28px;--card-content-gap: 14px;--card-title-content-gap: 18px;--card-radius: 10px}}@media(max-width:360px){.balina-card{--card-padding: 14px;--card-title-size: 24px}}\n"] }]
749
+ }], propDecorators: { title: [{
750
+ type: Input
751
+ }], customClass: [{
752
+ type: Input
753
+ }], clickable: [{
754
+ type: Input
755
+ }], disabled: [{
756
+ type: Input
757
+ }], clicked: [{
758
+ type: Output
759
+ }] } });
760
+
761
+ class FlightCard {
762
+ // CONTENT INPUTS
763
+ flightNumber = ' ';
764
+ route = ' ';
765
+ date = ' ';
766
+ airTime = ' ';
767
+ description = ' ';
768
+ // BEHAVIOR INPUTS
769
+ clickable = false;
770
+ disabled = false;
771
+ customClass = ' ';
772
+ // EVENTS
773
+ clicked = new EventEmitter();
774
+ // CLICK
775
+ onClick(event) {
776
+ if (!this.clickable ||
777
+ this.disabled) {
778
+ return;
779
+ }
780
+ this.clicked.emit(event);
781
+ }
782
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: FlightCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
783
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.2", type: FlightCard, isStandalone: true, selector: "lib-flight-card", inputs: { flightNumber: "flightNumber", route: "route", date: "date", airTime: "airTime", description: "description", clickable: "clickable", disabled: "disabled", customClass: "customClass" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<div class=\"flight-card\" [class]=\"customClass\" [class.card-clickable]=\"clickable\" [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\">\n\n <div class=\"flight-header\">\n\n <div class=\"flight-icon\">\n \u2708\n </div>\n\n <h2 class=\"flight-title\">\n Flight : {{ flightNumber }}\n </h2>\n\n </div>\n\n <div class=\"flight-info\">\n\n <div class=\"flight-route\">\n {{ route }}\n </div>\n\n <div class=\"flight-date\">\n {{ date }}\n </div>\n\n <div class=\"flight-air-time\">\n Air Time&nbsp; : &nbsp;{{ airTime }}\n </div>\n\n </div>\n\n\n <div class=\"flight-divider\"></div>\n\n <div class=\"flight-description\">\n {{ description }}\n </div>\n\n</div>", styles: [".flight-card{--flight-card-width: 100%;--flight-card-min-height: 420px;--flight-card-padding: 38px 42px;--flight-card-background: #ffffff;--flight-card-border: #e1e1e1;--flight-card-text: #111111;--flight-card-icon: #3478f6;--flight-card-divider: #eeeeee;--flight-card-border-width: 2px;--flight-card-radius: 12px;--flight-header-gap: 24px;--flight-info-gap: 26px;--flight-description-gap: 32px;--flight-font-family: Arial, Helvetica, sans-serif;--flight-title-size: 30px;--flight-route-size: 28px;--flight-date-size: 27px;--flight-air-time-size: 27px;--flight-description-size: 20px;width:var(--flight-card-width);min-height:var(--flight-card-min-height);box-sizing:border-box;padding:var(--flight-card-padding);display:flex;flex-direction:column;background:var(--flight-card-background);border:var(--flight-card-border-width) solid var(--flight-card-border);border-radius:var(--flight-card-radius);color:var(--flight-card-text);font-family:var(--flight-font-family);box-shadow:0 3px 6px #00000026;transition:box-shadow .2s ease,transform .2s ease}.card-clickable{cursor:pointer}.card-clickable:hover{transform:translateY(-1px);box-shadow:0 5px 12px #00000026}.flight-header{display:flex;align-items:center;gap:var(--flight-header-gap)}.flight-icon{flex:0 0 auto;display:flex;align-items:center;justify-content:center;color:var(--flight-card-icon);font-size:40px;line-height:1;transform:rotate(-8deg)}.flight-title{margin:0;font-size:var(--flight-title-size);font-weight:700;line-height:1.2}.flight-info{display:flex;flex-direction:column;gap:var(--flight-info-gap);margin-top:48px}.flight-route{font-size:var(--flight-route-size);font-weight:500;line-height:1.3}.flight-date{font-size:var(--flight-date-size);font-weight:500;line-height:1.3}.flight-air-time{font-size:var(--flight-air-time-size);font-weight:500;line-height:1.3}.flight-divider{width:100%;height:6px;flex-shrink:0;margin-top:20px;background:var(--flight-card-divider)}.flight-description{margin-top:var(--flight-description-gap);font-size:var(--flight-description-size);font-weight:400;line-height:1.35}.card-disabled{opacity:.55;pointer-events:none;box-shadow:none}@media(max-width:768px){.flight-card{--flight-card-padding: 28px;--flight-title-size: 25px;--flight-route-size: 22px;--flight-date-size: 21px;--flight-air-time-size: 21px;--flight-description-size: 17px}.flight-header{gap:16px}.flight-icon{font-size:32px}.flight-info{margin-top:35px}}@media(max-width:480px){.flight-card{--flight-card-padding: 20px;--flight-title-size: 21px;--flight-route-size: 18px;--flight-date-size: 18px;--flight-air-time-size: 18px;--flight-description-size: 15px}.flight-info{gap:18px;margin-top:28px}.flight-icon{font-size:28px}}\n"] });
784
+ }
785
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: FlightCard, decorators: [{
786
+ type: Component,
787
+ args: [{ selector: 'lib-flight-card', standalone: true, imports: [], template: "<div class=\"flight-card\" [class]=\"customClass\" [class.card-clickable]=\"clickable\" [class.card-disabled]=\"disabled\"\n (click)=\"onClick($event)\">\n\n <div class=\"flight-header\">\n\n <div class=\"flight-icon\">\n \u2708\n </div>\n\n <h2 class=\"flight-title\">\n Flight : {{ flightNumber }}\n </h2>\n\n </div>\n\n <div class=\"flight-info\">\n\n <div class=\"flight-route\">\n {{ route }}\n </div>\n\n <div class=\"flight-date\">\n {{ date }}\n </div>\n\n <div class=\"flight-air-time\">\n Air Time&nbsp; : &nbsp;{{ airTime }}\n </div>\n\n </div>\n\n\n <div class=\"flight-divider\"></div>\n\n <div class=\"flight-description\">\n {{ description }}\n </div>\n\n</div>", styles: [".flight-card{--flight-card-width: 100%;--flight-card-min-height: 420px;--flight-card-padding: 38px 42px;--flight-card-background: #ffffff;--flight-card-border: #e1e1e1;--flight-card-text: #111111;--flight-card-icon: #3478f6;--flight-card-divider: #eeeeee;--flight-card-border-width: 2px;--flight-card-radius: 12px;--flight-header-gap: 24px;--flight-info-gap: 26px;--flight-description-gap: 32px;--flight-font-family: Arial, Helvetica, sans-serif;--flight-title-size: 30px;--flight-route-size: 28px;--flight-date-size: 27px;--flight-air-time-size: 27px;--flight-description-size: 20px;width:var(--flight-card-width);min-height:var(--flight-card-min-height);box-sizing:border-box;padding:var(--flight-card-padding);display:flex;flex-direction:column;background:var(--flight-card-background);border:var(--flight-card-border-width) solid var(--flight-card-border);border-radius:var(--flight-card-radius);color:var(--flight-card-text);font-family:var(--flight-font-family);box-shadow:0 3px 6px #00000026;transition:box-shadow .2s ease,transform .2s ease}.card-clickable{cursor:pointer}.card-clickable:hover{transform:translateY(-1px);box-shadow:0 5px 12px #00000026}.flight-header{display:flex;align-items:center;gap:var(--flight-header-gap)}.flight-icon{flex:0 0 auto;display:flex;align-items:center;justify-content:center;color:var(--flight-card-icon);font-size:40px;line-height:1;transform:rotate(-8deg)}.flight-title{margin:0;font-size:var(--flight-title-size);font-weight:700;line-height:1.2}.flight-info{display:flex;flex-direction:column;gap:var(--flight-info-gap);margin-top:48px}.flight-route{font-size:var(--flight-route-size);font-weight:500;line-height:1.3}.flight-date{font-size:var(--flight-date-size);font-weight:500;line-height:1.3}.flight-air-time{font-size:var(--flight-air-time-size);font-weight:500;line-height:1.3}.flight-divider{width:100%;height:6px;flex-shrink:0;margin-top:20px;background:var(--flight-card-divider)}.flight-description{margin-top:var(--flight-description-gap);font-size:var(--flight-description-size);font-weight:400;line-height:1.35}.card-disabled{opacity:.55;pointer-events:none;box-shadow:none}@media(max-width:768px){.flight-card{--flight-card-padding: 28px;--flight-title-size: 25px;--flight-route-size: 22px;--flight-date-size: 21px;--flight-air-time-size: 21px;--flight-description-size: 17px}.flight-header{gap:16px}.flight-icon{font-size:32px}.flight-info{margin-top:35px}}@media(max-width:480px){.flight-card{--flight-card-padding: 20px;--flight-title-size: 21px;--flight-route-size: 18px;--flight-date-size: 18px;--flight-air-time-size: 18px;--flight-description-size: 15px}.flight-info{gap:18px;margin-top:28px}.flight-icon{font-size:28px}}\n"] }]
788
+ }], propDecorators: { flightNumber: [{
789
+ type: Input
790
+ }], route: [{
791
+ type: Input
792
+ }], date: [{
793
+ type: Input
794
+ }], airTime: [{
795
+ type: Input
796
+ }], description: [{
797
+ type: Input
798
+ }], clickable: [{
799
+ type: Input
800
+ }], disabled: [{
801
+ type: Input
802
+ }], customClass: [{
803
+ type: Input
804
+ }], clicked: [{
805
+ type: Output
806
+ }] } });
807
+
808
+ class Breadcrumb {
809
+ items = [
810
+ {
811
+ label: 'Dashboard',
812
+ url: '/dashboard'
813
+ }
814
+ ];
815
+ customClass = '';
816
+ clickable = true;
817
+ disabled = false;
818
+ clicked = new EventEmitter();
819
+ onClick(item, event) {
820
+ if (!this.clickable ||
821
+ this.disabled) {
822
+ return;
823
+ }
824
+ this.clicked.emit({
825
+ item,
826
+ event
827
+ });
828
+ }
829
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Breadcrumb, deps: [], target: i0.ɵɵFactoryTarget.Component });
830
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: Breadcrumb, isStandalone: true, selector: "lib-breadcrumb", inputs: { items: "items", customClass: "customClass", clickable: "clickable", disabled: "disabled" }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<nav\n class=\"balina-breadcrumb\"\n [class]=\"customClass\"\n [class.breadcrumb-clickable]=\"clickable\"\n [class.breadcrumb-disabled]=\"disabled\"\n aria-label=\"Breadcrumb\"\n>\n\n @for (item of items; track $index) {\n\n <div class=\"breadcrumb-item\">\n\n <span\n class=\"breadcrumb-label\"\n (click)=\"onClick(item, $event)\"\n >\n {{ item.label }}\n </span>\n\n @if (!$last) {\n\n <span\n class=\"breadcrumb-arrow\"\n aria-hidden=\"true\"\n >\n \u203A\n </span>\n\n }\n\n </div>\n\n }\n\n</nav>", styles: [".balina-breadcrumb{--breadcrumb-gap: 12px;--breadcrumb-font-size: 26px;--breadcrumb-font-weight: 600;--breadcrumb-color: #111111;--breadcrumb-arrow-color: #111111;--breadcrumb-arrow-size: 34px;--breadcrumb-font-family: Arial, Helvetica, sans-serif;width:100%;display:flex;align-items:center;gap:var(--breadcrumb-gap);box-sizing:border-box;font-family:var(--breadcrumb-font-family);font-size:var(--breadcrumb-font-size);font-weight:var(--breadcrumb-font-weight);color:var(--breadcrumb-color)}.breadcrumb-item{display:flex;align-items:center;gap:var(--breadcrumb-gap);white-space:nowrap}.breadcrumb-label{color:var(--breadcrumb-color);cursor:pointer;transition:opacity .2s ease}.breadcrumb-label:hover{opacity:.7}.breadcrumb-arrow{display:flex;align-items:center;justify-content:center;color:var(--breadcrumb-arrow-color);font-size:var(--breadcrumb-arrow-size);font-weight:300;line-height:1}.breadcrumb-disabled{opacity:.5;pointer-events:none}@media(max-width:768px){.balina-breadcrumb{--breadcrumb-font-size: 21px;--breadcrumb-arrow-size: 28px;--breadcrumb-gap: 8px}}\n"] });
831
+ }
832
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: Breadcrumb, decorators: [{
833
+ type: Component,
834
+ args: [{ selector: 'lib-breadcrumb', standalone: true, imports: [], template: "<nav\n class=\"balina-breadcrumb\"\n [class]=\"customClass\"\n [class.breadcrumb-clickable]=\"clickable\"\n [class.breadcrumb-disabled]=\"disabled\"\n aria-label=\"Breadcrumb\"\n>\n\n @for (item of items; track $index) {\n\n <div class=\"breadcrumb-item\">\n\n <span\n class=\"breadcrumb-label\"\n (click)=\"onClick(item, $event)\"\n >\n {{ item.label }}\n </span>\n\n @if (!$last) {\n\n <span\n class=\"breadcrumb-arrow\"\n aria-hidden=\"true\"\n >\n \u203A\n </span>\n\n }\n\n </div>\n\n }\n\n</nav>", styles: [".balina-breadcrumb{--breadcrumb-gap: 12px;--breadcrumb-font-size: 26px;--breadcrumb-font-weight: 600;--breadcrumb-color: #111111;--breadcrumb-arrow-color: #111111;--breadcrumb-arrow-size: 34px;--breadcrumb-font-family: Arial, Helvetica, sans-serif;width:100%;display:flex;align-items:center;gap:var(--breadcrumb-gap);box-sizing:border-box;font-family:var(--breadcrumb-font-family);font-size:var(--breadcrumb-font-size);font-weight:var(--breadcrumb-font-weight);color:var(--breadcrumb-color)}.breadcrumb-item{display:flex;align-items:center;gap:var(--breadcrumb-gap);white-space:nowrap}.breadcrumb-label{color:var(--breadcrumb-color);cursor:pointer;transition:opacity .2s ease}.breadcrumb-label:hover{opacity:.7}.breadcrumb-arrow{display:flex;align-items:center;justify-content:center;color:var(--breadcrumb-arrow-color);font-size:var(--breadcrumb-arrow-size);font-weight:300;line-height:1}.breadcrumb-disabled{opacity:.5;pointer-events:none}@media(max-width:768px){.balina-breadcrumb{--breadcrumb-font-size: 21px;--breadcrumb-arrow-size: 28px;--breadcrumb-gap: 8px}}\n"] }]
835
+ }], propDecorators: { items: [{
836
+ type: Input
837
+ }], customClass: [{
838
+ type: Input
839
+ }], clickable: [{
840
+ type: Input
841
+ }], disabled: [{
842
+ type: Input
843
+ }], clicked: [{
844
+ type: Output
652
845
  }] } });
653
846
 
654
847
  /*
@@ -659,5 +852,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
659
852
  * Generated bundle index. Do not edit.
660
853
  */
661
854
 
662
- export { BalinauiComponents, Button, Card, DateInput, Dropdown, Navbar, TextBox, TimeFilter };
855
+ export { BalinauiComponents, Breadcrumb, Button, Card, DateInput, Dropdown, FlightCard, GraphCard, Navbar, TextBox, TimeFilter };
663
856
  //# sourceMappingURL=balinasoftware-balinaui-components.mjs.map