@kirbydesign/designsystem 6.1.1 → 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.
Files changed (41) hide show
  1. package/esm2020/lib/components/dropdown/dropdown.component.mjs +26 -18
  2. package/esm2020/lib/components/modal/footer/modal-footer.component.mjs +13 -8
  3. package/esm2020/lib/components/modal/modal-wrapper/modal-elements-mover.delegate.mjs +62 -0
  4. package/esm2020/lib/components/modal/modal-wrapper/modal-wrapper.component.mjs +66 -120
  5. package/esm2020/lib/components/modal/services/modal.interfaces.mjs +39 -1
  6. package/esm2020/lib/components/page/page.component.mjs +31 -21
  7. package/fesm2015/kirbydesign-designsystem.mjs +217 -149
  8. package/fesm2015/kirbydesign-designsystem.mjs.map +1 -1
  9. package/fesm2020/kirbydesign-designsystem.mjs +210 -149
  10. package/fesm2020/kirbydesign-designsystem.mjs.map +1 -1
  11. package/lib/components/avatar/avatar.component.d.ts +1 -1
  12. package/lib/components/dropdown/dropdown.component.d.ts +6 -5
  13. package/lib/components/modal/footer/modal-footer.component.d.ts +5 -2
  14. package/lib/components/modal/modal-wrapper/modal-elements-mover.delegate.d.ts +14 -0
  15. package/lib/components/modal/modal-wrapper/modal-wrapper.component.d.ts +13 -16
  16. package/lib/components/modal/services/modal.interfaces.d.ts +22 -0
  17. package/lib/components/page/page.component.d.ts +7 -5
  18. package/package.json +2 -2
  19. package/scss/_trigger-publish.scss +0 -1
  20. package/scss/_trigger.scss +0 -1
  21. package/scss/awesome-stylesheet.scss +0 -1
  22. package/scss/base/_awesome-partial.scss +0 -1
  23. package/scss/base/_index.scss +0 -1
  24. package/scss/base/_interaction-states.scss +0 -1
  25. package/scss/base/_link.scss +0 -1
  26. package/scss/base/index.scss +0 -1
  27. package/scss/interaction-state/_active.scss +0 -1
  28. package/scss/interaction-state/_focus.scss +0 -1
  29. package/scss/interaction-state/_hover.scss +0 -1
  30. package/scss/interaction-state/_index.scss +0 -1
  31. package/scss/interaction-state/_interaction-state.utilities.scss +0 -1
  32. package/scss/interaction-state/_layer.scss +0 -1
  33. package/scss/interaction-state/_state-layer.scss +0 -1
  34. package/scss/interaction-state/_utilities.scss +0 -1
  35. package/scss/interaction-state/ionic/_active.scss +0 -1
  36. package/scss/interaction-state/ionic/_hover.scss +0 -1
  37. package/scss/interaction-state/ionic/_index.scss +0 -1
  38. package/scss/interaction-states/_hover.scss +0 -1
  39. package/scss/interaction-states/_index.scss +0 -1
  40. package/scss/opt-out/_index.scss +0 -1
  41. package/scss/opt-out/_link.scss +0 -1
@@ -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, ElementRef, ContentChild, EventEmitter, Output, ContentChildren, ViewChild, InjectionToken, Injector, HostListener, RendererStyleFlags2, ViewChildren, Optional, Inject, NgModule, ChangeDetectorRef, NgZone, LOCALE_ID, forwardRef, TemplateRef, Pipe, SkipSelf, APP_INITIALIZER } from '@angular/core';
4
+ import { Directive, Injectable, Component, ChangeDetectionStrategy, HostBinding, Input, ElementRef, ContentChild, EventEmitter, Output, ContentChildren, ViewChild, Optional, InjectionToken, Injector, HostListener, RendererStyleFlags2, ViewChildren, 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';
@@ -1161,6 +1161,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
1161
1161
 
1162
1162
  class Modal {
1163
1163
  }
1164
+ var ModalElementType;
1165
+ (function (ModalElementType) {
1166
+ ModalElementType[ModalElementType["PAGE_PROGRESS"] = 0] = "PAGE_PROGRESS";
1167
+ ModalElementType[ModalElementType["FOOTER"] = 1] = "FOOTER";
1168
+ ModalElementType[ModalElementType["TITLE"] = 2] = "TITLE";
1169
+ })(ModalElementType || (ModalElementType = {}));
1170
+ class ModalElementsAdvertiser {
1171
+ }
1172
+ class ModalElementComponent {
1173
+ constructor(modalElementType, elementRef, modalElementsAdvertiser) {
1174
+ this.modalElementType = modalElementType;
1175
+ this.elementRef = elementRef;
1176
+ this.modalElementsAdvertiser = modalElementsAdvertiser;
1177
+ }
1178
+ get isContainedInModal() {
1179
+ return this.modalElementsAdvertiser !== null;
1180
+ }
1181
+ ngAfterViewInit() {
1182
+ if (this.isContainedInModal) {
1183
+ this.modalElementsAdvertiser.addModalElement(this.modalElementType, this.elementRef);
1184
+ }
1185
+ }
1186
+ ngOnDestroy() {
1187
+ if (this.isContainedInModal) {
1188
+ this.modalElementsAdvertiser.removeModalElement(this.modalElementType, this.elementRef);
1189
+ }
1190
+ }
1191
+ }
1192
+ /** @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 });
1193
+ /** @nocollapse */ ModalElementComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.9", type: ModalElementComponent, selector: "ng-component", ngImport: i0, template: '', isInline: true });
1194
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalElementComponent, decorators: [{
1195
+ type: Component,
1196
+ args: [{ template: '' }]
1197
+ }], ctorParameters: function () { return [{ type: ModalElementType }, { type: i0.ElementRef }, { type: ModalElementsAdvertiser, decorators: [{
1198
+ type: Optional
1199
+ }] }]; } });
1164
1200
 
1165
1201
  const COMPONENT_PROPS = new InjectionToken('componentProps');
1166
1202
 
@@ -1249,8 +1285,70 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
1249
1285
  }]
1250
1286
  }], ctorParameters: function () { return [{ type: WindowRef }]; } });
1251
1287
 
1288
+ /*
1289
+ The ModalWrapperComponent class was growing large.
1290
+
1291
+ Hence the functions responsible for moving modal elements around
1292
+ has been encapsulated in this class.
1293
+ */
1294
+ class ModalElementsMoverDelegate {
1295
+ constructor(renderer, elementRef) {
1296
+ this.renderer = renderer;
1297
+ this.elementRef = elementRef;
1298
+ }
1299
+ addFooter(footerElementRef) {
1300
+ // Move the footer next to ion-content
1301
+ this.moveChild(footerElementRef, this.elementRef);
1302
+ }
1303
+ removeFooter(footerElementRef) {
1304
+ this.removeChild(footerElementRef);
1305
+ }
1306
+ addPageProgress(pageProgressElementRef, ionToolbarElement) {
1307
+ this.moveChild(pageProgressElementRef, ionToolbarElement);
1308
+ }
1309
+ removePageProgress(pageProgressElementRef) {
1310
+ this.removeChild(pageProgressElementRef);
1311
+ }
1312
+ /*
1313
+ contentTitleElement & ionTitleElement has to be passed
1314
+ as arguments to the method; not part of the constructor, as they
1315
+ might reference completely different elements between calls.
1316
+
1317
+ For example in a multi-page routed modal where the elements are destroyed
1318
+ and recreated.
1319
+ */
1320
+ addTitle(titleElementRef, contentTitleElement, hasCollapsibleTitle, ionTitleElement) {
1321
+ this.moveChild(titleElementRef, ionTitleElement);
1322
+ // If title is collapsible append it to content area; required by ionic implementation.
1323
+ if (hasCollapsibleTitle) {
1324
+ const titleElementClone = titleElementRef.nativeElement.cloneNode(true);
1325
+ this.moveChild(new ElementRef(titleElementClone), contentTitleElement);
1326
+ }
1327
+ }
1328
+ removeTitle(titleElementRef, hasCollapsibleTitle, contentTitleElement) {
1329
+ this.removeChild(titleElementRef);
1330
+ if (hasCollapsibleTitle) {
1331
+ const kirbyPageTitleElement = contentTitleElement.nativeElement.querySelector('kirby-page-title');
1332
+ this.removeChild(new ElementRef(kirbyPageTitleElement));
1333
+ }
1334
+ }
1335
+ moveChild(childElementRef, newParentElementRef) {
1336
+ const child = childElementRef.nativeElement;
1337
+ const newParent = newParentElementRef.nativeElement;
1338
+ this.renderer.removeChild(child.parentElement, child);
1339
+ this.renderer.appendChild(newParent, child);
1340
+ }
1341
+ removeChild(childElementRef, parentElement) {
1342
+ const child = childElementRef.nativeElement;
1343
+ if (!!child) {
1344
+ this.renderer.removeChild(parentElement || child.parentElement, child);
1345
+ }
1346
+ }
1347
+ }
1348
+
1252
1349
  class ModalWrapperComponent {
1253
- constructor(injector, elementRef, renderer, zone, resizeObserverService, componentFactoryResolver, windowRef, platform) {
1350
+ constructor(changeDetector, injector, elementRef, renderer, zone, resizeObserverService, componentFactoryResolver, windowRef, platform) {
1351
+ this.changeDetector = changeDetector;
1254
1352
  this.injector = injector;
1255
1353
  this.elementRef = elementRef;
1256
1354
  this.renderer = renderer;
@@ -1275,13 +1373,10 @@ class ModalWrapperComponent {
1275
1373
  .pipe(debounceTime(this.VIEWPORT_RESIZE_DEBOUNCE_TIME));
1276
1374
  this.destroy$ = new Subject();
1277
1375
  this.willClose$ = this.ionModalWillDismiss.pipe(first());
1278
- this.elementToParentMap = {
1279
- 'KIRBY-MODAL-FOOTER': () => [this.elementRef.nativeElement],
1280
- 'KIRBY-PAGE-TITLE': () => [this.ionTitleElement.nativeElement, this.contentTitle?.nativeElement].filter((element) => element !== undefined),
1281
- 'KIRBY-PAGE-PROGRESS': () => [this.ionToolbarElement.nativeElement],
1282
- };
1376
+ this._currentFooter = null;
1283
1377
  this.setViewportHeight();
1284
1378
  this.observeViewportResize();
1379
+ this.modalElementsMoverDelegate = new ModalElementsMoverDelegate(renderer, elementRef);
1285
1380
  }
1286
1381
  get _hasCollapsibleTitle() {
1287
1382
  return !!this.config?.collapseTitle;
@@ -1289,11 +1384,15 @@ class ModalWrapperComponent {
1289
1384
  set scrollDisabled(disabled) {
1290
1385
  this.ionContent.scrollY = !disabled;
1291
1386
  }
1292
- get mutationObserver() {
1293
- if (!this._mutationObserver) {
1294
- this._mutationObserver = this.createEmbeddedElementsMutationObserver();
1387
+ get contentTitleElement() {
1388
+ /*
1389
+ contentTitleElement has ngIf directive dependent on _hasCollapsibleTitle; trigger CD to make sure element has been queried.
1390
+ Solution taken from: https://danieleyassu.com/angular-viewchild-and-ngif/
1391
+ */
1392
+ if (!this._contentTitleElement && this._hasCollapsibleTitle) {
1393
+ this.changeDetector.detectChanges();
1295
1394
  }
1296
- return this._mutationObserver;
1395
+ return this._contentTitleElement;
1297
1396
  }
1298
1397
  get intersectionObserver() {
1299
1398
  if (!this._intersectionObserver) {
@@ -1316,6 +1415,43 @@ class ModalWrapperComponent {
1316
1415
  parent: this.injector,
1317
1416
  });
1318
1417
  }
1418
+ set currentFooter(footer) {
1419
+ if (footer !== null) {
1420
+ this.resizeObserverService.observe(footer, (entry) => {
1421
+ const [property, pixelValue] = [
1422
+ '--footer-height',
1423
+ `${Math.floor(entry.contentRect.height)}px`,
1424
+ ];
1425
+ this.setCssVar(this.elementRef.nativeElement, property, pixelValue);
1426
+ });
1427
+ }
1428
+ this._currentFooter = footer;
1429
+ }
1430
+ get currentFooter() {
1431
+ return this._currentFooter;
1432
+ }
1433
+ addModalElement(type, modalElement) {
1434
+ const addModalElementFn = {
1435
+ [ModalElementType.FOOTER]: () => {
1436
+ this.modalElementsMoverDelegate.addFooter(modalElement);
1437
+ this.currentFooter = modalElement.nativeElement;
1438
+ },
1439
+ [ModalElementType.TITLE]: () => this.modalElementsMoverDelegate.addTitle(modalElement, this.contentTitleElement, this._hasCollapsibleTitle, this.ionTitleElement),
1440
+ [ModalElementType.PAGE_PROGRESS]: () => this.modalElementsMoverDelegate.addPageProgress(modalElement, this.ionToolbarElement),
1441
+ }[type];
1442
+ addModalElementFn();
1443
+ }
1444
+ removeModalElement(type, modalElement) {
1445
+ const removeModalElementFn = {
1446
+ [ModalElementType.FOOTER]: () => {
1447
+ this.modalElementsMoverDelegate.removeFooter(modalElement);
1448
+ this.currentFooter = null;
1449
+ },
1450
+ [ModalElementType.TITLE]: () => this.modalElementsMoverDelegate.removeTitle(modalElement, this._hasCollapsibleTitle, this.contentTitleElement),
1451
+ [ModalElementType.PAGE_PROGRESS]: () => this.modalElementsMoverDelegate.removePageProgress(modalElement),
1452
+ }[type];
1453
+ removeModalElementFn();
1454
+ }
1319
1455
  initializeResizeModalToModalWrapper() {
1320
1456
  if (this.config.flavor === 'drawer' && this.config.interactWithBackground) {
1321
1457
  merge(this.ionModalDidPresent, this.viewportResize$)
@@ -1352,12 +1488,9 @@ class ModalWrapperComponent {
1352
1488
  return;
1353
1489
  siblingModalRouteActivated$.pipe(takeUntil(this.willClose$)).subscribe((route) => {
1354
1490
  if (this.routerOutlet.isActivated) {
1355
- this.mutationObserver.disconnect();
1356
1491
  this.routerOutlet.deactivate();
1357
- this.clearEmbeddedElements();
1358
1492
  }
1359
1493
  this.routerOutlet.activateWith(route, this.componentFactoryResolver);
1360
- this.checkForEmbeddedElements();
1361
1494
  });
1362
1495
  }
1363
1496
  patchScrollElementSize() {
@@ -1385,11 +1518,6 @@ class ModalWrapperComponent {
1385
1518
  if (this.toolbarButtonsQuery) {
1386
1519
  this.toolbarButtons = this.toolbarButtonsQuery.map((buttonRef) => buttonRef.nativeElement);
1387
1520
  }
1388
- this.checkForEmbeddedElements();
1389
- }
1390
- checkForEmbeddedElements() {
1391
- this.moveEmbeddedElements();
1392
- this.observeEmbeddedElements();
1393
1521
  }
1394
1522
  observeHeaderResize() {
1395
1523
  this.resizeObserverService.observe(this.ionHeaderElement.nativeElement, (entry) => {
@@ -1397,17 +1525,6 @@ class ModalWrapperComponent {
1397
1525
  this.setCssVar(this.elementRef.nativeElement, property, pixelValue);
1398
1526
  });
1399
1527
  }
1400
- moveEmbeddedElements() {
1401
- const parentElement = this.getEmbeddedComponentElement();
1402
- if (parentElement) {
1403
- Object.entries(this.elementToParentMap).forEach(([tagName, getNewParent]) => {
1404
- const embeddedElement = parentElement.querySelector(tagName);
1405
- if (embeddedElement) {
1406
- this.moveChild(embeddedElement, getNewParent());
1407
- }
1408
- });
1409
- }
1410
- }
1411
1528
  listenForIonModalDidPresent() {
1412
1529
  if (this.ionModalElement) {
1413
1530
  this.ionModalElement.addEventListener('ionModalDidPresent', () => {
@@ -1504,7 +1621,7 @@ class ModalWrapperComponent {
1504
1621
  this.toggleCssClass(this.elementRef.nativeElement, 'keyboard-visible', keyboardHeight > 0);
1505
1622
  const keyboardOverlap = this.getKeyboardOverlap(keyboardHeight, this.elementRef.nativeElement);
1506
1623
  let snapFooterToKeyboard = false;
1507
- const embeddedFooterElement = this.getEmbeddedFooterElement();
1624
+ const embeddedFooterElement = this.currentFooter;
1508
1625
  if (embeddedFooterElement) {
1509
1626
  this.setCssVar(embeddedFooterElement, '--keyboard-offset', `${keyboardOverlap}px`);
1510
1627
  snapFooterToKeyboard = embeddedFooterElement.classList.contains('snap-to-keyboard');
@@ -1563,86 +1680,6 @@ class ModalWrapperComponent {
1563
1680
  }
1564
1681
  }
1565
1682
  }
1566
- clearEmbeddedElements() {
1567
- Object.entries(this.elementToParentMap).forEach(([tagName, getParents]) => {
1568
- const newParents = getParents();
1569
- newParents.forEach((newParent) => {
1570
- const embeddedElement = newParent.querySelector(`:scope > ${tagName}`);
1571
- this.removeChild(embeddedElement);
1572
- });
1573
- });
1574
- }
1575
- /* TODO: Rewrite to make this function independent of element order.
1576
- See: https://github.com/kirbydesign/designsystem/issues/2096
1577
- */
1578
- getEmbeddedComponentElement() {
1579
- const contentElementChildren = Array.from(this.ionContentElement.nativeElement.children).reverse(); // Reverse makes it easier to retrieve the last children in the list
1580
- const embeddedComponentElement = !!this.config.modalRoute
1581
- ? contentElementChildren[0]
1582
- : contentElementChildren[1];
1583
- /*
1584
- As ModalConfig.component has type 'any' all values are valid for component;
1585
- explicitly handle the case where no embedded component element is found due to
1586
- this.
1587
- */
1588
- if (!embeddedComponentElement)
1589
- return null;
1590
- return embeddedComponentElement;
1591
- }
1592
- getEmbeddedFooterElement() {
1593
- return this.elementRef.nativeElement.querySelector('kirby-modal-footer');
1594
- }
1595
- moveChild(child, newParents) {
1596
- this.renderer.removeChild(child.parentElement, child);
1597
- newParents.forEach((newParent, index) => {
1598
- const childToAppend = index > 0 ? child.cloneNode(true) : child;
1599
- this.renderer.appendChild(newParent, childToAppend);
1600
- // Append adds child as last element of parent; therefore retrieve with lastElementChild
1601
- const childElement = newParent.lastElementChild;
1602
- if (childElement.tagName === 'KIRBY-MODAL-FOOTER') {
1603
- this.resizeObserverService.observe(childElement, (entry) => {
1604
- const [property, pixelValue] = [
1605
- '--footer-height',
1606
- `${Math.floor(entry.contentRect.height)}px`,
1607
- ];
1608
- this.setCssVar(this.elementRef.nativeElement, property, pixelValue);
1609
- });
1610
- }
1611
- });
1612
- }
1613
- removeChild(child) {
1614
- if (!!child) {
1615
- this.renderer.removeChild(child.parentElement, child);
1616
- }
1617
- }
1618
- observeEmbeddedElements() {
1619
- const parentElement = this.getEmbeddedComponentElement();
1620
- if (parentElement === null)
1621
- return; // Mute observe warning when parentElement is null
1622
- this.mutationObserver.observe(parentElement, {
1623
- childList: true, // Listen for addition or removal of child nodes
1624
- });
1625
- }
1626
- createEmbeddedElementsMutationObserver() {
1627
- const observedElements = Object.keys(this.elementToParentMap);
1628
- const callback = (mutations) => {
1629
- const addedNodes = mutations
1630
- .filter((mutation) => mutation.type === 'childList') // Filter for mutation to the tree of nodes
1631
- .map((mutation) => {
1632
- // Only check for addedNodes as removal is handled by the Angular renderer:
1633
- return Array.from(mutation.addedNodes).filter((node) => observedElements.includes(node.nodeName));
1634
- });
1635
- const addedElements = Array.prototype
1636
- .concat(...addedNodes)
1637
- .filter((node) => node instanceof HTMLElement);
1638
- addedElements.forEach((addedElement) => {
1639
- const newParentElement = this.elementToParentMap[addedElement.nodeName]();
1640
- // Move embedded element out of content and append to new parent:
1641
- this.moveChild(addedElement, newParentElement);
1642
- });
1643
- };
1644
- return new MutationObserver(callback);
1645
- }
1646
1683
  createModalWrapperIntersectionObserver() {
1647
1684
  const callback = (entries) => {
1648
1685
  const entry = entries[0];
@@ -1670,26 +1707,31 @@ class ModalWrapperComponent {
1670
1707
  this.routerOutlet.deactivate();
1671
1708
  }
1672
1709
  //clean up the observer
1673
- this.mutationObserver.disconnect();
1674
1710
  delete this._mutationObserver;
1675
1711
  this.intersectionObserver.disconnect();
1676
1712
  delete this._intersectionObserver;
1677
1713
  if (this.resizeObserverService) {
1678
1714
  this.resizeObserverService.unobserve(this.windowRef.nativeWindow.document.body);
1679
1715
  this.resizeObserverService.unobserve(this.ionHeaderElement.nativeElement);
1680
- this.resizeObserverService.unobserve(this.getEmbeddedFooterElement());
1716
+ this.resizeObserverService.unobserve(this.currentFooter);
1681
1717
  }
1682
1718
  this.destroy$.next();
1683
1719
  this.destroy$.complete();
1684
1720
  }
1685
1721
  }
1686
1722
  ModalWrapperComponent.KEYBOARD_HIDE_DELAY_IN_MS = 100;
1687
- /** @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 });
1688
- /** @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"] }] });
1723
+ /** @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 });
1724
+ /** @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: [
1725
+ { provide: Modal, useExisting: ModalWrapperComponent },
1726
+ { provide: ModalElementsAdvertiser, useExisting: ModalWrapperComponent },
1727
+ ], 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"] }] });
1689
1728
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalWrapperComponent, decorators: [{
1690
1729
  type: Component,
1691
- 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"] }]
1692
- }], 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: [{
1730
+ args: [{ selector: 'kirby-modal-wrapper', providers: [
1731
+ { provide: Modal, useExisting: ModalWrapperComponent },
1732
+ { provide: ModalElementsAdvertiser, useExisting: ModalWrapperComponent },
1733
+ ], 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"] }]
1734
+ }], 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: [{
1693
1735
  type: HostBinding,
1694
1736
  args: ['class.collapsible-title']
1695
1737
  }], config: [{
@@ -1715,7 +1757,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
1715
1757
  }], routerOutlet: [{
1716
1758
  type: ViewChild,
1717
1759
  args: [RouterOutlet, { static: true }]
1718
- }], contentTitle: [{
1760
+ }], _contentTitleElement: [{
1719
1761
  type: ViewChild,
1720
1762
  args: ['contentTitle', { read: ElementRef }]
1721
1763
  }], _isDrawer: [{
@@ -5057,7 +5099,6 @@ class DropdownComponent {
5057
5099
  this.changeDetectorRef = changeDetectorRef;
5058
5100
  this.keyboardHandlerService = keyboardHandlerService;
5059
5101
  this.state = OpenState.closed;
5060
- this.hasConfiguredSlottedItems = false;
5061
5102
  this.horizontalDirection = HorizontalDirection.right;
5062
5103
  this.verticalDirection = VerticalDirection.down;
5063
5104
  this._items = [];
@@ -5133,6 +5174,24 @@ class DropdownComponent {
5133
5174
  get _popoutUp() {
5134
5175
  return this.verticalDirection === VerticalDirection.up;
5135
5176
  }
5177
+ set kirbyItemsSlotted(kirbyItems) {
5178
+ const hasSlottedItems = this.itemClickUnlisten?.length > 0;
5179
+ if (hasSlottedItems) {
5180
+ this.unlistenAllSlottedItems();
5181
+ }
5182
+ // Setup a click listener for each new slotted items
5183
+ kirbyItems.forEach((kirbyItem, index) => {
5184
+ this.renderer.setAttribute(kirbyItem.nativeElement, 'role', 'option');
5185
+ const unlisten = this.renderer.listen(kirbyItem.nativeElement, 'click', () => {
5186
+ this.onItemSelect(index);
5187
+ });
5188
+ this.itemClickUnlisten.push(unlisten);
5189
+ });
5190
+ this._kirbyItemsSlotted = kirbyItems;
5191
+ }
5192
+ get kirbyItemsSlotted() {
5193
+ return this._kirbyItemsSlotted;
5194
+ }
5136
5195
  onToggle(event) {
5137
5196
  event.stopPropagation();
5138
5197
  if (!this.isOpen) {
@@ -5150,18 +5209,6 @@ class DropdownComponent {
5150
5209
  // Prevent button focus;
5151
5210
  event.preventDefault();
5152
5211
  }
5153
- ngAfterContentChecked() {
5154
- if (!this.hasConfiguredSlottedItems && this.kirbyItemsSlotted.length) {
5155
- this.kirbyItemsSlotted.forEach((kirbyItem, index) => {
5156
- this.renderer.setAttribute(kirbyItem.nativeElement, 'role', 'option');
5157
- const unlisten = this.renderer.listen(kirbyItem.nativeElement, 'click', () => {
5158
- this.onItemSelect(index);
5159
- });
5160
- this.itemClickUnlisten.push(unlisten);
5161
- });
5162
- this.hasConfiguredSlottedItems = true;
5163
- }
5164
- }
5165
5212
  /* Utility that makes it easier to set styles on card element
5166
5213
  when using popover*/
5167
5214
  setPopoverCardStyle(style, value) {
@@ -5414,11 +5461,14 @@ class DropdownComponent {
5414
5461
  }
5415
5462
  return false;
5416
5463
  }
5417
- ngOnDestroy() {
5418
- let unlisten;
5419
- while ((unlisten = this.itemClickUnlisten.pop()) !== undefined) {
5420
- unlisten();
5464
+ unlistenAllSlottedItems() {
5465
+ let unlistenItem;
5466
+ while ((unlistenItem = this.itemClickUnlisten.pop()) !== undefined) {
5467
+ unlistenItem();
5421
5468
  }
5469
+ }
5470
+ ngOnDestroy() {
5471
+ this.unlistenAllSlottedItems();
5422
5472
  if (this.intersectionObserverRef) {
5423
5473
  this.intersectionObserverRef.disconnect();
5424
5474
  }
@@ -7814,18 +7864,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
7814
7864
  }]
7815
7865
  }] });
7816
7866
 
7817
- class ModalFooterComponent {
7818
- constructor() {
7867
+ class ModalFooterComponent extends ModalElementComponent {
7868
+ constructor(elementRef, modalElementsAdvertiser) {
7869
+ super(ModalElementType.FOOTER, elementRef, modalElementsAdvertiser);
7819
7870
  this.snapToKeyboard = false;
7820
7871
  this.type = 'fixed';
7821
7872
  }
7822
7873
  }
7823
- /** @nocollapse */ ModalFooterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7824
- /** @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 });
7874
+ /** @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 });
7875
+ /** @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 });
7825
7876
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: ModalFooterComponent, decorators: [{
7826
7877
  type: Component,
7827
7878
  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"] }]
7828
- }], propDecorators: { snapToKeyboard: [{
7879
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ModalElementsAdvertiser, decorators: [{
7880
+ type: Optional
7881
+ }] }]; }, propDecorators: { snapToKeyboard: [{
7829
7882
  type: HostBinding,
7830
7883
  args: ['class.snap-to-keyboard']
7831
7884
  }, {
@@ -8080,8 +8133,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
8080
8133
  type: Input,
8081
8134
  args: ['kirbyPageContent']
8082
8135
  }] } });
8083
- class PageProgressComponent {
8084
- constructor(modalWrapper) {
8136
+ class PageProgressComponent extends ModalElementComponent {
8137
+ constructor(modalWrapper, modalElementsAdvertiser, elementRef) {
8138
+ super(ModalElementType.PAGE_PROGRESS, elementRef, modalElementsAdvertiser);
8085
8139
  this.modalWrapper = modalWrapper;
8086
8140
  // TODO: Find alternative implementation, which aligns with future page configuration / consumption
8087
8141
  // This implementation was chosen over expanding `moveChild` method in component wrapper with yet another scenario
@@ -8093,8 +8147,8 @@ class PageProgressComponent {
8093
8147
  }
8094
8148
  }
8095
8149
  }
8096
- /** @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 });
8097
- /** @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"] });
8150
+ /** @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 });
8151
+ /** @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"] });
8098
8152
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageProgressComponent, decorators: [{
8099
8153
  type: Component,
8100
8154
  args: [{
@@ -8106,21 +8160,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImpor
8106
8160
  type: Optional
8107
8161
  }, {
8108
8162
  type: SkipSelf
8109
- }] }]; }, propDecorators: { slot: [{
8163
+ }] }, { type: ModalElementsAdvertiser, decorators: [{
8164
+ type: Optional
8165
+ }] }, { type: i0.ElementRef }]; }, propDecorators: { slot: [{
8110
8166
  type: HostBinding,
8111
8167
  args: ['attr.slot']
8112
8168
  }] } });
8113
- class PageTitleComponent {
8169
+ class PageTitleComponent extends ModalElementComponent {
8170
+ constructor(elementRef, modalElementsAdvertiser) {
8171
+ super(ModalElementType.TITLE, elementRef, modalElementsAdvertiser);
8172
+ }
8114
8173
  }
8115
- /** @nocollapse */ PageTitleComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageTitleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8116
- /** @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 });
8174
+ /** @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 });
8175
+ /** @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 });
8117
8176
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageTitleComponent, decorators: [{
8118
8177
  type: Component,
8119
8178
  args: [{
8120
8179
  selector: 'kirby-page-title',
8121
8180
  template: ` <ng-content></ng-content> `,
8122
8181
  }]
8123
- }] });
8182
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ModalElementsAdvertiser, decorators: [{
8183
+ type: Optional
8184
+ }] }]; } });
8124
8185
  class PageContentComponent {
8125
8186
  }
8126
8187
  /** @nocollapse */ PageContentComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: PageContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });