@kirbydesign/designsystem 6.0.2 → 6.1.2-pubtest.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,7 +1,7 @@
1
1
  import { DesignTokenHelper, ColorHelper, capitalizeFirstLetter } from '@kirbydesign/core';
2
2
  export { ColorHelper, DesignTokenHelper, camelToKebabCase, capitalizeFirstLetter, kebabToCamelCase, kebabToTitleCase } from '@kirbydesign/core';
3
3
  import * as i0 from '@angular/core';
4
- import { Directive, Injectable, Component, ChangeDetectionStrategy, HostBinding, Input, InjectionToken, Injector, HostListener, ElementRef, ContentChild, RendererStyleFlags2, ViewChildren, ViewChild, EventEmitter, Output, ContentChildren, Optional, Inject, NgModule, ChangeDetectorRef, NgZone, LOCALE_ID, forwardRef, TemplateRef, Pipe, SkipSelf, APP_INITIALIZER } from '@angular/core';
4
+ import { Directive, Injectable, Component, ChangeDetectionStrategy, HostBinding, Input, Optional, InjectionToken, Injector, HostListener, ElementRef, ContentChild, RendererStyleFlags2, ViewChildren, ViewChild, EventEmitter, Output, ContentChildren, Inject, NgModule, ChangeDetectorRef, NgZone, LOCALE_ID, forwardRef, TemplateRef, Pipe, SkipSelf, APP_INITIALIZER } from '@angular/core';
5
5
  import { trigger, state, style, transition, animate } from '@angular/animations';
6
6
  import * as i1 from '@ionic/angular';
7
7
  import { IonContent, IonHeader, IonToolbar, IonTitle, IonApp, IonicModule, IonRadio, IonFabButton, IonItemSliding, IonList, IonTabs, IonFooter, IonBackButtonDelegate } from '@ionic/angular';
@@ -287,6 +287,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
287
287
 
288
288
  class Modal {
289
289
  }
290
+ var ModalElementType;
291
+ (function (ModalElementType) {
292
+ ModalElementType[ModalElementType["PAGE_PROGRESS"] = 0] = "PAGE_PROGRESS";
293
+ ModalElementType[ModalElementType["FOOTER"] = 1] = "FOOTER";
294
+ ModalElementType[ModalElementType["TITLE"] = 2] = "TITLE";
295
+ })(ModalElementType || (ModalElementType = {}));
296
+ class ModalElementsAdvertiser {
297
+ }
298
+ class ModalElementComponent {
299
+ constructor(modalElementType, elementRef, modalElementsAdvertiser) {
300
+ this.modalElementType = modalElementType;
301
+ this.elementRef = elementRef;
302
+ this.modalElementsAdvertiser = modalElementsAdvertiser;
303
+ }
304
+ get isContainedInModal() {
305
+ return this.modalElementsAdvertiser !== null;
306
+ }
307
+ ngAfterViewInit() {
308
+ if (this.isContainedInModal) {
309
+ this.modalElementsAdvertiser.addModalElement(this.modalElementType, this.elementRef);
310
+ }
311
+ }
312
+ ngOnDestroy() {
313
+ if (this.isContainedInModal) {
314
+ this.modalElementsAdvertiser.removeModalElement(this.modalElementType, this.elementRef);
315
+ }
316
+ }
317
+ }
318
+ /** @nocollapse */ ModalElementComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalElementComponent, deps: [{ token: ModalElementType }, { token: i0.ElementRef }, { token: ModalElementsAdvertiser, optional: true }], target: i0.ɵɵFactoryTarget.Component });
319
+ /** @nocollapse */ ModalElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: ModalElementComponent, selector: "ng-component", ngImport: i0, template: '', isInline: true });
320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalElementComponent, decorators: [{
321
+ type: Component,
322
+ args: [{ template: '' }]
323
+ }], ctorParameters: function () {
324
+ return [{ type: ModalElementType }, { type: i0.ElementRef }, { type: ModalElementsAdvertiser, decorators: [{
325
+ type: Optional
326
+ }] }];
327
+ } });
290
328
 
291
329
  const COMPONENT_PROPS = new InjectionToken('componentProps');
292
330
 
@@ -474,6 +512,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
474
512
  args: [IconComponent, { read: ElementRef }]
475
513
  }] } });
476
514
 
515
+ /*
516
+ The ModalWrapperComponent class was growing large.
517
+
518
+ Hence the functions responsible for moving modal elements around
519
+ has been encapsulated in this class.
520
+ */
521
+ class ModalElementsMoverDelegate {
522
+ constructor(renderer, elementRef) {
523
+ this.renderer = renderer;
524
+ this.elementRef = elementRef;
525
+ }
526
+ addFooter(footerElementRef) {
527
+ // Move the footer next to ion-content
528
+ this.moveChild(footerElementRef, this.elementRef);
529
+ }
530
+ removeFooter(footerElementRef) {
531
+ this.removeChild(footerElementRef);
532
+ }
533
+ addPageProgress(pageProgressElementRef, ionToolbarElement) {
534
+ this.moveChild(pageProgressElementRef, ionToolbarElement);
535
+ }
536
+ removePageProgress(pageProgressElementRef) {
537
+ this.removeChild(pageProgressElementRef);
538
+ }
539
+ /*
540
+ contentTitleElement & ionTitleElement has to be passed
541
+ as arguments to the method; not part of the constructor, as they
542
+ might reference completely different elements between calls.
543
+
544
+ For example in a multi-page routed modal where the elements are destroyed
545
+ and recreated.
546
+ */
547
+ addTitle(titleElementRef, contentTitleElement, hasCollapsibleTitle, ionTitleElement) {
548
+ this.moveChild(titleElementRef, ionTitleElement);
549
+ // If title is collapsible append it to content area; required by ionic implementation.
550
+ if (hasCollapsibleTitle) {
551
+ const titleElementClone = titleElementRef.nativeElement.cloneNode(true);
552
+ this.moveChild(new ElementRef(titleElementClone), contentTitleElement);
553
+ }
554
+ }
555
+ removeTitle(titleElementRef, hasCollapsibleTitle, contentTitleElement) {
556
+ this.removeChild(titleElementRef);
557
+ if (hasCollapsibleTitle) {
558
+ const kirbyPageTitleElement = contentTitleElement.nativeElement.querySelector('kirby-page-title');
559
+ this.removeChild(new ElementRef(kirbyPageTitleElement));
560
+ }
561
+ }
562
+ moveChild(childElementRef, newParentElementRef) {
563
+ const child = childElementRef.nativeElement;
564
+ const newParent = newParentElementRef.nativeElement;
565
+ this.renderer.removeChild(child.parentElement, child);
566
+ this.renderer.appendChild(newParent, child);
567
+ }
568
+ removeChild(childElementRef, parentElement) {
569
+ const child = childElementRef.nativeElement;
570
+ if (!!child) {
571
+ this.renderer.removeChild(parentElement || child.parentElement, child);
572
+ }
573
+ }
574
+ }
575
+
477
576
  /**
478
577
  * Factory that creates a new ResizeObserver and allows us to stub it out in unit tests.
479
578
  * @docs-private
@@ -569,7 +668,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
569
668
  }], ctorParameters: function () { return [{ type: WindowRef }]; } });
570
669
 
571
670
  class ModalWrapperComponent {
572
- constructor(injector, elementRef, renderer, zone, resizeObserverService, componentFactoryResolver, windowRef, platform) {
671
+ constructor(changeDetector, injector, elementRef, renderer, zone, resizeObserverService, componentFactoryResolver, windowRef, platform) {
672
+ this.changeDetector = changeDetector;
573
673
  this.injector = injector;
574
674
  this.elementRef = elementRef;
575
675
  this.renderer = renderer;
@@ -594,13 +694,10 @@ class ModalWrapperComponent {
594
694
  .pipe(debounceTime(this.VIEWPORT_RESIZE_DEBOUNCE_TIME));
595
695
  this.destroy$ = new Subject();
596
696
  this.willClose$ = this.ionModalWillDismiss.pipe(first());
597
- this.elementToParentMap = {
598
- 'KIRBY-MODAL-FOOTER': () => [this.elementRef.nativeElement],
599
- 'KIRBY-PAGE-TITLE': () => { var _a; return [this.ionTitleElement.nativeElement, (_a = this.contentTitle) === null || _a === void 0 ? void 0 : _a.nativeElement].filter((element) => element !== undefined); },
600
- 'KIRBY-PAGE-PROGRESS': () => [this.ionToolbarElement.nativeElement],
601
- };
697
+ this._currentFooter = null;
602
698
  this.setViewportHeight();
603
699
  this.observeViewportResize();
700
+ this.modalElementsMoverDelegate = new ModalElementsMoverDelegate(renderer, elementRef);
604
701
  }
605
702
  get _hasCollapsibleTitle() {
606
703
  var _a;
@@ -609,11 +706,15 @@ class ModalWrapperComponent {
609
706
  set scrollDisabled(disabled) {
610
707
  this.ionContent.scrollY = !disabled;
611
708
  }
612
- get mutationObserver() {
613
- if (!this._mutationObserver) {
614
- this._mutationObserver = this.createEmbeddedElementsMutationObserver();
709
+ get contentTitleElement() {
710
+ /*
711
+ contentTitleElement has ngIf directive dependent on _hasCollapsibleTitle; trigger CD to make sure element has been queried.
712
+ Solution taken from: https://danieleyassu.com/angular-viewchild-and-ngif/
713
+ */
714
+ if (!this._contentTitleElement && this._hasCollapsibleTitle) {
715
+ this.changeDetector.detectChanges();
615
716
  }
616
- return this._mutationObserver;
717
+ return this._contentTitleElement;
617
718
  }
618
719
  get intersectionObserver() {
619
720
  if (!this._intersectionObserver) {
@@ -636,6 +737,43 @@ class ModalWrapperComponent {
636
737
  parent: this.injector,
637
738
  });
638
739
  }
740
+ set currentFooter(footer) {
741
+ if (footer !== null) {
742
+ this.resizeObserverService.observe(footer, (entry) => {
743
+ const [property, pixelValue] = [
744
+ '--footer-height',
745
+ `${Math.floor(entry.contentRect.height)}px`,
746
+ ];
747
+ this.setCssVar(this.elementRef.nativeElement, property, pixelValue);
748
+ });
749
+ }
750
+ this._currentFooter = footer;
751
+ }
752
+ get currentFooter() {
753
+ return this._currentFooter;
754
+ }
755
+ addModalElement(type, modalElement) {
756
+ const addModalElementFn = {
757
+ [ModalElementType.FOOTER]: () => {
758
+ this.modalElementsMoverDelegate.addFooter(modalElement);
759
+ this.currentFooter = modalElement.nativeElement;
760
+ },
761
+ [ModalElementType.TITLE]: () => this.modalElementsMoverDelegate.addTitle(modalElement, this.contentTitleElement, this._hasCollapsibleTitle, this.ionTitleElement),
762
+ [ModalElementType.PAGE_PROGRESS]: () => this.modalElementsMoverDelegate.addPageProgress(modalElement, this.ionToolbarElement),
763
+ }[type];
764
+ addModalElementFn();
765
+ }
766
+ removeModalElement(type, modalElement) {
767
+ const removeModalElementFn = {
768
+ [ModalElementType.FOOTER]: () => {
769
+ this.modalElementsMoverDelegate.removeFooter(modalElement);
770
+ this.currentFooter = null;
771
+ },
772
+ [ModalElementType.TITLE]: () => this.modalElementsMoverDelegate.removeTitle(modalElement, this._hasCollapsibleTitle, this.contentTitleElement),
773
+ [ModalElementType.PAGE_PROGRESS]: () => this.modalElementsMoverDelegate.removePageProgress(modalElement),
774
+ }[type];
775
+ removeModalElementFn();
776
+ }
639
777
  initializeResizeModalToModalWrapper() {
640
778
  if (this.config.flavor === 'drawer' && this.config.interactWithBackground) {
641
779
  merge(this.ionModalDidPresent, this.viewportResize$)
@@ -672,12 +810,9 @@ class ModalWrapperComponent {
672
810
  return;
673
811
  siblingModalRouteActivated$.pipe(takeUntil(this.willClose$)).subscribe((route) => {
674
812
  if (this.routerOutlet.isActivated) {
675
- this.mutationObserver.disconnect();
676
813
  this.routerOutlet.deactivate();
677
- this.clearEmbeddedElements();
678
814
  }
679
815
  this.routerOutlet.activateWith(route, this.componentFactoryResolver);
680
- this.checkForEmbeddedElements();
681
816
  });
682
817
  }
683
818
  patchScrollElementSize() {
@@ -705,11 +840,6 @@ class ModalWrapperComponent {
705
840
  if (this.toolbarButtonsQuery) {
706
841
  this.toolbarButtons = this.toolbarButtonsQuery.map((buttonRef) => buttonRef.nativeElement);
707
842
  }
708
- this.checkForEmbeddedElements();
709
- }
710
- checkForEmbeddedElements() {
711
- this.moveEmbeddedElements();
712
- this.observeEmbeddedElements();
713
843
  }
714
844
  observeHeaderResize() {
715
845
  this.resizeObserverService.observe(this.ionHeaderElement.nativeElement, (entry) => {
@@ -717,17 +847,6 @@ class ModalWrapperComponent {
717
847
  this.setCssVar(this.elementRef.nativeElement, property, pixelValue);
718
848
  });
719
849
  }
720
- moveEmbeddedElements() {
721
- const parentElement = this.getEmbeddedComponentElement();
722
- if (parentElement) {
723
- Object.entries(this.elementToParentMap).forEach(([tagName, getNewParent]) => {
724
- const embeddedElement = parentElement.querySelector(tagName);
725
- if (embeddedElement) {
726
- this.moveChild(embeddedElement, getNewParent());
727
- }
728
- });
729
- }
730
- }
731
850
  listenForIonModalDidPresent() {
732
851
  if (this.ionModalElement) {
733
852
  this.ionModalElement.addEventListener('ionModalDidPresent', () => {
@@ -826,7 +945,7 @@ class ModalWrapperComponent {
826
945
  this.toggleCssClass(this.elementRef.nativeElement, 'keyboard-visible', keyboardHeight > 0);
827
946
  const keyboardOverlap = this.getKeyboardOverlap(keyboardHeight, this.elementRef.nativeElement);
828
947
  let snapFooterToKeyboard = false;
829
- const embeddedFooterElement = this.getEmbeddedFooterElement();
948
+ const embeddedFooterElement = this.currentFooter;
830
949
  if (embeddedFooterElement) {
831
950
  this.setCssVar(embeddedFooterElement, '--keyboard-offset', `${keyboardOverlap}px`);
832
951
  snapFooterToKeyboard = embeddedFooterElement.classList.contains('snap-to-keyboard');
@@ -885,86 +1004,6 @@ class ModalWrapperComponent {
885
1004
  }
886
1005
  }
887
1006
  }
888
- clearEmbeddedElements() {
889
- Object.entries(this.elementToParentMap).forEach(([tagName, getParents]) => {
890
- const newParents = getParents();
891
- newParents.forEach((newParent) => {
892
- const embeddedElement = newParent.querySelector(`:scope > ${tagName}`);
893
- this.removeChild(embeddedElement);
894
- });
895
- });
896
- }
897
- /* TODO: Rewrite to make this function independent of element order.
898
- See: https://github.com/kirbydesign/designsystem/issues/2096
899
- */
900
- getEmbeddedComponentElement() {
901
- const contentElementChildren = Array.from(this.ionContentElement.nativeElement.children).reverse(); // Reverse makes it easier to retrieve the last children in the list
902
- const embeddedComponentElement = !!this.config.modalRoute
903
- ? contentElementChildren[0]
904
- : contentElementChildren[1];
905
- /*
906
- As ModalConfig.component has type 'any' all values are valid for component;
907
- explicitly handle the case where no embedded component element is found due to
908
- this.
909
- */
910
- if (!embeddedComponentElement)
911
- return null;
912
- return embeddedComponentElement;
913
- }
914
- getEmbeddedFooterElement() {
915
- return this.elementRef.nativeElement.querySelector('kirby-modal-footer');
916
- }
917
- moveChild(child, newParents) {
918
- this.renderer.removeChild(child.parentElement, child);
919
- newParents.forEach((newParent, index) => {
920
- const childToAppend = index > 0 ? child.cloneNode(true) : child;
921
- this.renderer.appendChild(newParent, childToAppend);
922
- // Append adds child as last element of parent; therefore retrieve with lastElementChild
923
- const childElement = newParent.lastElementChild;
924
- if (childElement.tagName === 'KIRBY-MODAL-FOOTER') {
925
- this.resizeObserverService.observe(childElement, (entry) => {
926
- const [property, pixelValue] = [
927
- '--footer-height',
928
- `${Math.floor(entry.contentRect.height)}px`,
929
- ];
930
- this.setCssVar(this.elementRef.nativeElement, property, pixelValue);
931
- });
932
- }
933
- });
934
- }
935
- removeChild(child) {
936
- if (!!child) {
937
- this.renderer.removeChild(child.parentElement, child);
938
- }
939
- }
940
- observeEmbeddedElements() {
941
- const parentElement = this.getEmbeddedComponentElement();
942
- if (parentElement === null)
943
- return; // Mute observe warning when parentElement is null
944
- this.mutationObserver.observe(parentElement, {
945
- childList: true, // Listen for addition or removal of child nodes
946
- });
947
- }
948
- createEmbeddedElementsMutationObserver() {
949
- const observedElements = Object.keys(this.elementToParentMap);
950
- const callback = (mutations) => {
951
- const addedNodes = mutations
952
- .filter((mutation) => mutation.type === 'childList') // Filter for mutation to the tree of nodes
953
- .map((mutation) => {
954
- // Only check for addedNodes as removal is handled by the Angular renderer:
955
- return Array.from(mutation.addedNodes).filter((node) => observedElements.includes(node.nodeName));
956
- });
957
- const addedElements = Array.prototype
958
- .concat(...addedNodes)
959
- .filter((node) => node instanceof HTMLElement);
960
- addedElements.forEach((addedElement) => {
961
- const newParentElement = this.elementToParentMap[addedElement.nodeName]();
962
- // Move embedded element out of content and append to new parent:
963
- this.moveChild(addedElement, newParentElement);
964
- });
965
- };
966
- return new MutationObserver(callback);
967
- }
968
1007
  createModalWrapperIntersectionObserver() {
969
1008
  const callback = (entries) => {
970
1009
  const entry = entries[0];
@@ -992,26 +1031,31 @@ class ModalWrapperComponent {
992
1031
  this.routerOutlet.deactivate();
993
1032
  }
994
1033
  //clean up the observer
995
- this.mutationObserver.disconnect();
996
1034
  delete this._mutationObserver;
997
1035
  this.intersectionObserver.disconnect();
998
1036
  delete this._intersectionObserver;
999
1037
  if (this.resizeObserverService) {
1000
1038
  this.resizeObserverService.unobserve(this.windowRef.nativeWindow.document.body);
1001
1039
  this.resizeObserverService.unobserve(this.ionHeaderElement.nativeElement);
1002
- this.resizeObserverService.unobserve(this.getEmbeddedFooterElement());
1040
+ this.resizeObserverService.unobserve(this.currentFooter);
1003
1041
  }
1004
1042
  this.destroy$.next();
1005
1043
  this.destroy$.complete();
1006
1044
  }
1007
1045
  }
1008
1046
  ModalWrapperComponent.KEYBOARD_HIDE_DELAY_IN_MS = 100;
1009
- /** @nocollapse */ ModalWrapperComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalWrapperComponent, deps: [{ token: i0.Injector }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: ResizeObserverService }, { token: i0.ComponentFactoryResolver }, { token: WindowRef }, { token: PlatformService }], target: i0.ɵɵFactoryTarget.Component });
1010
- /** @nocollapse */ ModalWrapperComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: ModalWrapperComponent, selector: "kirby-modal-wrapper", inputs: { config: "config" }, host: { listeners: { "window:focus": "onFocusChange()", "window:focusout": "onFocusChange()", "window:ionKeyboardDidShow": "_onKeyboardShow($event.detail.keyboardHeight)", "window:keyboardWillShow": "_onKeyboardShow($event.keyboardHeight)", "window:ionKeyboardDidHide": "_onKeyboardHide()", "window:keyboardWillHide": "_onKeyboardHide()", "window:resize": "_onWindowResize()" }, properties: { "class.collapsible-title": "this._hasCollapsibleTitle", "class.drawer": "this._isDrawer" } }, providers: [{ provide: Modal, useExisting: ModalWrapperComponent }], viewQueries: [{ propertyName: "ionContent", first: true, predicate: IonContent, descendants: true, static: true }, { propertyName: "ionContentElement", first: true, predicate: IonContent, descendants: true, read: ElementRef, static: true }, { propertyName: "ionHeaderElement", first: true, predicate: IonHeader, descendants: true, read: ElementRef, static: true }, { propertyName: "ionToolbarElement", first: true, predicate: IonToolbar, descendants: true, read: ElementRef, static: true }, { propertyName: "ionTitleElement", first: true, predicate: IonTitle, descendants: true, read: ElementRef, static: true }, { propertyName: "routerOutlet", first: true, predicate: RouterOutlet, descendants: true, static: true }, { propertyName: "contentTitle", first: true, predicate: ["contentTitle"], descendants: true, read: ElementRef }, { propertyName: "toolbarButtonsQuery", predicate: ButtonComponent, descendants: true, read: ElementRef }], ngImport: i0, template: "<ion-header (touchstart)=\"onHeaderTouchStart($event)\">\n <ion-toolbar>\n <ion-title></ion-title>\n <ion-buttons slot=\"start\" *ngIf=\"config.flavor === 'drawer'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'arrow-down' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'modal'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'close' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'drawer' && config.drawerSupplementaryAction\">\n <ng-container\n *ngTemplateOutlet=\"supplementaryButton; context: { btn: config.drawerSupplementaryAction }\"\n ></ng-container>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [scrollEvents]=\"true\">\n <ion-header *ngIf=\"_hasCollapsibleTitle\" collapse=\"condense\">\n <ion-toolbar>\n <span class=\"kirby-text-large\" #contentTitle></span>\n </ion-toolbar>\n </ion-header>\n <ng-container\n *ngComponentOutlet=\"config.component; injector: componentPropsInjector\"\n ></ng-container>\n <router-outlet\n name=\"kirbyModalWrapperOutlet\"\n [style.visibility]=\"config.modalRoute ? 'visible' : 'hidden'\"\n ></router-outlet>\n</ion-content>\n\n<ng-template #closeButton let-icon=\"icon\">\n <button kirby-button attentionLevel=\"4\" size=\"md\" (click)=\"close()\">\n <kirby-icon [name]=\"icon\"></kirby-icon>\n </button>\n</ng-template>\n\n<ng-template #supplementaryButton let-btn=\"btn\">\n <button kirby-button attentionLevel=\"2\" size=\"md\" (click)=\"btn.action($event)\">\n <kirby-icon [name]=\"btn.iconName\"></kirby-icon>\n </button>\n</ng-template>\n", styles: ["ion-header ion-toolbar{--padding-start: 16px;--padding-end: 16px;--padding-bottom: 12px;--padding-top: 12px;--border-width: 0;--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black))}ion-header ion-toolbar button{color:var(--color)}@media (min-width: 721px){ion-header ion-toolbar{padding-top:8px}}:host{--vh100: var(--vh, 1vh) * 100;--header-height: 0px;--footer-height: 0px}:host.drawer ion-header ion-toolbar:first-of-type{padding-top:0}@media (min-width: 721px){:host-context(ion-modal:not(.kirby-modal-full-height)){padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer{padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:var(--kirby-safe-area-top, 0)}@media (min-width: 721px){:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:8px}}ion-title{box-sizing:border-box;padding-inline-start:calc(48px + var(--padding-start));padding-inline-end:calc(48px + var(--padding-end));font-size:22px;font-weight:700}:host(.drawer) ion-title{font-size:18px}ion-content{--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black));display:flex;flex-direction:column;--padding-top: 24px;--padding-bottom: 24px;--padding-start: 16px;--padding-end: 16px}ion-content ::ng-deep>*{box-sizing:border-box;display:block}@media (min-width: 721px){ion-content{--padding-start: 56px;--padding-end: 56px}}:host(.collapsible-title) ion-content{--padding-top: 0px}:host(.collapsible-title) ion-content ion-header ion-toolbar:first-of-type{padding-top:0;--padding-top: 0px;--padding-bottom: 0px;--padding-start: 0px;--padding-end: 0px}:host(.collapsible-title) ion-title{font-size:16px;font-weight:700}\n"], components: [{ type: i1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { type: i1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { type: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { type: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { type: ButtonComponent, selector: "button[kirby-button],Button[kirby-button]", inputs: ["attentionLevel", "isDestructive", "themeColor", "expand", "isFloating", "size"] }, { type: IconComponent, selector: "kirby-icon", inputs: ["size", "name", "customName"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModuleFactory"] }, { type: i1$1.RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
1047
+ /** @nocollapse */ ModalWrapperComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalWrapperComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Injector }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: ResizeObserverService }, { token: i0.ComponentFactoryResolver }, { token: WindowRef }, { token: PlatformService }], target: i0.ɵɵFactoryTarget.Component });
1048
+ /** @nocollapse */ ModalWrapperComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: ModalWrapperComponent, selector: "kirby-modal-wrapper", inputs: { config: "config" }, host: { listeners: { "window:focus": "onFocusChange()", "window:focusout": "onFocusChange()", "window:ionKeyboardDidShow": "_onKeyboardShow($event.detail.keyboardHeight)", "window:keyboardWillShow": "_onKeyboardShow($event.keyboardHeight)", "window:ionKeyboardDidHide": "_onKeyboardHide()", "window:keyboardWillHide": "_onKeyboardHide()", "window:resize": "_onWindowResize()" }, properties: { "class.collapsible-title": "this._hasCollapsibleTitle", "class.drawer": "this._isDrawer" } }, providers: [
1049
+ { provide: Modal, useExisting: ModalWrapperComponent },
1050
+ { provide: ModalElementsAdvertiser, useExisting: ModalWrapperComponent },
1051
+ ], viewQueries: [{ propertyName: "ionContent", first: true, predicate: IonContent, descendants: true, static: true }, { propertyName: "ionContentElement", first: true, predicate: IonContent, descendants: true, read: ElementRef, static: true }, { propertyName: "ionHeaderElement", first: true, predicate: IonHeader, descendants: true, read: ElementRef, static: true }, { propertyName: "ionToolbarElement", first: true, predicate: IonToolbar, descendants: true, read: ElementRef, static: true }, { propertyName: "ionTitleElement", first: true, predicate: IonTitle, descendants: true, read: ElementRef, static: true }, { propertyName: "routerOutlet", first: true, predicate: RouterOutlet, descendants: true, static: true }, { propertyName: "_contentTitleElement", first: true, predicate: ["contentTitle"], descendants: true, read: ElementRef }, { propertyName: "toolbarButtonsQuery", predicate: ButtonComponent, descendants: true, read: ElementRef }], ngImport: i0, template: "<ion-header (touchstart)=\"onHeaderTouchStart($event)\">\n <ion-toolbar>\n <ion-title></ion-title>\n <ion-buttons slot=\"start\" *ngIf=\"config.flavor === 'drawer'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'arrow-down' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'modal'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'close' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'drawer' && config.drawerSupplementaryAction\">\n <ng-container\n *ngTemplateOutlet=\"supplementaryButton; context: { btn: config.drawerSupplementaryAction }\"\n ></ng-container>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [scrollEvents]=\"true\">\n <ion-header *ngIf=\"_hasCollapsibleTitle\" collapse=\"condense\">\n <ion-toolbar>\n <span class=\"kirby-text-large\" #contentTitle></span>\n </ion-toolbar>\n </ion-header>\n <ng-container\n *ngComponentOutlet=\"config.component; injector: componentPropsInjector\"\n ></ng-container>\n <router-outlet\n name=\"kirbyModalWrapperOutlet\"\n [style.visibility]=\"config.modalRoute ? 'visible' : 'hidden'\"\n ></router-outlet>\n</ion-content>\n\n<ng-template #closeButton let-icon=\"icon\">\n <button kirby-button attentionLevel=\"4\" size=\"md\" (click)=\"close()\">\n <kirby-icon [name]=\"icon\"></kirby-icon>\n </button>\n</ng-template>\n\n<ng-template #supplementaryButton let-btn=\"btn\">\n <button kirby-button attentionLevel=\"2\" size=\"md\" (click)=\"btn.action($event)\">\n <kirby-icon [name]=\"btn.iconName\"></kirby-icon>\n </button>\n</ng-template>\n", styles: ["ion-header ion-toolbar{--padding-start: 16px;--padding-end: 16px;--padding-bottom: 12px;--padding-top: 12px;--border-width: 0;--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black))}ion-header ion-toolbar button{color:var(--color)}@media (min-width: 721px){ion-header ion-toolbar{padding-top:8px}}:host{--vh100: var(--vh, 1vh) * 100;--header-height: 0px;--footer-height: 0px}:host.drawer ion-header ion-toolbar:first-of-type{padding-top:0}@media (min-width: 721px){:host-context(ion-modal:not(.kirby-modal-full-height)){padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer{padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:var(--kirby-safe-area-top, 0)}@media (min-width: 721px){:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:8px}}ion-title{box-sizing:border-box;padding-inline-start:calc(48px + var(--padding-start));padding-inline-end:calc(48px + var(--padding-end));font-size:22px;font-weight:700}:host(.drawer) ion-title{font-size:18px}ion-content{--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black));display:flex;flex-direction:column;--padding-top: 24px;--padding-bottom: 24px;--padding-start: 16px;--padding-end: 16px}ion-content ::ng-deep>*{box-sizing:border-box;display:block}@media (min-width: 721px){ion-content{--padding-start: 56px;--padding-end: 56px}}:host(.collapsible-title) ion-content{--padding-top: 0px}:host(.collapsible-title) ion-content ion-header ion-toolbar:first-of-type{padding-top:0;--padding-top: 0px;--padding-bottom: 0px;--padding-start: 0px;--padding-end: 0px}:host(.collapsible-title) ion-title{font-size:16px;font-weight:700}\n"], components: [{ type: i1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { type: i1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { type: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { type: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { type: ButtonComponent, selector: "button[kirby-button],Button[kirby-button]", inputs: ["attentionLevel", "isDestructive", "themeColor", "expand", "isFloating", "size"] }, { type: IconComponent, selector: "kirby-icon", inputs: ["size", "name", "customName"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i2.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModuleFactory"] }, { type: i1$1.RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
1011
1052
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalWrapperComponent, decorators: [{
1012
1053
  type: Component,
1013
- args: [{ selector: 'kirby-modal-wrapper', providers: [{ provide: Modal, useExisting: ModalWrapperComponent }], template: "<ion-header (touchstart)=\"onHeaderTouchStart($event)\">\n <ion-toolbar>\n <ion-title></ion-title>\n <ion-buttons slot=\"start\" *ngIf=\"config.flavor === 'drawer'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'arrow-down' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'modal'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'close' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'drawer' && config.drawerSupplementaryAction\">\n <ng-container\n *ngTemplateOutlet=\"supplementaryButton; context: { btn: config.drawerSupplementaryAction }\"\n ></ng-container>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [scrollEvents]=\"true\">\n <ion-header *ngIf=\"_hasCollapsibleTitle\" collapse=\"condense\">\n <ion-toolbar>\n <span class=\"kirby-text-large\" #contentTitle></span>\n </ion-toolbar>\n </ion-header>\n <ng-container\n *ngComponentOutlet=\"config.component; injector: componentPropsInjector\"\n ></ng-container>\n <router-outlet\n name=\"kirbyModalWrapperOutlet\"\n [style.visibility]=\"config.modalRoute ? 'visible' : 'hidden'\"\n ></router-outlet>\n</ion-content>\n\n<ng-template #closeButton let-icon=\"icon\">\n <button kirby-button attentionLevel=\"4\" size=\"md\" (click)=\"close()\">\n <kirby-icon [name]=\"icon\"></kirby-icon>\n </button>\n</ng-template>\n\n<ng-template #supplementaryButton let-btn=\"btn\">\n <button kirby-button attentionLevel=\"2\" size=\"md\" (click)=\"btn.action($event)\">\n <kirby-icon [name]=\"btn.iconName\"></kirby-icon>\n </button>\n</ng-template>\n", styles: ["ion-header ion-toolbar{--padding-start: 16px;--padding-end: 16px;--padding-bottom: 12px;--padding-top: 12px;--border-width: 0;--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black))}ion-header ion-toolbar button{color:var(--color)}@media (min-width: 721px){ion-header ion-toolbar{padding-top:8px}}:host{--vh100: var(--vh, 1vh) * 100;--header-height: 0px;--footer-height: 0px}:host.drawer ion-header ion-toolbar:first-of-type{padding-top:0}@media (min-width: 721px){:host-context(ion-modal:not(.kirby-modal-full-height)){padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer{padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:var(--kirby-safe-area-top, 0)}@media (min-width: 721px){:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:8px}}ion-title{box-sizing:border-box;padding-inline-start:calc(48px + var(--padding-start));padding-inline-end:calc(48px + var(--padding-end));font-size:22px;font-weight:700}:host(.drawer) ion-title{font-size:18px}ion-content{--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black));display:flex;flex-direction:column;--padding-top: 24px;--padding-bottom: 24px;--padding-start: 16px;--padding-end: 16px}ion-content ::ng-deep>*{box-sizing:border-box;display:block}@media (min-width: 721px){ion-content{--padding-start: 56px;--padding-end: 56px}}:host(.collapsible-title) ion-content{--padding-top: 0px}:host(.collapsible-title) ion-content ion-header ion-toolbar:first-of-type{padding-top:0;--padding-top: 0px;--padding-bottom: 0px;--padding-start: 0px;--padding-end: 0px}:host(.collapsible-title) ion-title{font-size:16px;font-weight:700}\n"] }]
1014
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: ResizeObserverService }, { type: i0.ComponentFactoryResolver }, { type: WindowRef }, { type: PlatformService }]; }, propDecorators: { _hasCollapsibleTitle: [{
1054
+ args: [{ selector: 'kirby-modal-wrapper', providers: [
1055
+ { provide: Modal, useExisting: ModalWrapperComponent },
1056
+ { provide: ModalElementsAdvertiser, useExisting: ModalWrapperComponent },
1057
+ ], template: "<ion-header (touchstart)=\"onHeaderTouchStart($event)\">\n <ion-toolbar>\n <ion-title></ion-title>\n <ion-buttons slot=\"start\" *ngIf=\"config.flavor === 'drawer'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'arrow-down' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'modal'\">\n <ng-container *ngTemplateOutlet=\"closeButton; context: { icon: 'close' }\"></ng-container>\n </ion-buttons>\n <ion-buttons slot=\"end\" *ngIf=\"config.flavor === 'drawer' && config.drawerSupplementaryAction\">\n <ng-container\n *ngTemplateOutlet=\"supplementaryButton; context: { btn: config.drawerSupplementaryAction }\"\n ></ng-container>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content [scrollEvents]=\"true\">\n <ion-header *ngIf=\"_hasCollapsibleTitle\" collapse=\"condense\">\n <ion-toolbar>\n <span class=\"kirby-text-large\" #contentTitle></span>\n </ion-toolbar>\n </ion-header>\n <ng-container\n *ngComponentOutlet=\"config.component; injector: componentPropsInjector\"\n ></ng-container>\n <router-outlet\n name=\"kirbyModalWrapperOutlet\"\n [style.visibility]=\"config.modalRoute ? 'visible' : 'hidden'\"\n ></router-outlet>\n</ion-content>\n\n<ng-template #closeButton let-icon=\"icon\">\n <button kirby-button attentionLevel=\"4\" size=\"md\" (click)=\"close()\">\n <kirby-icon [name]=\"icon\"></kirby-icon>\n </button>\n</ng-template>\n\n<ng-template #supplementaryButton let-btn=\"btn\">\n <button kirby-button attentionLevel=\"2\" size=\"md\" (click)=\"btn.action($event)\">\n <kirby-icon [name]=\"btn.iconName\"></kirby-icon>\n </button>\n</ng-template>\n", styles: ["ion-header ion-toolbar{--padding-start: 16px;--padding-end: 16px;--padding-bottom: 12px;--padding-top: 12px;--border-width: 0;--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black))}ion-header ion-toolbar button{color:var(--color)}@media (min-width: 721px){ion-header ion-toolbar{padding-top:8px}}:host{--vh100: var(--vh, 1vh) * 100;--header-height: 0px;--footer-height: 0px}:host.drawer ion-header ion-toolbar:first-of-type{padding-top:0}@media (min-width: 721px){:host-context(ion-modal:not(.kirby-modal-full-height)){padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)) ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer{padding-top:0;position:relative;contain:inherit;min-height:min(var(--min-height),var(--vh100) - var(--kirby-modal-padding-top, 0px))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content{contain:content;max-height:calc(var(--vh100) - var(--kirby-modal-padding-top, 0px) - var(--header-height) - var(--footer-height))}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer ion-content::part(scroll){height:\"100%\";position:relative}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer ion-content::part(scroll){transition:padding-bottom .15s ease-out}:host-context(ion-modal:not(.kirby-modal-full-height)).drawer.drawer.keyboard-visible ion-content::part(scroll){transition:padding-bottom .25s ease-out 1ms}:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:var(--kirby-safe-area-top, 0)}@media (min-width: 721px){:host-context(ion-modal.modal-card:not(.kirby-drawer)) ion-header ion-toolbar:first-of-type{padding-top:8px}}ion-title{box-sizing:border-box;padding-inline-start:calc(48px + var(--padding-start));padding-inline-end:calc(48px + var(--padding-end));font-size:22px;font-weight:700}:host(.drawer) ion-title{font-size:18px}ion-content{--background: transparent;--color: var(--kirby-modal-color, var(--kirby-black));display:flex;flex-direction:column;--padding-top: 24px;--padding-bottom: 24px;--padding-start: 16px;--padding-end: 16px}ion-content ::ng-deep>*{box-sizing:border-box;display:block}@media (min-width: 721px){ion-content{--padding-start: 56px;--padding-end: 56px}}:host(.collapsible-title) ion-content{--padding-top: 0px}:host(.collapsible-title) ion-content ion-header ion-toolbar:first-of-type{padding-top:0;--padding-top: 0px;--padding-bottom: 0px;--padding-start: 0px;--padding-end: 0px}:host(.collapsible-title) ion-title{font-size:16px;font-weight:700}\n"] }]
1058
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Injector }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: ResizeObserverService }, { type: i0.ComponentFactoryResolver }, { type: WindowRef }, { type: PlatformService }]; }, propDecorators: { _hasCollapsibleTitle: [{
1015
1059
  type: HostBinding,
1016
1060
  args: ['class.collapsible-title']
1017
1061
  }], config: [{
@@ -1037,7 +1081,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
1037
1081
  }], routerOutlet: [{
1038
1082
  type: ViewChild,
1039
1083
  args: [RouterOutlet, { static: true }]
1040
- }], contentTitle: [{
1084
+ }], _contentTitleElement: [{
1041
1085
  type: ViewChild,
1042
1086
  args: ['contentTitle', { read: ElementRef }]
1043
1087
  }], _isDrawer: [{
@@ -5089,7 +5133,6 @@ class DropdownComponent {
5089
5133
  this.changeDetectorRef = changeDetectorRef;
5090
5134
  this.keyboardHandlerService = keyboardHandlerService;
5091
5135
  this.state = OpenState.closed;
5092
- this.hasConfiguredSlottedItems = false;
5093
5136
  this.horizontalDirection = HorizontalDirection.right;
5094
5137
  this.verticalDirection = VerticalDirection.down;
5095
5138
  this._items = [];
@@ -5165,6 +5208,25 @@ class DropdownComponent {
5165
5208
  get _popoutUp() {
5166
5209
  return this.verticalDirection === VerticalDirection.up;
5167
5210
  }
5211
+ set kirbyItemsSlotted(kirbyItems) {
5212
+ var _a;
5213
+ const hasSlottedItems = ((_a = this.itemClickUnlisten) === null || _a === void 0 ? void 0 : _a.length) > 0;
5214
+ if (hasSlottedItems) {
5215
+ this.unlistenAllSlottedItems();
5216
+ }
5217
+ // Setup a click listener for each new slotted items
5218
+ kirbyItems.forEach((kirbyItem, index) => {
5219
+ this.renderer.setAttribute(kirbyItem.nativeElement, 'role', 'option');
5220
+ const unlisten = this.renderer.listen(kirbyItem.nativeElement, 'click', () => {
5221
+ this.onItemSelect(index);
5222
+ });
5223
+ this.itemClickUnlisten.push(unlisten);
5224
+ });
5225
+ this._kirbyItemsSlotted = kirbyItems;
5226
+ }
5227
+ get kirbyItemsSlotted() {
5228
+ return this._kirbyItemsSlotted;
5229
+ }
5168
5230
  onToggle(event) {
5169
5231
  event.stopPropagation();
5170
5232
  if (!this.isOpen) {
@@ -5182,18 +5244,6 @@ class DropdownComponent {
5182
5244
  // Prevent button focus;
5183
5245
  event.preventDefault();
5184
5246
  }
5185
- ngAfterContentChecked() {
5186
- if (!this.hasConfiguredSlottedItems && this.kirbyItemsSlotted.length) {
5187
- this.kirbyItemsSlotted.forEach((kirbyItem, index) => {
5188
- this.renderer.setAttribute(kirbyItem.nativeElement, 'role', 'option');
5189
- const unlisten = this.renderer.listen(kirbyItem.nativeElement, 'click', () => {
5190
- this.onItemSelect(index);
5191
- });
5192
- this.itemClickUnlisten.push(unlisten);
5193
- });
5194
- this.hasConfiguredSlottedItems = true;
5195
- }
5196
- }
5197
5247
  /* Utility that makes it easier to set styles on card element
5198
5248
  when using popover*/
5199
5249
  setPopoverCardStyle(style, value) {
@@ -5448,11 +5498,14 @@ class DropdownComponent {
5448
5498
  }
5449
5499
  return false;
5450
5500
  }
5451
- ngOnDestroy() {
5452
- let unlisten;
5453
- while ((unlisten = this.itemClickUnlisten.pop()) !== undefined) {
5454
- unlisten();
5501
+ unlistenAllSlottedItems() {
5502
+ let unlistenItem;
5503
+ while ((unlistenItem = this.itemClickUnlisten.pop()) !== undefined) {
5504
+ unlistenItem();
5455
5505
  }
5506
+ }
5507
+ ngOnDestroy() {
5508
+ this.unlistenAllSlottedItems();
5456
5509
  if (this.intersectionObserverRef) {
5457
5510
  this.intersectionObserverRef.disconnect();
5458
5511
  }
@@ -7862,18 +7915,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
7862
7915
  }]
7863
7916
  }] });
7864
7917
 
7865
- class ModalFooterComponent {
7866
- constructor() {
7918
+ class ModalFooterComponent extends ModalElementComponent {
7919
+ constructor(elementRef, modalElementsAdvertiser) {
7920
+ super(ModalElementType.FOOTER, elementRef, modalElementsAdvertiser);
7867
7921
  this.snapToKeyboard = false;
7868
7922
  this.type = 'fixed';
7869
7923
  }
7870
7924
  }
7871
- /** @nocollapse */ ModalFooterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7872
- /** @nocollapse */ ModalFooterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: ModalFooterComponent, selector: "kirby-modal-footer", inputs: { snapToKeyboard: "snapToKeyboard", type: "type" }, host: { properties: { "class.snap-to-keyboard": "this.snapToKeyboard", "class": "this.type" } }, ngImport: i0, template: "<ion-footer>\n <ng-content></ng-content>\n</ion-footer>\n", styles: ["ion-footer{box-shadow:0 20px 30px -15px #1c1c1c4d,0 0 5px #1c1c1c14;display:flex;justify-content:var(--kirby-modal-footer-justify-content, center);align-items:center;background-color:var(--kirby-modal-footer-background, var(--kirby-white));color:var(--kirby-modal-footer-color, var(--kirby-white-contrast));padding:8px 16px;padding-bottom:calc(8px + var(--kirby-modal-footer-safe-area-bottom, 0px))}@media (max-width: 720px){:host{--kirby-modal-footer-safe-area-bottom: var(--kirby-safe-area-bottom)}}:host(.snap-to-keyboard) ion-footer{transition:transform .15s ease-out}:host(.light) ion-footer{background-color:var(--kirby-background-color)}:host(.inline) ion-footer{background:transparent;box-shadow:none}:host-context(.keyboard-visible).snap-to-keyboard ion-footer{transition:transform .25s ease-out 1ms;transform:translateY(calc((var(--keyboard-offset, 0px) - var(--kirby-modal-footer-safe-area-bottom, 0px)) * -1))}:host-context(.modal-wrapper.full-height){--kirby-modal-footer-safe-area-bottom: var(--kirby-safe-area-bottom)}\n"], components: [{ type: i1.IonFooter, selector: "ion-footer", inputs: ["mode", "translucent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7925
+ /** @nocollapse */ ModalFooterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalFooterComponent, deps: [{ token: i0.ElementRef }, { token: ModalElementsAdvertiser, optional: true }], target: i0.ɵɵFactoryTarget.Component });
7926
+ /** @nocollapse */ ModalFooterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: ModalFooterComponent, selector: "kirby-modal-footer", inputs: { snapToKeyboard: "snapToKeyboard", type: "type" }, host: { properties: { "class.snap-to-keyboard": "this.snapToKeyboard", "class": "this.type" } }, usesInheritance: true, ngImport: i0, template: "<ion-footer>\n <ng-content></ng-content>\n</ion-footer>\n", styles: ["ion-footer{box-shadow:0 20px 30px -15px #1c1c1c4d,0 0 5px #1c1c1c14;display:flex;justify-content:var(--kirby-modal-footer-justify-content, center);align-items:center;background-color:var(--kirby-modal-footer-background, var(--kirby-white));color:var(--kirby-modal-footer-color, var(--kirby-white-contrast));padding:8px 16px;padding-bottom:calc(8px + var(--kirby-modal-footer-safe-area-bottom, 0px))}@media (max-width: 720px){:host{--kirby-modal-footer-safe-area-bottom: var(--kirby-safe-area-bottom)}}:host(.snap-to-keyboard) ion-footer{transition:transform .15s ease-out}:host(.light) ion-footer{background-color:var(--kirby-background-color)}:host(.inline) ion-footer{background:transparent;box-shadow:none}:host-context(.keyboard-visible).snap-to-keyboard ion-footer{transition:transform .25s ease-out 1ms;transform:translateY(calc((var(--keyboard-offset, 0px) - var(--kirby-modal-footer-safe-area-bottom, 0px)) * -1))}:host-context(.modal-wrapper.full-height){--kirby-modal-footer-safe-area-bottom: var(--kirby-safe-area-bottom)}\n"], components: [{ type: i1.IonFooter, selector: "ion-footer", inputs: ["mode", "translucent"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7873
7927
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalFooterComponent, decorators: [{
7874
7928
  type: Component,
7875
7929
  args: [{ selector: 'kirby-modal-footer', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ion-footer>\n <ng-content></ng-content>\n</ion-footer>\n", styles: ["ion-footer{box-shadow:0 20px 30px -15px #1c1c1c4d,0 0 5px #1c1c1c14;display:flex;justify-content:var(--kirby-modal-footer-justify-content, center);align-items:center;background-color:var(--kirby-modal-footer-background, var(--kirby-white));color:var(--kirby-modal-footer-color, var(--kirby-white-contrast));padding:8px 16px;padding-bottom:calc(8px + var(--kirby-modal-footer-safe-area-bottom, 0px))}@media (max-width: 720px){:host{--kirby-modal-footer-safe-area-bottom: var(--kirby-safe-area-bottom)}}:host(.snap-to-keyboard) ion-footer{transition:transform .15s ease-out}:host(.light) ion-footer{background-color:var(--kirby-background-color)}:host(.inline) ion-footer{background:transparent;box-shadow:none}:host-context(.keyboard-visible).snap-to-keyboard ion-footer{transition:transform .25s ease-out 1ms;transform:translateY(calc((var(--keyboard-offset, 0px) - var(--kirby-modal-footer-safe-area-bottom, 0px)) * -1))}:host-context(.modal-wrapper.full-height){--kirby-modal-footer-safe-area-bottom: var(--kirby-safe-area-bottom)}\n"] }]
7876
- }], propDecorators: { snapToKeyboard: [{
7930
+ }], ctorParameters: function () {
7931
+ return [{ type: i0.ElementRef }, { type: ModalElementsAdvertiser, decorators: [{
7932
+ type: Optional
7933
+ }] }];
7934
+ }, propDecorators: { snapToKeyboard: [{
7877
7935
  type: HostBinding,
7878
7936
  args: ['class.snap-to-keyboard']
7879
7937
  }, {
@@ -8128,8 +8186,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
8128
8186
  type: Input,
8129
8187
  args: ['kirbyPageContent']
8130
8188
  }] } });
8131
- class PageProgressComponent {
8132
- constructor(modalWrapper) {
8189
+ class PageProgressComponent extends ModalElementComponent {
8190
+ constructor(modalWrapper, modalElementsAdvertiser, elementRef) {
8191
+ super(ModalElementType.PAGE_PROGRESS, elementRef, modalElementsAdvertiser);
8133
8192
  this.modalWrapper = modalWrapper;
8134
8193
  // TODO: Find alternative implementation, which aligns with future page configuration / consumption
8135
8194
  // This implementation was chosen over expanding `moveChild` method in component wrapper with yet another scenario
@@ -8141,8 +8200,8 @@ class PageProgressComponent {
8141
8200
  }
8142
8201
  }
8143
8202
  }
8144
- /** @nocollapse */ PageProgressComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageProgressComponent, deps: [{ token: ModalWrapperComponent, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Component });
8145
- /** @nocollapse */ PageProgressComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: PageProgressComponent, selector: "kirby-page-progress", host: { properties: { "attr.slot": "this.slot" } }, ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true, styles: [":host{display:flex}\n"] });
8203
+ /** @nocollapse */ PageProgressComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageProgressComponent, deps: [{ token: ModalWrapperComponent, optional: true, skipSelf: true }, { token: ModalElementsAdvertiser, optional: true }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
8204
+ /** @nocollapse */ PageProgressComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: PageProgressComponent, selector: "kirby-page-progress", host: { properties: { "attr.slot": "this.slot" } }, usesInheritance: true, ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true, styles: [":host{display:flex}\n"] });
8146
8205
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageProgressComponent, decorators: [{
8147
8206
  type: Component,
8148
8207
  args: [{
@@ -8155,22 +8214,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
8155
8214
  type: Optional
8156
8215
  }, {
8157
8216
  type: SkipSelf
8158
- }] }];
8217
+ }] }, { type: ModalElementsAdvertiser, decorators: [{
8218
+ type: Optional
8219
+ }] }, { type: i0.ElementRef }];
8159
8220
  }, propDecorators: { slot: [{
8160
8221
  type: HostBinding,
8161
8222
  args: ['attr.slot']
8162
8223
  }] } });
8163
- class PageTitleComponent {
8224
+ class PageTitleComponent extends ModalElementComponent {
8225
+ constructor(elementRef, modalElementsAdvertiser) {
8226
+ super(ModalElementType.TITLE, elementRef, modalElementsAdvertiser);
8227
+ }
8164
8228
  }
8165
- /** @nocollapse */ PageTitleComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8166
- /** @nocollapse */ PageTitleComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: PageTitleComponent, selector: "kirby-page-title", ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true });
8229
+ /** @nocollapse */ PageTitleComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageTitleComponent, deps: [{ token: i0.ElementRef }, { token: ModalElementsAdvertiser, optional: true }], target: i0.ɵɵFactoryTarget.Component });
8230
+ /** @nocollapse */ PageTitleComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: PageTitleComponent, selector: "kirby-page-title", usesInheritance: true, ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true });
8167
8231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageTitleComponent, decorators: [{
8168
8232
  type: Component,
8169
8233
  args: [{
8170
8234
  selector: 'kirby-page-title',
8171
8235
  template: ` <ng-content></ng-content> `,
8172
8236
  }]
8173
- }] });
8237
+ }], ctorParameters: function () {
8238
+ return [{ type: i0.ElementRef }, { type: ModalElementsAdvertiser, decorators: [{
8239
+ type: Optional
8240
+ }] }];
8241
+ } });
8174
8242
  class PageContentComponent {
8175
8243
  }
8176
8244
  /** @nocollapse */ PageContentComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });