@crowdfarming/oliva-ds 1.33.0-rc.2 → 1.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Input, Component, EventEmitter, Output, input, computed, output, signal, effect, forwardRef, inject, ElementRef, ViewContainerRef, ApplicationRef, PLATFORM_ID, DestroyRef, TemplateRef, ContentChild, ViewChild, HostListener, Directive, ViewEncapsulation, viewChild, Injector, createComponent, Injectable, model, HostBinding } from '@angular/core';
2
+ import { Input, Component, EventEmitter, Output, input, computed, output, signal, effect, forwardRef, inject, ElementRef, PLATFORM_ID, HostListener, ViewChild, Directive, viewChild, ApplicationRef, Injector, createComponent, Injectable, model, HostBinding } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
- import { CommonModule, NgClass, isPlatformBrowser, NgStyle, NgTemplateOutlet } from '@angular/common';
4
+ import { CommonModule, NgClass, isPlatformBrowser, NgStyle } from '@angular/common';
5
5
  import * as i1 from '@angular/platform-browser';
6
6
  import * as i1$2 from '@angular/router';
7
- import { RouterModule, Router, NavigationStart, RouterLink } from '@angular/router';
7
+ import { RouterModule, RouterLink } from '@angular/router';
8
8
  import * as i1$3 from '@angular/forms';
9
9
  import { NG_VALUE_ACCESSOR, ReactiveFormsModule, FormControl, FormsModule } from '@angular/forms';
10
- import { TemplatePortal, DomPortalOutlet, PortalModule, ComponentPortal } from '@angular/cdk/portal';
11
- import { FocusTrapFactory } from '@angular/cdk/a11y';
10
+ import { ComponentPortal } from '@angular/cdk/portal';
12
11
  import * as i1$4 from '@angular/cdk/overlay';
13
12
 
14
13
  // Auto-generated icons from Figma
@@ -3135,39 +3134,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImpor
3135
3134
  }] });
3136
3135
 
3137
3136
  class OverlayComponent {
3138
- static MOBILE_BREAKPOINT = 768;
3139
- static DROPDOWN_HEIGHT = 320;
3140
- static DROPDOWN_GAP = 2;
3141
- static VIEWPORT_MARGIN = 16;
3142
- static ANIMATION_DURATION = 20;
3143
- static DEFAULT_MENU_WIDTH = 200;
3137
+ // Inputs
3144
3138
  position = input('right');
3145
3139
  disabled = input(false);
3146
- width = input(`${OverlayComponent.DEFAULT_MENU_WIDTH}px`);
3140
+ width = input('200px');
3141
+ // Outputs
3147
3142
  opened = output();
3148
3143
  closed = output();
3144
+ // Private signals
3149
3145
  _isOpen = signal(false);
3150
3146
  _isClosing = signal(false);
3151
3147
  _isMobile = signal(false);
3152
- _menuPosition = signal({
3153
- top: 0,
3154
- left: 0,
3155
- width: OverlayComponent.DEFAULT_MENU_WIDTH,
3156
- });
3148
+ // Public computed signals
3157
3149
  isOpen = this._isOpen.asReadonly();
3158
3150
  isClosing = this._isClosing.asReadonly();
3159
- getMenuClasses = computed(() => ['c-overlay__menu', `c-overlay__menu--${this.position()}`].join(' '));
3160
- getMenuStyles = computed(() => {
3161
- if (this._isMobile()) {
3162
- return {};
3163
- }
3164
- const pos = this._menuPosition();
3165
- return {
3166
- width: `${pos.width}px`,
3167
- top: `${pos.top}px`,
3168
- left: `${pos.left}px`,
3169
- };
3170
- });
3151
+ // Computed class methods
3171
3152
  getClasses = computed(() => {
3172
3153
  const classes = ['c-overlay'];
3173
3154
  if (this.isOpen()) {
@@ -3182,540 +3163,105 @@ class OverlayComponent {
3182
3163
  }
3183
3164
  return classes.join(' ');
3184
3165
  });
3166
+ getMenuClasses = computed(() => {
3167
+ const classes = ['c-overlay__menu'];
3168
+ classes.push(`c-overlay__menu--${this.position()}`);
3169
+ return classes.join(' ');
3170
+ });
3171
+ getMenuStyles = computed(() => {
3172
+ return {
3173
+ width: this._isMobile() ? '100%' : this.width(),
3174
+ };
3175
+ });
3176
+ // Element references
3185
3177
  elementRef = inject(ElementRef);
3186
- viewContainerRef = inject(ViewContainerRef);
3187
- applicationRef = inject(ApplicationRef);
3188
- platformId = inject(PLATFORM_ID);
3189
- destroyRef = inject(DestroyRef);
3190
- focusTrapFactory = inject(FocusTrapFactory);
3191
- router = inject(Router);
3192
- // Portal and container management
3193
3178
  triggerButtonRef;
3194
- portal;
3195
- portalOutlet;
3196
- portalContainer;
3197
- boundPortalClickHandler;
3198
- // Focus and accessibility management
3199
- focusTrap;
3200
- previouslyFocusedElement;
3201
- triggerKeydownHandler;
3202
- inertElements = [];
3203
- escapeKeyHandler;
3204
- // Scroll and navigation management
3205
- originalBodyOverflow;
3206
- navigationSub;
3207
- // Helper to get the correct document context (important for Storybook)
3208
- getDocument() {
3209
- return this.elementRef.nativeElement.ownerDocument || document;
3210
- }
3211
- menuTemplate;
3212
- contentTemplate;
3213
- footerTemplate;
3179
+ platformId = inject(PLATFORM_ID);
3180
+ overlayMenu;
3214
3181
  constructor() {
3182
+ // Initialize mobile detection
3215
3183
  this.updateMobileDetection();
3184
+ // Only add resize listener if running in browser (not in SSR)
3216
3185
  if (isPlatformBrowser(this.platformId)) {
3217
3186
  window.addEventListener('resize', () => this.updateMobileDetection());
3218
3187
  }
3188
+ // Emit events when overlay state changes
3219
3189
  effect(() => {
3220
- if (this.isOpen())
3190
+ if (this.isOpen()) {
3221
3191
  this.opened.emit();
3222
- else if (!this.isOpen() && !this.isClosing())
3192
+ }
3193
+ else if (!this.isOpen() && !this.isClosing()) {
3223
3194
  this.closed.emit();
3224
- });
3225
- this.destroyRef.onDestroy(() => {
3226
- if (this.isOpen()) {
3227
- this.unblockBodyScroll();
3228
3195
  }
3229
- this.destroyFocusTrap();
3230
- this.cleanupTriggerListener();
3231
- this.navigationSub?.unsubscribe();
3232
- this.removeEscapeKeyListener();
3233
3196
  });
3234
3197
  }
3235
- // ================== MOBILE DETECTION ==================
3198
+ // Mobile detection method
3236
3199
  updateMobileDetection() {
3237
- this._isMobile.set(isPlatformBrowser(this.platformId)
3238
- ? window.innerWidth <= OverlayComponent.MOBILE_BREAKPOINT
3239
- : false);
3200
+ // Check if running in browser (not in SSR)
3201
+ if (isPlatformBrowser(this.platformId)) {
3202
+ this._isMobile.set(window.innerWidth <= 768);
3203
+ }
3204
+ else {
3205
+ // Default to desktop view during SSR
3206
+ this._isMobile.set(false);
3207
+ }
3240
3208
  }
3241
- // ================== TRIGGER MANAGEMENT ==================
3209
+ // Public methods for trigger directive
3242
3210
  setTriggerButton(element) {
3243
3211
  this.triggerButtonRef = element;
3244
- this.triggerKeydownHandler = (event) => {
3245
- if (event.key === 'Enter' || event.key === ' ') {
3246
- event.preventDefault();
3247
- this.toggleOverlay();
3248
- }
3249
- };
3250
- element.addEventListener('keydown', this.triggerKeydownHandler);
3251
3212
  }
3252
3213
  toggleOverlay() {
3253
- if (this.disabled())
3214
+ if (this.disabled()) {
3254
3215
  return;
3255
- if (this.isOpen() && !this.isClosing())
3216
+ }
3217
+ if (this.isOpen() && !this.isClosing()) {
3256
3218
  this.closeOverlay();
3257
- else if (!this.isOpen() && !this.isClosing())
3219
+ }
3220
+ else if (!this.isOpen() && !this.isClosing()) {
3258
3221
  this.openOverlay();
3222
+ }
3259
3223
  }
3260
- onBackdropClick() {
3261
- this.closeOverlay();
3262
- }
3263
- onEscapeKey() {
3264
- this.closeOverlay();
3265
- }
3266
- // ================== OVERLAY LIFECYCLE ==================
3267
3224
  openOverlay() {
3268
- this.initializeOverlayState();
3269
- this.prepareOverlayForOpening();
3270
- this.createOverlayPortal();
3271
- this.configureScrollBehavior();
3272
- this.finalizeOverlayOpening();
3273
- setTimeout(() => {
3274
- this.trapFocus();
3275
- this.makeOutsideElementsInert();
3276
- this.setupEscapeKeyListener();
3277
- }, 0);
3278
- }
3279
- initializeOverlayState() {
3280
3225
  this._isClosing.set(false);
3281
- this.updateMobileDetection();
3282
- this.previouslyFocusedElement = this.triggerButtonRef ?? this.getDocument().activeElement;
3283
- }
3284
- prepareOverlayForOpening() {
3285
- if (!this._isMobile()) {
3286
- this.calculatePosition();
3287
- }
3288
- }
3289
- createOverlayPortal() {
3290
- this.createPortal();
3291
- }
3292
- configureScrollBehavior() {
3293
- // Block scroll for both mobile and desktop
3294
- this.blockBodyScroll();
3295
- }
3296
- finalizeOverlayOpening() {
3297
3226
  this._isOpen.set(true);
3298
- this.addResizeListener();
3299
- this.listenToNavigation();
3300
3227
  }
3301
3228
  closeOverlay() {
3302
- this.initializeOverlayClosing();
3303
- this.cleanupOverlayResources();
3304
- this.restoreScrollBehavior();
3305
- this.destroyOverlayComponents();
3306
- // Restore focus AFTER destroying DOM to avoid interference
3307
- requestAnimationFrame(() => {
3308
- this.restoreFocusToTrigger();
3309
- });
3310
- this.scheduleOverlayFinalization();
3311
- }
3312
- initializeOverlayClosing() {
3313
3229
  this._isClosing.set(true);
3314
- }
3315
- cleanupOverlayResources() {
3316
- this.removeResizeListener();
3317
- this.unsubscribeFromNavigation();
3318
- }
3319
- unsubscribeFromNavigation() {
3320
- this.navigationSub?.unsubscribe();
3321
- this.navigationSub = undefined;
3322
- }
3323
- restoreScrollBehavior() {
3324
- // Unblock scroll for both mobile and desktop
3325
- this.unblockBodyScroll();
3326
- }
3327
- destroyOverlayComponents() {
3328
- this.destroyFocusTrap();
3329
- this.destroyPortal();
3330
- // Ensure elements are restored after destroying components
3331
- this.restoreOutsideElements();
3332
- }
3333
- scheduleOverlayFinalization() {
3334
3230
  setTimeout(() => {
3335
- this.finalizeOverlayClosing();
3336
- }, OverlayComponent.ANIMATION_DURATION);
3337
- }
3338
- finalizeOverlayClosing() {
3339
- this._isOpen.set(false);
3340
- this._isClosing.set(false);
3231
+ this._isOpen.set(false);
3232
+ this._isClosing.set(false);
3233
+ }, 20); // Match animation duration
3341
3234
  }
3342
- // ================== EVENT HANDLING ==================
3343
- onPortalClick = (event) => {
3344
- if (!this.isOpen() || this.isClosing())
3345
- return;
3346
- const target = event.target;
3347
- const onTrigger = this.triggerButtonRef?.contains(target);
3348
- if (onTrigger) {
3349
- return;
3350
- }
3351
- const menuEl = this.portalContainer?.querySelector('.c-overlay__menu');
3352
- const insideMenu = menuEl?.contains(target);
3353
- if (insideMenu) {
3354
- return;
3355
- }
3235
+ // Backdrop and keyboard handlers
3236
+ onBackdropClick() {
3356
3237
  this.closeOverlay();
3357
- };
3358
- // ================== POSITIONING ==================
3359
- calculatePosition() {
3360
- if (!this.triggerButtonRef)
3361
- return;
3362
- const rect = this.triggerButtonRef.getBoundingClientRect();
3363
- const menuWidth = this.parseWidth(rect.width);
3364
- const menuHeight = OverlayComponent.DROPDOWN_HEIGHT;
3365
- const viewportPosition = this.calculateViewportPosition(rect, menuWidth, menuHeight);
3366
- const finalPosition = this.convertToFinalCoordinates(viewportPosition, menuWidth, menuHeight);
3367
- this._menuPosition.set(finalPosition);
3368
- }
3369
- calculateViewportPosition(rect, menuWidth, menuHeight) {
3370
- const gap = OverlayComponent.DROPDOWN_GAP;
3371
- const viewportTop = this.calculateVerticalPosition(rect, menuHeight, gap);
3372
- const viewportLeft = this.calculateHorizontalPosition(rect, menuWidth);
3373
- return { top: viewportTop, left: viewportLeft };
3374
- }
3375
- calculateVerticalPosition(rect, menuHeight, gap) {
3376
- let top = rect.bottom + gap;
3377
- if (window.innerHeight - rect.bottom < menuHeight &&
3378
- rect.top > rect.bottom) {
3379
- top = rect.top - menuHeight - gap;
3380
- }
3381
- return top;
3382
- }
3383
- calculateHorizontalPosition(rect, menuWidth) {
3384
- const position = this.position();
3385
- switch (position) {
3386
- case 'right':
3387
- return rect.right - menuWidth;
3388
- case 'center': {
3389
- const triggerCenter = rect.left + rect.width / 2;
3390
- return triggerCenter;
3391
- }
3392
- case 'left':
3393
- default:
3394
- return rect.left;
3395
- }
3396
- }
3397
- convertToFinalCoordinates(viewportPosition, menuWidth, menuHeight) {
3398
- const scrollTop = window.pageYOffset || this.getDocument().documentElement.scrollTop;
3399
- const scrollLeft = window.pageXOffset || this.getDocument().documentElement.scrollLeft;
3400
- let top;
3401
- let left;
3402
- if (this._isMobile()) {
3403
- const clampedPosition = this.clampToViewport(viewportPosition, menuWidth, menuHeight);
3404
- top = clampedPosition.top;
3405
- left = clampedPosition.left;
3406
- }
3407
- else {
3408
- const clampedPosition = this.clampToViewport(viewportPosition, menuWidth, menuHeight);
3409
- top = clampedPosition.top + scrollTop;
3410
- left = clampedPosition.left + scrollLeft;
3411
- }
3412
- return { top, left, width: menuWidth };
3413
- }
3414
- clampToViewport(position, menuWidth, menuHeight) {
3415
- const clampedTop = Math.max(OverlayComponent.VIEWPORT_MARGIN, Math.min(position.top, window.innerHeight - menuHeight - OverlayComponent.VIEWPORT_MARGIN));
3416
- const clampedLeft = Math.max(OverlayComponent.VIEWPORT_MARGIN, Math.min(position.left, window.innerWidth - menuWidth - OverlayComponent.VIEWPORT_MARGIN));
3417
- return { top: clampedTop, left: clampedLeft };
3418
- }
3419
- parseWidth(triggerWidth) {
3420
- if (this.width() === 'stretch')
3421
- return triggerWidth;
3422
- const w = parseFloat(this.width());
3423
- return isNaN(w) ? OverlayComponent.DEFAULT_MENU_WIDTH : w;
3424
- }
3425
- // ================== RESIZE HANDLING ==================
3426
- addResizeListener() {
3427
- if (!isPlatformBrowser(this.platformId))
3428
- return;
3429
- window.addEventListener('resize', this.resizeHandler);
3430
- }
3431
- removeResizeListener() {
3432
- if (!isPlatformBrowser(this.platformId))
3433
- return;
3434
- window.removeEventListener('resize', this.resizeHandler);
3435
- }
3436
- resizeHandler = () => {
3437
- if (!this.isOpen())
3438
- return;
3439
- const wasMobile = this._isMobile();
3440
- this.updateMobileDetection();
3441
- const isNowMobile = this._isMobile();
3442
- if (wasMobile !== isNowMobile) {
3443
- this.destroyPortal();
3444
- this.createPortal();
3445
- if (!isNowMobile && this.triggerButtonRef) {
3446
- this.calculatePosition();
3447
- }
3448
- }
3449
- else if (!isNowMobile && this.triggerButtonRef) {
3450
- this.calculatePosition();
3451
- }
3452
- };
3453
- // ================== PORTAL MANAGEMENT ==================
3454
- createPortal() {
3455
- if (!this.menuTemplate || !this.contentTemplate)
3456
- return;
3457
- this.createPortalTemplate();
3458
- this.createPortalContainer();
3459
- this.setupPortalEventListeners();
3460
- this.createPortalOutlet();
3461
- this.attachPortalContent();
3462
- // Focus trap will be set up in openOverlay()
3463
- this.applyMenuPositioning();
3464
- }
3465
- createPortalTemplate() {
3466
- this.portal = new TemplatePortal(this.menuTemplate, this.viewContainerRef);
3467
- }
3468
- createPortalContainer() {
3469
- this.portalContainer = this.getDocument().createElement('div');
3470
- this.configurePortalContainerStyles();
3471
- this.getDocument().body.appendChild(this.portalContainer);
3472
- }
3473
- configurePortalContainerStyles() {
3474
- if (!this.portalContainer)
3475
- return;
3476
- this.portalContainer.style.position = this._isMobile() ? 'fixed' : 'absolute';
3477
- this.portalContainer.style.top = '0';
3478
- this.portalContainer.style.left = '0';
3479
- this.portalContainer.style.width = '100%';
3480
- this.portalContainer.style.height = '100%';
3481
- this.portalContainer.style.zIndex = '1000';
3482
- this.portalContainer.style.pointerEvents = 'auto';
3483
- }
3484
- setupPortalEventListeners() {
3485
- if (!this.portalContainer)
3486
- return;
3487
- this.boundPortalClickHandler = this.onPortalClick.bind(this);
3488
- this.portalContainer.addEventListener('click', this.boundPortalClickHandler);
3489
3238
  }
3490
- createPortalOutlet() {
3491
- if (!this.portalContainer)
3492
- return;
3493
- this.portalOutlet = new DomPortalOutlet(this.portalContainer, null, this.applicationRef, this.viewContainerRef.injector);
3494
- }
3495
- attachPortalContent() {
3496
- if (!this.portalOutlet || !this.portal)
3497
- return;
3498
- this.portalOutlet.attach(this.portal);
3499
- }
3500
- applyMenuPositioning() {
3501
- const menuEl = this.portalContainer?.querySelector('.c-overlay__menu');
3502
- if (!menuEl)
3503
- return;
3504
- this.configureMenuElement(menuEl);
3505
- this.applyPositioningStyles(menuEl);
3506
- }
3507
- configureMenuElement(menuEl) {
3508
- menuEl.style.pointerEvents = 'auto';
3509
- }
3510
- applyPositioningStyles(menuEl) {
3511
- if (this._isMobile()) {
3512
- this.applyMobilePositioning(menuEl);
3513
- }
3514
- else {
3515
- this.applyDesktopPositioning(menuEl);
3516
- }
3517
- }
3518
- applyMobilePositioning(menuEl) {
3519
- menuEl.style.position = '';
3520
- menuEl.style.top = '';
3521
- menuEl.style.left = '';
3522
- menuEl.style.width = '';
3523
- }
3524
- applyDesktopPositioning(menuEl) {
3525
- const pos = this._menuPosition();
3526
- menuEl.style.position = 'absolute';
3527
- menuEl.style.top = `${pos.top}px`;
3528
- menuEl.style.left = `${pos.left}px`;
3529
- menuEl.style.width = `${pos.width}px`;
3530
- }
3531
- destroyPortal() {
3532
- if (this.portalOutlet) {
3533
- this.portalOutlet.detach();
3534
- this.portalOutlet.dispose();
3535
- this.portalOutlet = undefined;
3536
- this.portal = undefined;
3537
- }
3538
- if (this.portalContainer && this.portalContainer.parentNode) {
3539
- if (this.boundPortalClickHandler) {
3540
- this.portalContainer.removeEventListener('click', this.boundPortalClickHandler);
3541
- this.boundPortalClickHandler = undefined;
3542
- }
3543
- this.portalContainer.parentNode.removeChild(this.portalContainer);
3544
- }
3545
- this.portalContainer = undefined;
3546
- }
3547
- // ================== SCROLL MANAGEMENT ==================
3548
- blockBodyScroll() {
3549
- if (!isPlatformBrowser(this.platformId))
3550
- return;
3551
- this.originalBodyOverflow = this.getDocument().body.style.overflow;
3552
- this.getDocument().body.style.overflow = 'hidden';
3553
- this.getDocument().body.style.position = 'fixed';
3554
- this.getDocument().body.style.width = '100%';
3555
- this.getDocument().body.style.top = `-${window.pageYOffset}px`;
3556
- this.getDocument().documentElement.style.overflow = 'hidden';
3557
- }
3558
- unblockBodyScroll() {
3559
- if (!isPlatformBrowser(this.platformId))
3560
- return;
3561
- const scrollY = this.getDocument().body.style.top;
3562
- if (this.originalBodyOverflow !== undefined) {
3563
- this.getDocument().body.style.overflow = this.originalBodyOverflow;
3564
- }
3565
- else {
3566
- this.getDocument().body.style.overflow = '';
3567
- }
3568
- this.getDocument().body.style.position = '';
3569
- this.getDocument().body.style.width = '';
3570
- this.getDocument().body.style.top = '';
3571
- this.getDocument().documentElement.style.overflow = '';
3572
- if (scrollY) {
3573
- window.scrollTo(0, parseInt(scrollY || '0') * -1);
3574
- }
3575
- this.originalBodyOverflow = undefined;
3576
- }
3577
- // ================== FOCUS MANAGEMENT ==================
3578
- trapFocus() {
3579
- if (!this.portalContainer) {
3580
- return;
3581
- }
3582
- // Search for menu element in entire document, not just within portalContainer
3583
- const doc = this.getDocument();
3584
- const menuEl = doc.querySelector('.c-overlay__menu');
3585
- if (!menuEl) {
3586
- setTimeout(() => this.trapFocus(), 10);
3587
- return;
3588
- }
3589
- // CDK FocusTrap
3590
- this.focusTrap = this.focusTrapFactory.create(menuEl);
3591
- this.focusTrap.focusInitialElement();
3239
+ onEscapeKey() {
3240
+ this.closeOverlay();
3592
3241
  }
3593
- // ================== ESCAPE KEY HANDLING ==================
3594
- setupEscapeKeyListener() {
3595
- if (!isPlatformBrowser(this.platformId))
3596
- return;
3597
- this.escapeKeyHandler = (event) => {
3598
- if (event.key === 'Escape' && this.isOpen() && !this.isClosing()) {
3599
- event.preventDefault();
3242
+ // Host listeners
3243
+ onClickOutside(event) {
3244
+ if (this.isOpen() && !this.isClosing()) {
3245
+ const clickedElement = event.target;
3246
+ const isClickInsideOverlay = this.elementRef.nativeElement.contains(clickedElement);
3247
+ const isClickOnTrigger = this.triggerButtonRef?.contains(clickedElement);
3248
+ if (!isClickInsideOverlay && !isClickOnTrigger) {
3600
3249
  this.closeOverlay();
3601
3250
  }
3602
- };
3603
- this.getDocument().addEventListener('keydown', this.escapeKeyHandler);
3604
- }
3605
- removeEscapeKeyListener() {
3606
- if (!isPlatformBrowser(this.platformId))
3607
- return;
3608
- if (this.escapeKeyHandler) {
3609
- this.getDocument().removeEventListener('keydown', this.escapeKeyHandler);
3610
- this.escapeKeyHandler = undefined;
3611
- }
3612
- }
3613
- // ================== FOCUS RESTORATION ==================
3614
- restoreFocusToTrigger() {
3615
- const doc = this.getDocument();
3616
- // Prefer to return focus to trigger button
3617
- if (this.triggerButtonRef && doc.contains(this.triggerButtonRef)) {
3618
- const focusableElement = this.findFocusableButton(this.triggerButtonRef);
3619
- if (focusableElement) {
3620
- focusableElement.focus({ preventScroll: true });
3621
- return;
3622
- }
3623
- }
3624
- // Si no hay trigger, devolvemos el foco al elemento que estaba activo antes
3625
- if (this.previouslyFocusedElement && doc.contains(this.previouslyFocusedElement)) {
3626
- const focusableElement = this.findFocusableButton(this.previouslyFocusedElement);
3627
- if (focusableElement) {
3628
- focusableElement.focus({ preventScroll: true });
3629
- return;
3630
- }
3631
3251
  }
3632
- // Safety fallback
3633
- doc.body.focus();
3634
- }
3635
- findFocusableButton(element) {
3636
- // If element is already a focusable button, return it
3637
- if (element.tagName === 'BUTTON' && !element.hasAttribute('disabled')) {
3638
- return element;
3639
- }
3640
- // If it's a lib-button or custom component, search for internal button
3641
- const button = element.querySelector('button:not([disabled])');
3642
- if (button) {
3643
- return button;
3644
- }
3645
- // Search for any focusable element inside
3646
- const focusableSelectors = [
3647
- 'button:not([disabled])',
3648
- 'input:not([disabled])',
3649
- 'select:not([disabled])',
3650
- 'textarea:not([disabled])',
3651
- 'a[href]',
3652
- '[tabindex]:not([tabindex="-1"])'
3653
- ];
3654
- const focusable = element.querySelector(focusableSelectors.join(', '));
3655
- return focusable;
3656
- }
3657
- releaseFocusTrap() {
3658
- if (this.focusTrap) {
3659
- this.focusTrap.destroy();
3660
- this.focusTrap = undefined;
3661
- }
3662
- this.removeEscapeKeyListener();
3663
- }
3664
- // ================== INERT OUTSIDE ELEMENTS ==================
3665
- makeOutsideElementsInert() {
3666
- if (!isPlatformBrowser(this.platformId))
3667
- return;
3668
- this.inertElements = [];
3669
- const doc = this.getDocument();
3670
- const bodyChildren = Array.from(doc.body.children);
3671
- bodyChildren.forEach(el => {
3672
- if (el !== this.portalContainer && !el.hasAttribute('aria-hidden')) {
3673
- el.inert = true; // Hace que no sean focusables ni interactuables
3674
- this.inertElements.push(el);
3675
- }
3676
- });
3677
- }
3678
- restoreOutsideElements() {
3679
- if (!isPlatformBrowser(this.platformId))
3680
- return;
3681
- this.inertElements.forEach(el => {
3682
- el.inert = false;
3683
- });
3684
- this.inertElements = [];
3685
- }
3686
- destroyFocusTrap() {
3687
- this.releaseFocusTrap();
3688
- this.restoreOutsideElements();
3689
- }
3690
- cleanupTriggerListener() {
3691
- if (this.triggerButtonRef && this.triggerKeydownHandler) {
3692
- this.triggerButtonRef.removeEventListener('keydown', this.triggerKeydownHandler);
3693
- this.triggerKeydownHandler = undefined;
3694
- }
3695
- }
3696
- listenToNavigation() {
3697
- this.navigationSub?.unsubscribe(); // Clean up previous subscription
3698
- this.navigationSub = this.router.events.subscribe(event => {
3699
- if (event instanceof NavigationStart && this.isOpen()) {
3700
- this.closeOverlay();
3701
- }
3702
- });
3703
3252
  }
3704
3253
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: OverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3705
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: OverlayComponent, isStandalone: true, selector: "lib-overlay", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed" }, queries: [{ propertyName: "contentTemplate", first: true, predicate: TemplateRef, descendants: true, static: true }, { propertyName: "footerTemplate", first: true, predicate: ["footer"], descendants: true, static: true }], viewQueries: [{ propertyName: "menuTemplate", first: true, predicate: ["menuTemplate"], descendants: true, static: true }], ngImport: i0, template: "\n\n\n<!-- Portal template for both desktop and mobile -->\n<ng-template #menuTemplate>\n <div class=\"c-overlay\" [ngClass]=\"getClasses()\">\n <!-- Backdrop for mobile -->\n @if (_isMobile() && (isOpen() || isClosing())) {\n <div\n class=\"c-overlay__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close overlay\"\n ></div>\n }\n\n <!-- Overlay Menu -->\n @if (isOpen() || isClosing()) {\n <div\n class=\"c-overlay__menu\"\n [ngClass]=\"getMenuClasses()\"\n [ngStyle]=\"getMenuStyles()\"\n #overlayMenu\n >\n <div class=\"c-overlay__content\">\n <!-- Main content projection -->\n <ng-container *ngTemplateOutlet=\"contentTemplate\"></ng-container>\n </div>\n \n <!-- Footer slot for mobile action buttons -->\n @if (_isMobile() && footerTemplate) {\n <div class=\"c-overlay__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate\"></ng-container>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>", styles: [".c-overlay{position:relative}.c-overlay__backdrop{position:fixed;inset:0;z-index:999;background-color:var(--color-effect-overlay);opacity:0;transition:opacity .2s ease-in-out;display:none}.c-overlay__backdrop--open{opacity:1}.c-overlay__menu{position:absolute;margin-top:2px;z-index:10000;background-color:var(--color-core-background-surface-raised);border:var(--size-border-width-sm) solid var(--color-core-border-soft);border-radius:var(--size-textfield-border-radius);box-shadow:var(--elevation-raised);max-height:320px;min-width:200px;overflow:hidden;display:flex;flex-direction:column;opacity:0;transform:scale(.95);animation:overlay-enter .2s ease-out forwards;transform-origin:top center}.c-overlay__menu--fixed{position:fixed;min-width:0}.c-overlay__menu--right{left:0;right:auto}.c-overlay__menu--left{left:auto;right:0}.c-overlay__menu--center{left:50%;right:auto;transform:translate(-50%) scale(.95);animation:overlay-enter-center .2s ease-out forwards}.c-overlay__content{flex:1;overflow-y:auto}.c-overlay__footer{display:none}@keyframes overlay-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes overlay-enter-center{0%{opacity:0;transform:translate(-50%) scale(.95)}to{opacity:1;transform:translate(-50%) scale(1)}}@keyframes overlay-exit{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:scale(.95)}}@media (max-width: 768px){.c-overlay__backdrop{display:block;z-index:999}.c-overlay__menu{position:fixed;bottom:0;left:0;right:0;width:100%;max-width:none;max-height:100vh;margin-top:0;border-radius:0;animation:none;z-index:1001;opacity:1;display:flex;flex-direction:column}.c-overlay__content{flex:1;overflow-y:auto;overflow-x:hidden;max-height:100vh;width:100%;min-width:0}.c-overlay__content>*{max-width:100%!important;width:100%!important;box-sizing:border-box!important;word-wrap:break-word!important;overflow-wrap:break-word!important;overflow-x:hidden!important}.c-overlay__content *{max-width:100%;box-sizing:border-box;word-wrap:break-word;overflow-wrap:break-word}.c-overlay--open .c-overlay__menu{transform:translateY(0)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }] });
3254
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: OverlayComponent, isStandalone: true, selector: "lib-overlay", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "opened", closed: "closed" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, viewQueries: [{ propertyName: "overlayMenu", first: true, predicate: ["overlayMenu"], descendants: true }], ngImport: i0, template: "<div class=\"c-overlay\" [ngClass]=\"getClasses()\">\n <!-- Backdrop for mobile -->\n @if (isOpen() || isClosing()) {\n <div\n class=\"c-overlay__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close overlay\"\n ></div>\n }\n\n <!-- Overlay Menu -->\n @if (isOpen() || isClosing()) {\n <div\n class=\"c-overlay__menu\"\n [ngClass]=\"getMenuClasses()\"\n [ngStyle]=\"getMenuStyles()\"\n #overlayMenu\n >\n <div class=\"c-overlay__content\">\n <!-- Main content projection -->\n <ng-content></ng-content>\n </div>\n \n <!-- Footer slot for mobile action buttons -->\n <div class=\"c-overlay__footer\">\n <ng-content select=\"[slot=footer]\"></ng-content>\n </div>\n </div>\n }\n</div>", styles: [".c-overlay{position:relative}.c-overlay__backdrop{position:fixed;inset:0;z-index:999;background-color:var(--color-effect-overlay);opacity:0;transition:opacity .2s ease-in-out;display:none}.c-overlay__backdrop--open{opacity:1}.c-overlay__menu{position:absolute;margin-top:2px;z-index:1000;background-color:var(--color-core-background-surface-raised);border:var(--size-border-width-sm) solid var(--color-core-border-soft);border-radius:var(--size-textfield-border-radius);box-shadow:var(--elevation-raised);max-height:320px;min-width:200px;overflow:hidden;display:flex;flex-direction:column;opacity:0;transform:scale(.95);animation:overlay-enter .2s ease-out forwards;transform-origin:top center}.c-overlay__menu--right{left:0;right:auto}.c-overlay__menu--left{left:auto;right:0}.c-overlay__menu--center{left:50%;right:auto;transform:translate(-50%) scale(.95);animation:overlay-enter-center .2s ease-out forwards}.c-overlay__content{flex:1;overflow-y:auto}.c-overlay__footer{display:none;height:27px}.c-overlay__footer:not(:empty){display:flex}@keyframes overlay-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes overlay-enter-center{0%{opacity:0;transform:translate(-50%) scale(.95)}to{opacity:1;transform:translate(-50%) scale(1)}}@keyframes overlay-exit{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:scale(.95)}}@media (max-width: 768px){.c-overlay__backdrop{display:block;z-index:999}.c-overlay__menu{position:fixed;bottom:0;left:0;right:0;width:100%;max-width:none;max-height:100vh;margin-top:0;border-radius:0;animation:none;z-index:1001;opacity:1;display:flex;flex-direction:column}.c-overlay__content{flex:1;overflow-y:auto;overflow-x:hidden;max-height:calc(100vh - 27px);width:100%;min-width:0}.c-overlay__content>*{max-width:100%!important;width:100%!important;box-sizing:border-box!important;word-wrap:break-word!important;overflow-wrap:break-word!important;overflow-x:hidden!important}.c-overlay__content *{max-width:100%;box-sizing:border-box;word-wrap:break-word;overflow-wrap:break-word}.c-overlay__footer{flex-shrink:0;padding:var(--space-container-padding-sm);background-color:var(--color-core-background-surface-raised);border-top:var(--size-border-width-sm) solid var(--color-core-border-soft);display:flex;justify-content:space-between;align-items:center;height:27px}.c-overlay__footer:empty{display:none}.c-overlay--open .c-overlay__menu{transform:translateY(0)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
3706
3255
  }
3707
3256
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: OverlayComponent, decorators: [{
3708
3257
  type: Component,
3709
- args: [{ selector: 'lib-overlay', imports: [NgClass, NgStyle, NgTemplateOutlet, PortalModule], template: "\n\n\n<!-- Portal template for both desktop and mobile -->\n<ng-template #menuTemplate>\n <div class=\"c-overlay\" [ngClass]=\"getClasses()\">\n <!-- Backdrop for mobile -->\n @if (_isMobile() && (isOpen() || isClosing())) {\n <div\n class=\"c-overlay__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close overlay\"\n ></div>\n }\n\n <!-- Overlay Menu -->\n @if (isOpen() || isClosing()) {\n <div\n class=\"c-overlay__menu\"\n [ngClass]=\"getMenuClasses()\"\n [ngStyle]=\"getMenuStyles()\"\n #overlayMenu\n >\n <div class=\"c-overlay__content\">\n <!-- Main content projection -->\n <ng-container *ngTemplateOutlet=\"contentTemplate\"></ng-container>\n </div>\n \n <!-- Footer slot for mobile action buttons -->\n @if (_isMobile() && footerTemplate) {\n <div class=\"c-overlay__footer\">\n <ng-container *ngTemplateOutlet=\"footerTemplate\"></ng-container>\n </div>\n }\n </div>\n }\n </div>\n</ng-template>", styles: [".c-overlay{position:relative}.c-overlay__backdrop{position:fixed;inset:0;z-index:999;background-color:var(--color-effect-overlay);opacity:0;transition:opacity .2s ease-in-out;display:none}.c-overlay__backdrop--open{opacity:1}.c-overlay__menu{position:absolute;margin-top:2px;z-index:10000;background-color:var(--color-core-background-surface-raised);border:var(--size-border-width-sm) solid var(--color-core-border-soft);border-radius:var(--size-textfield-border-radius);box-shadow:var(--elevation-raised);max-height:320px;min-width:200px;overflow:hidden;display:flex;flex-direction:column;opacity:0;transform:scale(.95);animation:overlay-enter .2s ease-out forwards;transform-origin:top center}.c-overlay__menu--fixed{position:fixed;min-width:0}.c-overlay__menu--right{left:0;right:auto}.c-overlay__menu--left{left:auto;right:0}.c-overlay__menu--center{left:50%;right:auto;transform:translate(-50%) scale(.95);animation:overlay-enter-center .2s ease-out forwards}.c-overlay__content{flex:1;overflow-y:auto}.c-overlay__footer{display:none}@keyframes overlay-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes overlay-enter-center{0%{opacity:0;transform:translate(-50%) scale(.95)}to{opacity:1;transform:translate(-50%) scale(1)}}@keyframes overlay-exit{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:scale(.95)}}@media (max-width: 768px){.c-overlay__backdrop{display:block;z-index:999}.c-overlay__menu{position:fixed;bottom:0;left:0;right:0;width:100%;max-width:none;max-height:100vh;margin-top:0;border-radius:0;animation:none;z-index:1001;opacity:1;display:flex;flex-direction:column}.c-overlay__content{flex:1;overflow-y:auto;overflow-x:hidden;max-height:100vh;width:100%;min-width:0}.c-overlay__content>*{max-width:100%!important;width:100%!important;box-sizing:border-box!important;word-wrap:break-word!important;overflow-wrap:break-word!important;overflow-x:hidden!important}.c-overlay__content *{max-width:100%;box-sizing:border-box;word-wrap:break-word;overflow-wrap:break-word}.c-overlay--open .c-overlay__menu{transform:translateY(0)}}\n"] }]
3710
- }], ctorParameters: () => [], propDecorators: { menuTemplate: [{
3258
+ args: [{ selector: 'lib-overlay', imports: [NgClass, NgStyle], template: "<div class=\"c-overlay\" [ngClass]=\"getClasses()\">\n <!-- Backdrop for mobile -->\n @if (isOpen() || isClosing()) {\n <div\n class=\"c-overlay__backdrop\"\n [ngClass]=\"getBackdropClasses()\"\n (click)=\"onBackdropClick()\"\n (keydown.escape)=\"onEscapeKey()\"\n tabindex=\"0\"\n role=\"button\"\n aria-label=\"Close overlay\"\n ></div>\n }\n\n <!-- Overlay Menu -->\n @if (isOpen() || isClosing()) {\n <div\n class=\"c-overlay__menu\"\n [ngClass]=\"getMenuClasses()\"\n [ngStyle]=\"getMenuStyles()\"\n #overlayMenu\n >\n <div class=\"c-overlay__content\">\n <!-- Main content projection -->\n <ng-content></ng-content>\n </div>\n \n <!-- Footer slot for mobile action buttons -->\n <div class=\"c-overlay__footer\">\n <ng-content select=\"[slot=footer]\"></ng-content>\n </div>\n </div>\n }\n</div>", styles: [".c-overlay{position:relative}.c-overlay__backdrop{position:fixed;inset:0;z-index:999;background-color:var(--color-effect-overlay);opacity:0;transition:opacity .2s ease-in-out;display:none}.c-overlay__backdrop--open{opacity:1}.c-overlay__menu{position:absolute;margin-top:2px;z-index:1000;background-color:var(--color-core-background-surface-raised);border:var(--size-border-width-sm) solid var(--color-core-border-soft);border-radius:var(--size-textfield-border-radius);box-shadow:var(--elevation-raised);max-height:320px;min-width:200px;overflow:hidden;display:flex;flex-direction:column;opacity:0;transform:scale(.95);animation:overlay-enter .2s ease-out forwards;transform-origin:top center}.c-overlay__menu--right{left:0;right:auto}.c-overlay__menu--left{left:auto;right:0}.c-overlay__menu--center{left:50%;right:auto;transform:translate(-50%) scale(.95);animation:overlay-enter-center .2s ease-out forwards}.c-overlay__content{flex:1;overflow-y:auto}.c-overlay__footer{display:none;height:27px}.c-overlay__footer:not(:empty){display:flex}@keyframes overlay-enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes overlay-enter-center{0%{opacity:0;transform:translate(-50%) scale(.95)}to{opacity:1;transform:translate(-50%) scale(1)}}@keyframes overlay-exit{0%{opacity:1;transform:translateY(0) scale(1)}to{opacity:0;transform:scale(.95)}}@media (max-width: 768px){.c-overlay__backdrop{display:block;z-index:999}.c-overlay__menu{position:fixed;bottom:0;left:0;right:0;width:100%;max-width:none;max-height:100vh;margin-top:0;border-radius:0;animation:none;z-index:1001;opacity:1;display:flex;flex-direction:column}.c-overlay__content{flex:1;overflow-y:auto;overflow-x:hidden;max-height:calc(100vh - 27px);width:100%;min-width:0}.c-overlay__content>*{max-width:100%!important;width:100%!important;box-sizing:border-box!important;word-wrap:break-word!important;overflow-wrap:break-word!important;overflow-x:hidden!important}.c-overlay__content *{max-width:100%;box-sizing:border-box;word-wrap:break-word;overflow-wrap:break-word}.c-overlay__footer{flex-shrink:0;padding:var(--space-container-padding-sm);background-color:var(--color-core-background-surface-raised);border-top:var(--size-border-width-sm) solid var(--color-core-border-soft);display:flex;justify-content:space-between;align-items:center;height:27px}.c-overlay__footer:empty{display:none}.c-overlay--open .c-overlay__menu{transform:translateY(0)}}\n"] }]
3259
+ }], ctorParameters: () => [], propDecorators: { overlayMenu: [{
3711
3260
  type: ViewChild,
3712
- args: ['menuTemplate', { static: true }]
3713
- }], contentTemplate: [{
3714
- type: ContentChild,
3715
- args: [TemplateRef, { static: true }]
3716
- }], footerTemplate: [{
3717
- type: ContentChild,
3718
- args: ['footer', { static: true }]
3261
+ args: ['overlayMenu']
3262
+ }], onClickOutside: [{
3263
+ type: HostListener,
3264
+ args: ['document:click', ['$event']]
3719
3265
  }] } });
3720
3266
 
3721
3267
  class DropdownActionComponent {
@@ -3781,11 +3327,11 @@ class DropdownActionComponent {
3781
3327
  this._isOverlayOpen.set(false);
3782
3328
  }
3783
3329
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: DropdownActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3784
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: DropdownActionComponent, isStandalone: true, selector: "lib-dropdown-action", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked" }, viewQueries: [{ propertyName: "overlay", first: true, predicate: OverlayComponent, descendants: true }], ngImport: i0, template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <ng-template>\n <!-- Options List -->\n <div class=\"c-dropdown-action__options\">\n @for (group of options(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-action__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-action__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) {\n <!-- Action button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-action__option\"\n [disabled]=\"option.disabled\"\n (click)=\"selectAction(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-action__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-action__option-label\">\n {{ option.label }}\n </span>\n </button>\n }\n </div>\n }\n </div>\n </ng-template>\n</lib-overlay>\n", styles: [".c-dropdown-action__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-action__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-action__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-action__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-action__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-action__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-action__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-action__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-action__option-label{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "lib-icon", inputs: ["size", "icon", "name", "color"] }, { kind: "component", type: OverlayComponent, selector: "lib-overlay", inputs: ["position", "disabled", "width"], outputs: ["opened", "closed"] }] });
3330
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: DropdownActionComponent, isStandalone: true, selector: "lib-dropdown-action", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClicked: "actionClicked" }, viewQueries: [{ propertyName: "overlay", first: true, predicate: OverlayComponent, descendants: true }], ngImport: i0, template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <!-- Options List -->\n <div class=\"c-dropdown-action__options\">\n @for (group of options(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-action__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-action__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) {\n <!-- Action button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-action__option\"\n [disabled]=\"option.disabled\"\n (click)=\"selectAction(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-action__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-action__option-label\">\n {{ option.label }}\n </span>\n </button>\n }\n </div>\n }\n </div>\n</lib-overlay>\n", styles: [".c-dropdown-action__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-action__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-action__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-action__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-action__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-action__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-action__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-action__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-action__option-label{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "lib-icon", inputs: ["size", "icon", "name", "color"] }, { kind: "component", type: OverlayComponent, selector: "lib-overlay", inputs: ["position", "disabled", "width"], outputs: ["opened", "closed"] }] });
3785
3331
  }
3786
3332
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: DropdownActionComponent, decorators: [{
3787
3333
  type: Component,
3788
- args: [{ selector: 'lib-dropdown-action', imports: [IconComponent, OverlayComponent], template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <ng-template>\n <!-- Options List -->\n <div class=\"c-dropdown-action__options\">\n @for (group of options(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-action__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-action__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) {\n <!-- Action button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-action__option\"\n [disabled]=\"option.disabled\"\n (click)=\"selectAction(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-action__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-action__option-label\">\n {{ option.label }}\n </span>\n </button>\n }\n </div>\n }\n </div>\n </ng-template>\n</lib-overlay>\n", styles: [".c-dropdown-action__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-action__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-action__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-action__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-action__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-action__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-action__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-action__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-action__option-label{flex:1;min-width:0}\n"] }]
3334
+ args: [{ selector: 'lib-dropdown-action', imports: [IconComponent, OverlayComponent], template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <!-- Options List -->\n <div class=\"c-dropdown-action__options\">\n @for (group of options(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-action__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-action__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) {\n <!-- Action button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-action__option\"\n [disabled]=\"option.disabled\"\n (click)=\"selectAction(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-action__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-action__option-label\">\n {{ option.label }}\n </span>\n </button>\n }\n </div>\n }\n </div>\n</lib-overlay>\n", styles: [".c-dropdown-action__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-action__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-action__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-action__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-action__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-action__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-action__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-action__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-action__option-label{flex:1;min-width:0}\n"] }]
3789
3335
  }], ctorParameters: () => [], propDecorators: { overlay: [{
3790
3336
  type: ViewChild,
3791
3337
  args: [OverlayComponent]
@@ -4340,19 +3886,18 @@ class DropdownSelectComponent {
4340
3886
  }
4341
3887
  }
4342
3888
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: DropdownSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4343
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: DropdownSelectComponent, isStandalone: true, selector: "lib-dropdown-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null }, searchBarEnabled: { classPropertyName: "searchBarEnabled", publicName: "searchBarEnabled", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, cancelButtonText: { classPropertyName: "cancelButtonText", publicName: "cancelButtonText", isSignal: true, isRequired: false, transformFunction: null }, acceptButtonText: { classPropertyName: "acceptButtonText", publicName: "acceptButtonText", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { optionSelected: "optionSelected", optionDeselected: "optionDeselected", searchChanged: "searchChanged", valueChange: "valueChange", cancelClicked: "cancelClicked", acceptClicked: "acceptClicked" }, viewQueries: [{ propertyName: "overlay", first: true, predicate: OverlayComponent, descendants: true }], ngImport: i0, template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <ng-template>\n <!-- Search Input (if enabled and not multiselect) -->\n @if (showSearchBar()) {\n <div class=\"c-dropdown-select__search\">\n <lib-input-search\n [placeholder]=\"searchPlaceholder()\"\n [formControl]=\"searchControl\"\n size=\"lg\"\n [fullWidth]=\"true\"\n ></lib-input-search>\n </div>\n }\n\n <!-- Options List -->\n <div class=\"c-dropdown-select__options\" [ngClass]=\"{ 'c-dropdown-select__options--with-mobile-actions': showMobileActions() }\">\n @for (group of filteredOptions(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-select__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-select__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) { @if (isMultiSelect())\n {\n <!-- For multiselect: use full checkbox component with label -->\n <div\n class=\"c-dropdown-select__option c-dropdown-select__option--multiselect\"\n >\n <lib-checkbox\n [label]=\"option.label\"\n [name]=\"'option-' + option.value\"\n [value]=\"option.value\"\n [ariaLabel]=\"'Select ' + option.label\"\n [state]=\"isSelected(option) ? 'checked' : 'unchecked'\"\n [disabled]=\"option.disabled || false\"\n (changed)=\"onCheckboxChange(option, $event.checked)\"\n ></lib-checkbox>\n </div>\n } @else {\n <!-- For single select: use button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-select__option\"\n [class.c-dropdown-select__option--selected]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-select__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-select__option-label\">\n {{ option.label }}\n </span>\n\n <!-- Check icon for selected option in single select -->\n @if (isSelected(option)) {\n <lib-icon\n name=\"checkcircle-fill\"\n size=\"lg\"\n color=\"action-primary-selected-background-default\"\n >\n </lib-icon>\n }\n </button>\n } }\n </div>\n }\n </div>\n\n <!-- Mobile Action Buttons in footer slot -->\n @if (showMobileActions()) {\n <div class=\"c-dropdown-select__mobile-actions\">\n <lib-link-action\n [text]=\"cancelButtonText()\"\n variant=\"neutral\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onCancelClick()\"\n ></lib-link-action>\n <lib-link-action\n [text]=\"acceptButtonText()\"\n variant=\"primary\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onAcceptClick()\"\n ></lib-link-action>\n </div>\n }\n </ng-template>\n</lib-overlay>\n", styles: [".c-dropdown-select__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-select__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-select__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-select__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-select__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-select__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-select__option--selected{background-color:var(--color-action-primary-background-selected);color:var(--color-action-primary-content-selected);-webkit-transform:translateZ(0);transform:translateZ(0);will-change:transform}.c-dropdown-select__option--multiselect{cursor:default;padding:0 var(--space-component-padding-lg)}.c-dropdown-select__option--multiselect:hover{background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option--multiselect__option{font-family:var(--typography-label-md-default-family),sans-serif;font-weight:var(--typography-label-md-default-weight);font-size:var(--typography-label-md-default-size);letter-spacing:var(--typography-label-md-default-letter-spacing)}.c-dropdown-select__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-select__option-label{flex:1;min-width:0}.c-dropdown-select__options--with-mobile-actions{margin-bottom:85px}.c-dropdown-select__mobile-actions{display:none}@media (max-width: 768px){.c-dropdown-select__mobile-actions{display:flex;justify-content:space-between;align-items:center;width:100%;position:fixed;bottom:0;height:60px;background-color:var(--color-core-background-surface-raised);padding:var(--space-container-padding-sm);border-top:var(--size-border-width-sm) solid var(--color-core-border-soft)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: IconComponent, selector: "lib-icon", inputs: ["size", "icon", "name", "color"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["label", "state", "errorActive", "skeletonActive", "disabled", "name", "value", "innerHTML", "ariaLabel"], outputs: ["changed"] }, { kind: "component", type: InputSearchComponent, selector: "lib-input-search", inputs: ["label", "placeholder", "helperText", "alertText", "successText", "error", "success", "disabled", "readonly", "required", "size", "fullWidth", "clearButton"], outputs: ["emitValue"] }, { kind: "component", type: LinkActionComponent, selector: "lib-link-action", inputs: ["text", "disabled", "variant", "size", "weight", "iconBefore", "iconAfter"], outputs: ["clicked"] }, { kind: "component", type: OverlayComponent, selector: "lib-overlay", inputs: ["position", "disabled", "width"], outputs: ["opened", "closed"] }], encapsulation: i0.ViewEncapsulation.None });
3889
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: DropdownSelectComponent, isStandalone: true, selector: "lib-dropdown-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null }, searchBarEnabled: { classPropertyName: "searchBarEnabled", publicName: "searchBarEnabled", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, cancelButtonText: { classPropertyName: "cancelButtonText", publicName: "cancelButtonText", isSignal: true, isRequired: false, transformFunction: null }, acceptButtonText: { classPropertyName: "acceptButtonText", publicName: "acceptButtonText", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { optionSelected: "optionSelected", optionDeselected: "optionDeselected", searchChanged: "searchChanged", valueChange: "valueChange", cancelClicked: "cancelClicked", acceptClicked: "acceptClicked" }, viewQueries: [{ propertyName: "overlay", first: true, predicate: OverlayComponent, descendants: true }], ngImport: i0, template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <!-- Search Input (if enabled and not multiselect) -->\n @if (showSearchBar()) {\n <div class=\"c-dropdown-select__search\">\n <lib-input-search\n [placeholder]=\"searchPlaceholder()\"\n [formControl]=\"searchControl\"\n size=\"lg\"\n [fullWidth]=\"true\"\n ></lib-input-search>\n </div>\n }\n\n <!-- Options List -->\n <div class=\"c-dropdown-select__options\">\n @for (group of filteredOptions(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-select__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-select__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) { @if (isMultiSelect())\n {\n <!-- For multiselect: use full checkbox component with label -->\n <div\n class=\"c-dropdown-select__option c-dropdown-select__option--multiselect\"\n >\n <lib-checkbox\n [label]=\"option.label\"\n [name]=\"'option-' + option.value\"\n [value]=\"option.value\"\n [ariaLabel]=\"'Select ' + option.label\"\n [state]=\"isSelected(option) ? 'checked' : 'unchecked'\"\n [disabled]=\"option.disabled || false\"\n (changed)=\"onCheckboxChange(option, $event.checked)\"\n ></lib-checkbox>\n </div>\n } @else {\n <!-- For single select: use button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-select__option\"\n [class.c-dropdown-select__option--selected]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-select__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-select__option-label\">\n {{ option.label }}\n </span>\n\n <!-- Check icon for selected option in single select -->\n @if (isSelected(option)) {\n <lib-icon\n name=\"checkcircle-fill\"\n size=\"lg\"\n color=\"action-primary-selected-background-default\"\n >\n </lib-icon>\n }\n </button>\n } }\n </div>\n }\n </div>\n\n <!-- Mobile Action Buttons in footer slot -->\n @if (showMobileActions()) {\n <div slot=\"footer\" class=\"c-dropdown-select__mobile-actions\">\n <lib-link-action\n [text]=\"cancelButtonText()\"\n variant=\"neutral\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onCancelClick()\"\n ></lib-link-action>\n <lib-link-action\n [text]=\"acceptButtonText()\"\n variant=\"primary\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onAcceptClick()\"\n ></lib-link-action>\n </div>\n }\n</lib-overlay>\n", styles: [".c-dropdown-select__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-select__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-select__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-select__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-select__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-select__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-select__option--multiselect{cursor:default;padding:0 var(--space-component-padding-lg)}.c-dropdown-select__option--multiselect:hover{background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option--multiselect__option{font-family:var(--typography-label-md-default-family),sans-serif;font-weight:var(--typography-label-md-default-weight);font-size:var(--typography-label-md-default-size);letter-spacing:var(--typography-label-md-default-letter-spacing)}.c-dropdown-select__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-select__option-label{flex:1;min-width:0}.c-dropdown-select__mobile-actions{display:flex;justify-content:space-between;align-items:center;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: IconComponent, selector: "lib-icon", inputs: ["size", "icon", "name", "color"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["label", "state", "errorActive", "skeletonActive", "disabled", "name", "value", "innerHTML", "ariaLabel"], outputs: ["changed"] }, { kind: "component", type: InputSearchComponent, selector: "lib-input-search", inputs: ["label", "placeholder", "helperText", "alertText", "successText", "error", "success", "disabled", "readonly", "required", "size", "fullWidth", "clearButton"], outputs: ["emitValue"] }, { kind: "component", type: LinkActionComponent, selector: "lib-link-action", inputs: ["text", "disabled", "variant", "size", "weight", "iconBefore", "iconAfter"], outputs: ["clicked"] }, { kind: "component", type: OverlayComponent, selector: "lib-overlay", inputs: ["position", "disabled", "width"], outputs: ["opened", "closed"] }] });
4344
3890
  }
4345
3891
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: DropdownSelectComponent, decorators: [{
4346
3892
  type: Component,
4347
3893
  args: [{ selector: 'lib-dropdown-select', imports: [
4348
3894
  ReactiveFormsModule,
4349
- NgClass,
4350
3895
  IconComponent,
4351
3896
  CheckboxComponent,
4352
3897
  InputSearchComponent,
4353
3898
  LinkActionComponent,
4354
3899
  OverlayComponent,
4355
- ], encapsulation: ViewEncapsulation.None, template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <ng-template>\n <!-- Search Input (if enabled and not multiselect) -->\n @if (showSearchBar()) {\n <div class=\"c-dropdown-select__search\">\n <lib-input-search\n [placeholder]=\"searchPlaceholder()\"\n [formControl]=\"searchControl\"\n size=\"lg\"\n [fullWidth]=\"true\"\n ></lib-input-search>\n </div>\n }\n\n <!-- Options List -->\n <div class=\"c-dropdown-select__options\" [ngClass]=\"{ 'c-dropdown-select__options--with-mobile-actions': showMobileActions() }\">\n @for (group of filteredOptions(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-select__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-select__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) { @if (isMultiSelect())\n {\n <!-- For multiselect: use full checkbox component with label -->\n <div\n class=\"c-dropdown-select__option c-dropdown-select__option--multiselect\"\n >\n <lib-checkbox\n [label]=\"option.label\"\n [name]=\"'option-' + option.value\"\n [value]=\"option.value\"\n [ariaLabel]=\"'Select ' + option.label\"\n [state]=\"isSelected(option) ? 'checked' : 'unchecked'\"\n [disabled]=\"option.disabled || false\"\n (changed)=\"onCheckboxChange(option, $event.checked)\"\n ></lib-checkbox>\n </div>\n } @else {\n <!-- For single select: use button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-select__option\"\n [class.c-dropdown-select__option--selected]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-select__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-select__option-label\">\n {{ option.label }}\n </span>\n\n <!-- Check icon for selected option in single select -->\n @if (isSelected(option)) {\n <lib-icon\n name=\"checkcircle-fill\"\n size=\"lg\"\n color=\"action-primary-selected-background-default\"\n >\n </lib-icon>\n }\n </button>\n } }\n </div>\n }\n </div>\n\n <!-- Mobile Action Buttons in footer slot -->\n @if (showMobileActions()) {\n <div class=\"c-dropdown-select__mobile-actions\">\n <lib-link-action\n [text]=\"cancelButtonText()\"\n variant=\"neutral\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onCancelClick()\"\n ></lib-link-action>\n <lib-link-action\n [text]=\"acceptButtonText()\"\n variant=\"primary\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onAcceptClick()\"\n ></lib-link-action>\n </div>\n }\n </ng-template>\n</lib-overlay>\n", styles: [".c-dropdown-select__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-select__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-select__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-select__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-select__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-select__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-select__option--selected{background-color:var(--color-action-primary-background-selected);color:var(--color-action-primary-content-selected);-webkit-transform:translateZ(0);transform:translateZ(0);will-change:transform}.c-dropdown-select__option--multiselect{cursor:default;padding:0 var(--space-component-padding-lg)}.c-dropdown-select__option--multiselect:hover{background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option--multiselect__option{font-family:var(--typography-label-md-default-family),sans-serif;font-weight:var(--typography-label-md-default-weight);font-size:var(--typography-label-md-default-size);letter-spacing:var(--typography-label-md-default-letter-spacing)}.c-dropdown-select__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-select__option-label{flex:1;min-width:0}.c-dropdown-select__options--with-mobile-actions{margin-bottom:85px}.c-dropdown-select__mobile-actions{display:none}@media (max-width: 768px){.c-dropdown-select__mobile-actions{display:flex;justify-content:space-between;align-items:center;width:100%;position:fixed;bottom:0;height:60px;background-color:var(--color-core-background-surface-raised);padding:var(--space-container-padding-sm);border-top:var(--size-border-width-sm) solid var(--color-core-border-soft)}}\n"] }]
3900
+ ], template: "<lib-overlay\n [position]=\"position()\"\n [disabled]=\"disabled()\"\n (opened)=\"onOverlayOpened()\"\n (closed)=\"onOverlayClosed()\"\n [width]=\"width()\"\n>\n <!-- Search Input (if enabled and not multiselect) -->\n @if (showSearchBar()) {\n <div class=\"c-dropdown-select__search\">\n <lib-input-search\n [placeholder]=\"searchPlaceholder()\"\n [formControl]=\"searchControl\"\n size=\"lg\"\n [fullWidth]=\"true\"\n ></lib-input-search>\n </div>\n }\n\n <!-- Options List -->\n <div class=\"c-dropdown-select__options\">\n @for (group of filteredOptions(); track group.label) {\n <!-- Option Group -->\n <div class=\"c-dropdown-select__group\">\n <!-- Group Label -->\n @if (group.label) {\n <div class=\"c-dropdown-select__group-label\">\n {{ group.label }}\n </div>\n }\n <!-- Group Options -->\n @for (option of group.options; track option.value) { @if (isMultiSelect())\n {\n <!-- For multiselect: use full checkbox component with label -->\n <div\n class=\"c-dropdown-select__option c-dropdown-select__option--multiselect\"\n >\n <lib-checkbox\n [label]=\"option.label\"\n [name]=\"'option-' + option.value\"\n [value]=\"option.value\"\n [ariaLabel]=\"'Select ' + option.label\"\n [state]=\"isSelected(option) ? 'checked' : 'unchecked'\"\n [disabled]=\"option.disabled || false\"\n (changed)=\"onCheckboxChange(option, $event.checked)\"\n ></lib-checkbox>\n </div>\n } @else {\n <!-- For single select: use button with icon and label -->\n <button\n type=\"button\"\n class=\"c-dropdown-select__option\"\n [class.c-dropdown-select__option--selected]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n >\n @if (option.icon) {\n <lib-icon\n [name]=\"option.icon\"\n size=\"lg\"\n class=\"c-dropdown-select__option-icon\"\n >\n </lib-icon>\n }\n\n <span class=\"c-dropdown-select__option-label\">\n {{ option.label }}\n </span>\n\n <!-- Check icon for selected option in single select -->\n @if (isSelected(option)) {\n <lib-icon\n name=\"checkcircle-fill\"\n size=\"lg\"\n color=\"action-primary-selected-background-default\"\n >\n </lib-icon>\n }\n </button>\n } }\n </div>\n }\n </div>\n\n <!-- Mobile Action Buttons in footer slot -->\n @if (showMobileActions()) {\n <div slot=\"footer\" class=\"c-dropdown-select__mobile-actions\">\n <lib-link-action\n [text]=\"cancelButtonText()\"\n variant=\"neutral\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onCancelClick()\"\n ></lib-link-action>\n <lib-link-action\n [text]=\"acceptButtonText()\"\n variant=\"primary\"\n size=\"md\"\n weight=\"bold\"\n (clicked)=\"onAcceptClick()\"\n ></lib-link-action>\n </div>\n }\n</lib-overlay>\n", styles: [".c-dropdown-select__search{padding:var(--space-container-padding-sm);border-bottom:var(--size-border-width-sm) solid var(--color-core-border-soft)}.c-dropdown-select__options{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px 0}.c-dropdown-select__group-label{color:var(--color-core-content-soft);padding:var(--space-component-padding-md) var(--space-component-padding-lg);font-family:var(--typography-label-sm-strong-family),sans-serif;font-weight:var(--typography-label-sm-strong-weight);font-size:var(--typography-label-sm-strong-size);letter-spacing:var(--typography-label-sm-strong-letter-spacing)}.c-dropdown-select__option{display:flex;align-items:center;width:100%;min-height:40px;gap:var(--space-component-gap-sm);padding:var(--space-component-padding-sm) var(--space-component-padding-lg);border:none;background:var(--color-action-neutral-background-default);color:var(--color-core-content-default);font-family:var(--typography-label-sm-default-family),sans-serif;font-weight:var(--typography-label-sm-default-weight);font-size:var(--typography-label-sm-default-size);letter-spacing:var(--typography-label-sm-default-letter-spacing);text-align:left;cursor:pointer}.c-dropdown-select__option:hover:not(:disabled){background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option:focus-visible:not(:disabled){box-shadow:var(--focus-inset);outline:none}.c-dropdown-select__option:disabled{cursor:not-allowed;opacity:.5}.c-dropdown-select__option--multiselect{cursor:default;padding:0 var(--space-component-padding-lg)}.c-dropdown-select__option--multiselect:hover{background-color:var(--color-action-neutral-background-hover)}.c-dropdown-select__option--multiselect__option{font-family:var(--typography-label-md-default-family),sans-serif;font-weight:var(--typography-label-md-default-weight);font-size:var(--typography-label-md-default-size);letter-spacing:var(--typography-label-md-default-letter-spacing)}.c-dropdown-select__option-icon{flex-shrink:0;margin-right:12px;color:var(--color-core-content-soft)}.c-dropdown-select__option-label{flex:1;min-width:0}.c-dropdown-select__mobile-actions{display:flex;justify-content:space-between;align-items:center;width:100%}\n"] }]
4356
3901
  }], ctorParameters: () => [], propDecorators: { overlay: [{
4357
3902
  type: ViewChild,
4358
3903
  args: [OverlayComponent]