@platform-mesh/portal-ui-lib 0.50.2 → 0.52.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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Injectable, DestroyRef, signal, ViewChild, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent } from '@angular/core';
2
+ import { inject, Injectable, DestroyRef, signal, computed, ViewChild, ChangeDetectionStrategy, Component, ApplicationRef, EnvironmentInjector, createComponent } from '@angular/core';
3
3
  import { I18nService, EntityType, AuthService, LuigiCoreService, ConfigService, EnvConfigService, LocalStorageKeys } from '@openmfp/portal-ui-lib';
4
4
  import '@ui5/webcomponents/dist/Breadcrumbs.js';
5
5
  import '@ui5/webcomponents/dist/BreadcrumbsItem.js';
@@ -529,13 +529,30 @@ function recordValue(value) {
529
529
  return isRecord$1(value) ? value : {};
530
530
  }
531
531
 
532
+ const PORTAL_MAIN_AREA_SELECTOR = '.iframeContainer';
533
+ const PORTAL_LAYOUT_SELECTORS = [
534
+ PORTAL_MAIN_AREA_SELECTOR,
535
+ '.spinnerContainer.appSpinner',
536
+ '#splitViewContainer',
537
+ '#splitViewDragger',
538
+ '#splitViewDraggerBackdrop',
539
+ '#tabsContainer',
540
+ ].join(',');
532
541
  class PersistentPanelComponent {
533
542
  constructor() {
543
+ this.dimensions = panelDimensions();
544
+ this.preferredPanelWidth = signal(this.dimensions.defaultWidth, ...(ngDevMode ? [{ debugName: "preferredPanelWidth" }] : /* istanbul ignore next */ []));
534
545
  this.state = signal('hidden', ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
535
546
  this.title = signal('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
536
547
  this.source = signal(null, ...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
537
548
  this.closing = signal(false, ...(ngDevMode ? [{ debugName: "closing" }] : /* istanbul ignore next */ []));
538
549
  this.closeError = signal('', ...(ngDevMode ? [{ debugName: "closeError" }] : /* istanbul ignore next */ []));
550
+ this.resizing = signal(false, ...(ngDevMode ? [{ debugName: "resizing" }] : /* istanbul ignore next */ []));
551
+ this.maxPanelWidth = signal(this.availablePanelWidth(), ...(ngDevMode ? [{ debugName: "maxPanelWidth" }] : /* istanbul ignore next */ []));
552
+ this.minPanelWidth = computed(() => Math.min(this.dimensions.minimumWidth, this.maxPanelWidth()), ...(ngDevMode ? [{ debugName: "minPanelWidth" }] : /* istanbul ignore next */ []));
553
+ this.panelWidth = computed(() => Math.max(this.minPanelWidth(), Math.min(this.state() === 'maximized'
554
+ ? this.maxPanelWidth()
555
+ : this.preferredPanelWidth(), this.maxPanelWidth())), ...(ngDevMode ? [{ debugName: "panelWidth" }] : /* istanbul ignore next */ []));
539
556
  this.sanitizer = inject(DomSanitizer);
540
557
  this.config = null;
541
558
  this.target = {};
@@ -546,6 +563,30 @@ class PersistentPanelComponent {
546
563
  this.destroyed = false;
547
564
  this.ready = false;
548
565
  this.returnFocusElement = null;
566
+ this.resizePointerId = null;
567
+ this.observingPortalLayout = false;
568
+ this.observedMainArea = null;
569
+ this.portalLayoutStyles = new Map();
570
+ this.portalLayoutObserver = new MutationObserver(() => {
571
+ if (this.state() === 'hidden') {
572
+ return;
573
+ }
574
+ this.maxPanelWidth.set(this.availablePanelWidth());
575
+ this.syncPortalLayout();
576
+ });
577
+ this.mainAreaResizeObserver = typeof ResizeObserver === 'undefined'
578
+ ? null
579
+ : new ResizeObserver(() => {
580
+ if (this.state() === 'hidden') {
581
+ return;
582
+ }
583
+ this.maxPanelWidth.set(this.availablePanelWidth());
584
+ this.syncPortalLayout();
585
+ });
586
+ this.onWindowResize = () => {
587
+ this.maxPanelWidth.set(this.availablePanelWidth());
588
+ this.syncPortalLayout();
589
+ };
549
590
  this.onMessage = (event) => {
550
591
  const frame = this.panelFrame?.nativeElement;
551
592
  if (!frame ||
@@ -577,11 +618,18 @@ class PersistentPanelComponent {
577
618
  }
578
619
  };
579
620
  window.addEventListener('message', this.onMessage);
621
+ window.addEventListener('resize', this.onWindowResize);
580
622
  }
581
623
  ngOnDestroy() {
582
624
  this.destroyed = true;
583
625
  window.removeEventListener('message', this.onMessage);
626
+ window.removeEventListener('resize', this.onWindowResize);
584
627
  this.clearCloseTimeout();
628
+ this.resizePointerId = null;
629
+ this.resizing.set(false);
630
+ this.portalLayoutObserver.disconnect();
631
+ this.mainAreaResizeObserver?.disconnect();
632
+ this.restorePortalLayout();
585
633
  }
586
634
  open(config, target) {
587
635
  if (this.closing()) {
@@ -607,7 +655,9 @@ class PersistentPanelComponent {
607
655
  if (sourceChanged || !this.source()) {
608
656
  this.source.set(this.sanitizer.bypassSecurityTrustResourceUrl(config.url));
609
657
  }
658
+ this.maxPanelWidth.set(this.availablePanelWidth());
610
659
  this.state.set('expanded');
660
+ this.syncPortalLayout();
611
661
  queueMicrotask(() => {
612
662
  if (this.destroyed) {
613
663
  return;
@@ -618,10 +668,13 @@ class PersistentPanelComponent {
618
668
  }
619
669
  updateTarget(target) {
620
670
  this.target = structuredClone(target);
671
+ this.maxPanelWidth.set(this.availablePanelWidth());
672
+ this.syncPortalLayout();
621
673
  this.publishTarget();
622
674
  }
623
675
  collapse() {
624
676
  this.state.set('hidden');
677
+ this.syncPortalLayout();
625
678
  queueMicrotask(() => {
626
679
  if (this.destroyed) {
627
680
  return;
@@ -630,7 +683,9 @@ class PersistentPanelComponent {
630
683
  });
631
684
  }
632
685
  expand() {
686
+ this.maxPanelWidth.set(this.availablePanelWidth());
633
687
  this.state.set('expanded');
688
+ this.syncPortalLayout();
634
689
  queueMicrotask(() => {
635
690
  if (this.destroyed) {
636
691
  return;
@@ -640,6 +695,58 @@ class PersistentPanelComponent {
640
695
  }
641
696
  toggleSize() {
642
697
  this.state.update((state) => state === 'maximized' ? 'expanded' : 'maximized');
698
+ this.syncPortalLayout();
699
+ }
700
+ beginResize(event) {
701
+ if (this.state() !== 'expanded' ||
702
+ event.button !== 0 ||
703
+ event.isPrimary === false) {
704
+ return;
705
+ }
706
+ this.resizePointerId = event.pointerId;
707
+ this.resizing.set(true);
708
+ event.currentTarget.setPointerCapture(event.pointerId);
709
+ event.preventDefault();
710
+ }
711
+ resize(event) {
712
+ if (event.pointerId !== this.resizePointerId) {
713
+ return;
714
+ }
715
+ this.setPanelWidth(window.innerWidth - event.clientX);
716
+ event.preventDefault();
717
+ }
718
+ finishResize(event) {
719
+ if (event.pointerId !== this.resizePointerId) {
720
+ return;
721
+ }
722
+ const handle = event.currentTarget;
723
+ if (handle.hasPointerCapture(event.pointerId)) {
724
+ handle.releasePointerCapture(event.pointerId);
725
+ }
726
+ this.resizePointerId = null;
727
+ this.resizing.set(false);
728
+ event.preventDefault();
729
+ }
730
+ resizeWithKeyboard(event) {
731
+ let width;
732
+ switch (event.key) {
733
+ case 'ArrowLeft':
734
+ width = this.panelWidth() + this.dimensions.keyboardStep;
735
+ break;
736
+ case 'ArrowRight':
737
+ width = this.panelWidth() - this.dimensions.keyboardStep;
738
+ break;
739
+ case 'Home':
740
+ width = this.minPanelWidth();
741
+ break;
742
+ case 'End':
743
+ width = this.maxPanelWidth();
744
+ break;
745
+ default:
746
+ return;
747
+ }
748
+ this.setPanelWidth(width);
749
+ event.preventDefault();
643
750
  }
644
751
  close() {
645
752
  if (!this.source() || this.closing()) {
@@ -651,6 +758,7 @@ class PersistentPanelComponent {
651
758
  this.closing.set(true);
652
759
  this.closeError.set('');
653
760
  this.state.set('hidden');
761
+ this.syncPortalLayout();
654
762
  this.focusReturnTarget();
655
763
  this.requestCloseIfReady(requestId);
656
764
  this.closeTimeout = window.setTimeout(() => {
@@ -665,7 +773,9 @@ class PersistentPanelComponent {
665
773
  this.closeRequestIdSent = null;
666
774
  this.closing.set(false);
667
775
  this.closeError.set('Provider cleanup is incomplete. Try closing again.');
776
+ this.maxPanelWidth.set(this.availablePanelWidth());
668
777
  this.state.set('expanded');
778
+ this.syncPortalLayout();
669
779
  queueMicrotask(() => {
670
780
  if (this.destroyed) {
671
781
  return;
@@ -688,6 +798,7 @@ class PersistentPanelComponent {
688
798
  this.source.set(null);
689
799
  this.title.set('');
690
800
  this.state.set('hidden');
801
+ this.syncPortalLayout();
691
802
  this.focusReturnTarget();
692
803
  this.returnFocusElement = null;
693
804
  }
@@ -698,6 +809,8 @@ class PersistentPanelComponent {
698
809
  }
699
810
  }
700
811
  frameLoaded() {
812
+ this.maxPanelWidth.set(this.availablePanelWidth());
813
+ this.syncPortalLayout();
701
814
  this.publishTarget();
702
815
  }
703
816
  publishTarget() {
@@ -736,12 +849,91 @@ class PersistentPanelComponent {
736
849
  }
737
850
  this.panelFrame?.nativeElement.contentWindow?.postMessage(message, this.config.origin);
738
851
  }
852
+ setPanelWidth(width) {
853
+ this.preferredPanelWidth.set(Math.min(Math.max(width, this.minPanelWidth()), this.maxPanelWidth()));
854
+ this.syncPortalLayout();
855
+ }
856
+ availablePanelWidth() {
857
+ if (this.isMobileViewport()) {
858
+ return Math.max(1, window.innerWidth);
859
+ }
860
+ return Math.max(1, Math.floor(this.availableMainAreaWidth() / 2));
861
+ }
862
+ availableMainAreaWidth() {
863
+ const mainArea = document.querySelector(PORTAL_MAIN_AREA_SELECTOR);
864
+ if (mainArea) {
865
+ return Math.max(1, window.innerWidth - mainArea.getBoundingClientRect().left);
866
+ }
867
+ return Math.max(1, window.innerWidth);
868
+ }
869
+ syncPortalLayout() {
870
+ if (this.state() === 'hidden' || this.isMobileViewport()) {
871
+ this.stopObservingPortalLayout();
872
+ this.restorePortalLayout();
873
+ return;
874
+ }
875
+ this.observePortalLayout();
876
+ const offset = `${this.panelWidth()}px`;
877
+ document
878
+ .querySelectorAll(PORTAL_LAYOUT_SELECTORS)
879
+ .forEach((element) => {
880
+ if (!this.portalLayoutStyles.has(element)) {
881
+ this.portalLayoutStyles.set(element, {
882
+ value: element.style.getPropertyValue('right'),
883
+ priority: element.style.getPropertyPriority('right'),
884
+ });
885
+ }
886
+ element.style.setProperty('right', offset);
887
+ });
888
+ }
889
+ restorePortalLayout() {
890
+ this.portalLayoutStyles.forEach(({ value, priority }, element) => {
891
+ if (value) {
892
+ element.style.setProperty('right', value, priority);
893
+ }
894
+ else {
895
+ element.style.removeProperty('right');
896
+ }
897
+ });
898
+ this.portalLayoutStyles.clear();
899
+ }
900
+ observePortalLayout() {
901
+ this.observeMainAreaResize();
902
+ if (this.observingPortalLayout) {
903
+ return;
904
+ }
905
+ this.portalLayoutObserver.observe(document.body, {
906
+ childList: true,
907
+ subtree: true,
908
+ });
909
+ this.observingPortalLayout = true;
910
+ }
911
+ stopObservingPortalLayout() {
912
+ this.portalLayoutObserver.disconnect();
913
+ this.mainAreaResizeObserver?.disconnect();
914
+ this.observedMainArea = null;
915
+ this.observingPortalLayout = false;
916
+ }
917
+ observeMainAreaResize() {
918
+ const mainArea = document.querySelector(PORTAL_MAIN_AREA_SELECTOR);
919
+ if (!this.mainAreaResizeObserver || mainArea === this.observedMainArea) {
920
+ return;
921
+ }
922
+ this.mainAreaResizeObserver.disconnect();
923
+ this.observedMainArea = mainArea;
924
+ if (mainArea) {
925
+ this.mainAreaResizeObserver.observe(mainArea);
926
+ }
927
+ }
928
+ isMobileViewport() {
929
+ return window.innerWidth <= 600;
930
+ }
739
931
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PersistentPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
740
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PersistentPanelComponent, isStandalone: true, selector: "pm-persistent-panel", viewQueries: [{ propertyName: "panelFrame", first: true, predicate: ["panelFrame"], descendants: true }, { propertyName: "reopenButton", first: true, predicate: ["reopenButton"], descendants: true }], ngImport: i0, template: "<section\n class=\"persistent-panel\"\n role=\"complementary\"\n aria-labelledby=\"persistent-panel-title\"\n [attr.aria-hidden]=\"state() === 'hidden'\"\n [class.maximized]=\"state() === 'maximized'\"\n [class.open]=\"state() !== 'hidden'\"\n>\n <header class=\"persistent-panel-header\">\n <div>\n <h2 id=\"persistent-panel-title\">{{ title() }}</h2>\n @if (closeError()) {\n <p role=\"alert\">{{ closeError() }}</p>\n }\n </div>\n <div class=\"persistent-panel-actions\">\n <button\n aria-label=\"Toggle panel size\"\n [attr.aria-pressed]=\"state() === 'maximized'\"\n title=\"Toggle panel size\"\n type=\"button\"\n (click)=\"toggleSize()\"\n >\n @if (state() === 'maximized') { \u25F2 } @else { \u25F1 }\n </button>\n <button\n aria-label=\"Collapse panel\"\n title=\"Collapse panel\"\n type=\"button\"\n (click)=\"collapse()\"\n >\n \u2014\n </button>\n <button\n aria-label=\"Close panel\"\n title=\"Close panel\"\n type=\"button\"\n (click)=\"close()\"\n >\n \u00D7\n </button>\n </div>\n </header>\n @if (source()) {\n <iframe\n #panelFrame\n class=\"persistent-panel-frame\"\n referrerpolicy=\"no-referrer\"\n sandbox=\"allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts\"\n [src]=\"source()\"\n [title]=\"title()\"\n (load)=\"frameLoaded()\"\n ></iframe>\n }\n</section>\n\n@if (state() === 'hidden' && source() && !closing()) {\n<button\n #reopenButton\n class=\"persistent-panel-reopen\"\n aria-label=\"Open provider panel\"\n type=\"button\"\n (click)=\"expand()\"\n>\n {{ title() }}\n</button>\n}\n", styles: [":host{--pm-panel-header-height: 3rem;font-family:var(--sapFontFamily, \"72\", Arial, sans-serif)}.persistent-panel{position:fixed;top:var(--luigi__shellbar--height, 3.25rem);right:0;bottom:0;z-index:1000;display:none;width:min(34rem,100vw);background:var(--sapBackgroundColor, #fff);border-left:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9);box-shadow:-.25rem 0 1rem #0000001f}.persistent-panel.open{display:grid;grid-template-rows:var(--pm-panel-header-height) 1fr}.persistent-panel.maximized{left:4.25rem;width:auto}.persistent-panel-header{display:flex;align-items:center;justify-content:space-between;padding:0 .75rem 0 1rem;color:var(--sapShell_TextColor, #1d2d3e);background:var(--sapShell_Background, #fff);border-bottom:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9)}.persistent-panel-header h2{overflow:hidden;margin:0;font-size:1rem;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.persistent-panel-header p{margin:0;color:var(--sapNegativeTextColor, #aa0808);font-size:.75rem}.persistent-panel-actions{display:flex;gap:.25rem}.persistent-panel-actions button,.persistent-panel-reopen{min-width:2rem;min-height:2rem;color:var(--sapButton_TextColor, #0064d9);background:transparent;border:0;border-radius:.25rem;cursor:pointer}.persistent-panel-actions button:hover,.persistent-panel-reopen:hover{background:var(--sapButton_Lite_Hover_Background, #eaecee)}.persistent-panel-frame{width:100%;height:100%;border:0}.persistent-panel-reopen{position:fixed;right:1rem;bottom:1rem;z-index:1000;padding:.5rem .75rem;color:var(--sapButton_Emphasized_TextColor, #fff);background:var(--sapButton_Emphasized_Background, #0070f2);box-shadow:0 .25rem .75rem #0003}@media(max-width:600px){.persistent-panel,.persistent-panel.maximized{left:0;width:100vw}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
932
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: PersistentPanelComponent, isStandalone: true, selector: "pm-persistent-panel", viewQueries: [{ propertyName: "panelFrame", first: true, predicate: ["panelFrame"], descendants: true }, { propertyName: "reopenButton", first: true, predicate: ["reopenButton"], descendants: true }], ngImport: i0, template: "<section\n class=\"persistent-panel fd-dialog__content\"\n role=\"complementary\"\n aria-labelledby=\"persistent-panel-title\"\n [attr.aria-hidden]=\"state() === 'hidden'\"\n [class.maximized]=\"state() === 'maximized'\"\n [class.open]=\"state() !== 'hidden'\"\n [class.resizing]=\"resizing()\"\n [style.--pm-panel-width]=\"panelWidth() + 'px'\"\n>\n <div\n class=\"persistent-panel-resizer\"\n role=\"separator\"\n aria-label=\"Resize provider panel\"\n aria-orientation=\"vertical\"\n aria-controls=\"persistent-panel-content\"\n [attr.aria-valuemin]=\"minPanelWidth()\"\n [attr.aria-valuemax]=\"maxPanelWidth()\"\n [attr.aria-valuenow]=\"panelWidth()\"\n tabindex=\"0\"\n (pointerdown)=\"beginResize($event)\"\n (pointermove)=\"resize($event)\"\n (pointerup)=\"finishResize($event)\"\n (pointercancel)=\"finishResize($event)\"\n (lostpointercapture)=\"finishResize($event)\"\n (keydown)=\"resizeWithKeyboard($event)\"\n ></div>\n <header\n class=\"persistent-panel-header fd-dialog__header fd-bar fd-bar--header\"\n >\n <div class=\"fd-bar__left persistent-panel-title-area\">\n <div class=\"fd-bar__element persistent-panel-title-element\">\n <h2\n id=\"persistent-panel-title\"\n class=\"fd-title fd-title--h5 persistent-panel-title\"\n >\n {{ title() }}\n </h2>\n </div>\n </div>\n <div class=\"fd-bar__right persistent-panel-actions\">\n <div class=\"fd-bar__element\">\n <button\n class=\"fd-button fd-button--transparent fd-button--compact\"\n aria-label=\"Toggle panel size\"\n [attr.aria-pressed]=\"state() === 'maximized'\"\n title=\"Toggle panel size\"\n type=\"button\"\n (click)=\"toggleSize()\"\n >\n <i\n class=\"sap-icon\"\n [class.sap-icon--exitfullscreen]=\"state() === 'maximized'\"\n [class.sap-icon--full-screen]=\"state() !== 'maximized'\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n <div class=\"fd-bar__element\">\n <button\n class=\"fd-button fd-button--transparent fd-button--compact\"\n aria-label=\"Collapse panel\"\n title=\"Collapse panel\"\n type=\"button\"\n (click)=\"collapse()\"\n >\n <i class=\"sap-icon sap-icon--collapse\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"fd-bar__element\">\n <button\n class=\"fd-button fd-button--transparent fd-button--compact\"\n aria-label=\"Close panel\"\n title=\"Close panel\"\n type=\"button\"\n (click)=\"close()\"\n >\n <i class=\"sap-icon sap-icon--decline\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n </header>\n <div class=\"persistent-panel-body fd-dialog__body\">\n @if (closeError()) {\n <p class=\"persistent-panel-error\" role=\"alert\">{{ closeError() }}</p>\n } @if (source()) {\n <iframe\n #panelFrame\n id=\"persistent-panel-content\"\n class=\"persistent-panel-frame\"\n referrerpolicy=\"no-referrer\"\n sandbox=\"allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts\"\n [src]=\"source()\"\n [title]=\"title()\"\n (load)=\"frameLoaded()\"\n ></iframe>\n }\n </div>\n</section>\n\n@if (state() === 'hidden' && source() && !closing()) {\n<button\n #reopenButton\n class=\"persistent-panel-reopen fd-button fd-button--emphasized fd-button--compact\"\n [attr.aria-label]=\"'Open ' + title()\"\n type=\"button\"\n (click)=\"expand()\"\n>\n {{ title() }}\n</button>\n}\n", styles: [":host{font-family:var(--sapFontFamily, \"72\", Arial, sans-serif)}.persistent-panel{position:fixed;top:var(--luigi__shellbar--height, 3.25rem);right:0;bottom:0;z-index:1000;display:none;box-sizing:border-box;min-width:0;max-width:none;min-height:0;max-height:none;width:var(--pm-panel-width, min(34rem, 100vw));background:var(--sapGroup_ContentBackground, #fff);border-radius:var(--sapElement_BorderCornerRadius, .75rem) 0 0 var(--sapElement_BorderCornerRadius, .75rem);box-shadow:var(--sapContent_Shadow3, 0 0 0 .0625rem rgba(34, 53, 72, .48), 0 1.25rem 5rem rgba(34, 53, 72, .3))}:host-context(.lui-breadcrumb) .persistent-panel{top:calc(var(--luigi__shellbar--height, 3.25rem) + var(--luigi__breadcrumb--height, 2.75rem))}.persistent-panel.open{display:grid;grid-template-rows:auto minmax(0,1fr)}.persistent-panel-resizer{position:absolute;top:0;bottom:0;left:-.375rem;z-index:1;width:.75rem;cursor:col-resize;touch-action:none}.persistent-panel-resizer:after{position:absolute;top:50%;left:50%;width:.125rem;height:3rem;background:var(--sapContent_FocusColor, #0064d9);border-radius:.125rem;content:\"\";opacity:0;pointer-events:none;transform:translate(-50%,-50%);transition:opacity .12s ease-in-out}.persistent-panel-resizer:hover:after,.persistent-panel-resizer:focus-visible:after,.persistent-panel.resizing .persistent-panel-resizer:after{opacity:1}.persistent-panel-resizer:focus-visible{outline:0}.persistent-panel-resizer:focus-visible:after{outline:var(--sapContent_FocusWidth, .125rem) solid var(--sapContent_FocusColor, #0032a5);outline-offset:.125rem}.persistent-panel.maximized .persistent-panel-resizer{display:none}.persistent-panel-header{min-width:0;border-radius:var(--sapElement_BorderCornerRadius, .75rem) 0 0}.persistent-panel-title-area,.persistent-panel-title-element{min-width:0}.persistent-panel-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.persistent-panel-body{display:flex;min-width:0;min-height:0;flex-direction:column;padding:0;overflow:hidden}.persistent-panel-error{flex:none;margin:0;padding:.5rem 1rem;color:var(--sapNegativeTextColor, #aa0808);background:var(--sapErrorBackground, #ffeaf4);font-size:var(--sapFontSmallSize, .75rem)}.persistent-panel-frame{min-height:0;flex:1;width:100%;border:0;border-bottom-left-radius:var(--sapElement_BorderCornerRadius, .75rem)}.persistent-panel.resizing,.persistent-panel.resizing .persistent-panel-resizer{cursor:col-resize}.persistent-panel.resizing .persistent-panel-frame{pointer-events:none;-webkit-user-select:none;user-select:none}.persistent-panel-reopen{position:fixed;right:1rem;bottom:1rem;z-index:1000;overflow:hidden;max-width:calc(100vw - 2rem);text-overflow:ellipsis;white-space:nowrap}@media(max-width:600px){.persistent-panel,.persistent-panel.maximized{left:0;width:100vw;border-radius:0;box-shadow:none}.persistent-panel-resizer{display:none}.persistent-panel-header,.persistent-panel-body,.persistent-panel-frame{border-radius:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
741
933
  }
742
934
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: PersistentPanelComponent, decorators: [{
743
935
  type: Component,
744
- args: [{ selector: 'pm-persistent-panel', imports: [CommonModule], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n class=\"persistent-panel\"\n role=\"complementary\"\n aria-labelledby=\"persistent-panel-title\"\n [attr.aria-hidden]=\"state() === 'hidden'\"\n [class.maximized]=\"state() === 'maximized'\"\n [class.open]=\"state() !== 'hidden'\"\n>\n <header class=\"persistent-panel-header\">\n <div>\n <h2 id=\"persistent-panel-title\">{{ title() }}</h2>\n @if (closeError()) {\n <p role=\"alert\">{{ closeError() }}</p>\n }\n </div>\n <div class=\"persistent-panel-actions\">\n <button\n aria-label=\"Toggle panel size\"\n [attr.aria-pressed]=\"state() === 'maximized'\"\n title=\"Toggle panel size\"\n type=\"button\"\n (click)=\"toggleSize()\"\n >\n @if (state() === 'maximized') { \u25F2 } @else { \u25F1 }\n </button>\n <button\n aria-label=\"Collapse panel\"\n title=\"Collapse panel\"\n type=\"button\"\n (click)=\"collapse()\"\n >\n \u2014\n </button>\n <button\n aria-label=\"Close panel\"\n title=\"Close panel\"\n type=\"button\"\n (click)=\"close()\"\n >\n \u00D7\n </button>\n </div>\n </header>\n @if (source()) {\n <iframe\n #panelFrame\n class=\"persistent-panel-frame\"\n referrerpolicy=\"no-referrer\"\n sandbox=\"allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts\"\n [src]=\"source()\"\n [title]=\"title()\"\n (load)=\"frameLoaded()\"\n ></iframe>\n }\n</section>\n\n@if (state() === 'hidden' && source() && !closing()) {\n<button\n #reopenButton\n class=\"persistent-panel-reopen\"\n aria-label=\"Open provider panel\"\n type=\"button\"\n (click)=\"expand()\"\n>\n {{ title() }}\n</button>\n}\n", styles: [":host{--pm-panel-header-height: 3rem;font-family:var(--sapFontFamily, \"72\", Arial, sans-serif)}.persistent-panel{position:fixed;top:var(--luigi__shellbar--height, 3.25rem);right:0;bottom:0;z-index:1000;display:none;width:min(34rem,100vw);background:var(--sapBackgroundColor, #fff);border-left:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9);box-shadow:-.25rem 0 1rem #0000001f}.persistent-panel.open{display:grid;grid-template-rows:var(--pm-panel-header-height) 1fr}.persistent-panel.maximized{left:4.25rem;width:auto}.persistent-panel-header{display:flex;align-items:center;justify-content:space-between;padding:0 .75rem 0 1rem;color:var(--sapShell_TextColor, #1d2d3e);background:var(--sapShell_Background, #fff);border-bottom:1px solid var(--sapGroup_ContentBorderColor, #d9d9d9)}.persistent-panel-header h2{overflow:hidden;margin:0;font-size:1rem;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.persistent-panel-header p{margin:0;color:var(--sapNegativeTextColor, #aa0808);font-size:.75rem}.persistent-panel-actions{display:flex;gap:.25rem}.persistent-panel-actions button,.persistent-panel-reopen{min-width:2rem;min-height:2rem;color:var(--sapButton_TextColor, #0064d9);background:transparent;border:0;border-radius:.25rem;cursor:pointer}.persistent-panel-actions button:hover,.persistent-panel-reopen:hover{background:var(--sapButton_Lite_Hover_Background, #eaecee)}.persistent-panel-frame{width:100%;height:100%;border:0}.persistent-panel-reopen{position:fixed;right:1rem;bottom:1rem;z-index:1000;padding:.5rem .75rem;color:var(--sapButton_Emphasized_TextColor, #fff);background:var(--sapButton_Emphasized_Background, #0070f2);box-shadow:0 .25rem .75rem #0003}@media(max-width:600px){.persistent-panel,.persistent-panel.maximized{left:0;width:100vw}}\n"] }]
936
+ args: [{ selector: 'pm-persistent-panel', imports: [CommonModule], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n class=\"persistent-panel fd-dialog__content\"\n role=\"complementary\"\n aria-labelledby=\"persistent-panel-title\"\n [attr.aria-hidden]=\"state() === 'hidden'\"\n [class.maximized]=\"state() === 'maximized'\"\n [class.open]=\"state() !== 'hidden'\"\n [class.resizing]=\"resizing()\"\n [style.--pm-panel-width]=\"panelWidth() + 'px'\"\n>\n <div\n class=\"persistent-panel-resizer\"\n role=\"separator\"\n aria-label=\"Resize provider panel\"\n aria-orientation=\"vertical\"\n aria-controls=\"persistent-panel-content\"\n [attr.aria-valuemin]=\"minPanelWidth()\"\n [attr.aria-valuemax]=\"maxPanelWidth()\"\n [attr.aria-valuenow]=\"panelWidth()\"\n tabindex=\"0\"\n (pointerdown)=\"beginResize($event)\"\n (pointermove)=\"resize($event)\"\n (pointerup)=\"finishResize($event)\"\n (pointercancel)=\"finishResize($event)\"\n (lostpointercapture)=\"finishResize($event)\"\n (keydown)=\"resizeWithKeyboard($event)\"\n ></div>\n <header\n class=\"persistent-panel-header fd-dialog__header fd-bar fd-bar--header\"\n >\n <div class=\"fd-bar__left persistent-panel-title-area\">\n <div class=\"fd-bar__element persistent-panel-title-element\">\n <h2\n id=\"persistent-panel-title\"\n class=\"fd-title fd-title--h5 persistent-panel-title\"\n >\n {{ title() }}\n </h2>\n </div>\n </div>\n <div class=\"fd-bar__right persistent-panel-actions\">\n <div class=\"fd-bar__element\">\n <button\n class=\"fd-button fd-button--transparent fd-button--compact\"\n aria-label=\"Toggle panel size\"\n [attr.aria-pressed]=\"state() === 'maximized'\"\n title=\"Toggle panel size\"\n type=\"button\"\n (click)=\"toggleSize()\"\n >\n <i\n class=\"sap-icon\"\n [class.sap-icon--exitfullscreen]=\"state() === 'maximized'\"\n [class.sap-icon--full-screen]=\"state() !== 'maximized'\"\n aria-hidden=\"true\"\n ></i>\n </button>\n </div>\n <div class=\"fd-bar__element\">\n <button\n class=\"fd-button fd-button--transparent fd-button--compact\"\n aria-label=\"Collapse panel\"\n title=\"Collapse panel\"\n type=\"button\"\n (click)=\"collapse()\"\n >\n <i class=\"sap-icon sap-icon--collapse\" aria-hidden=\"true\"></i>\n </button>\n </div>\n <div class=\"fd-bar__element\">\n <button\n class=\"fd-button fd-button--transparent fd-button--compact\"\n aria-label=\"Close panel\"\n title=\"Close panel\"\n type=\"button\"\n (click)=\"close()\"\n >\n <i class=\"sap-icon sap-icon--decline\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n </header>\n <div class=\"persistent-panel-body fd-dialog__body\">\n @if (closeError()) {\n <p class=\"persistent-panel-error\" role=\"alert\">{{ closeError() }}</p>\n } @if (source()) {\n <iframe\n #panelFrame\n id=\"persistent-panel-content\"\n class=\"persistent-panel-frame\"\n referrerpolicy=\"no-referrer\"\n sandbox=\"allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts\"\n [src]=\"source()\"\n [title]=\"title()\"\n (load)=\"frameLoaded()\"\n ></iframe>\n }\n </div>\n</section>\n\n@if (state() === 'hidden' && source() && !closing()) {\n<button\n #reopenButton\n class=\"persistent-panel-reopen fd-button fd-button--emphasized fd-button--compact\"\n [attr.aria-label]=\"'Open ' + title()\"\n type=\"button\"\n (click)=\"expand()\"\n>\n {{ title() }}\n</button>\n}\n", styles: [":host{font-family:var(--sapFontFamily, \"72\", Arial, sans-serif)}.persistent-panel{position:fixed;top:var(--luigi__shellbar--height, 3.25rem);right:0;bottom:0;z-index:1000;display:none;box-sizing:border-box;min-width:0;max-width:none;min-height:0;max-height:none;width:var(--pm-panel-width, min(34rem, 100vw));background:var(--sapGroup_ContentBackground, #fff);border-radius:var(--sapElement_BorderCornerRadius, .75rem) 0 0 var(--sapElement_BorderCornerRadius, .75rem);box-shadow:var(--sapContent_Shadow3, 0 0 0 .0625rem rgba(34, 53, 72, .48), 0 1.25rem 5rem rgba(34, 53, 72, .3))}:host-context(.lui-breadcrumb) .persistent-panel{top:calc(var(--luigi__shellbar--height, 3.25rem) + var(--luigi__breadcrumb--height, 2.75rem))}.persistent-panel.open{display:grid;grid-template-rows:auto minmax(0,1fr)}.persistent-panel-resizer{position:absolute;top:0;bottom:0;left:-.375rem;z-index:1;width:.75rem;cursor:col-resize;touch-action:none}.persistent-panel-resizer:after{position:absolute;top:50%;left:50%;width:.125rem;height:3rem;background:var(--sapContent_FocusColor, #0064d9);border-radius:.125rem;content:\"\";opacity:0;pointer-events:none;transform:translate(-50%,-50%);transition:opacity .12s ease-in-out}.persistent-panel-resizer:hover:after,.persistent-panel-resizer:focus-visible:after,.persistent-panel.resizing .persistent-panel-resizer:after{opacity:1}.persistent-panel-resizer:focus-visible{outline:0}.persistent-panel-resizer:focus-visible:after{outline:var(--sapContent_FocusWidth, .125rem) solid var(--sapContent_FocusColor, #0032a5);outline-offset:.125rem}.persistent-panel.maximized .persistent-panel-resizer{display:none}.persistent-panel-header{min-width:0;border-radius:var(--sapElement_BorderCornerRadius, .75rem) 0 0}.persistent-panel-title-area,.persistent-panel-title-element{min-width:0}.persistent-panel-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.persistent-panel-body{display:flex;min-width:0;min-height:0;flex-direction:column;padding:0;overflow:hidden}.persistent-panel-error{flex:none;margin:0;padding:.5rem 1rem;color:var(--sapNegativeTextColor, #aa0808);background:var(--sapErrorBackground, #ffeaf4);font-size:var(--sapFontSmallSize, .75rem)}.persistent-panel-frame{min-height:0;flex:1;width:100%;border:0;border-bottom-left-radius:var(--sapElement_BorderCornerRadius, .75rem)}.persistent-panel.resizing,.persistent-panel.resizing .persistent-panel-resizer{cursor:col-resize}.persistent-panel.resizing .persistent-panel-frame{pointer-events:none;-webkit-user-select:none;user-select:none}.persistent-panel-reopen{position:fixed;right:1rem;bottom:1rem;z-index:1000;overflow:hidden;max-width:calc(100vw - 2rem);text-overflow:ellipsis;white-space:nowrap}@media(max-width:600px){.persistent-panel,.persistent-panel.maximized{left:0;width:100vw;border-radius:0;box-shadow:none}.persistent-panel-resizer{display:none}.persistent-panel-header,.persistent-panel-body,.persistent-panel-frame{border-radius:0}}\n"] }]
745
937
  }], ctorParameters: () => [], propDecorators: { panelFrame: [{
746
938
  type: ViewChild,
747
939
  args: ['panelFrame']
@@ -752,6 +944,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
752
944
  function isRecord(value) {
753
945
  return typeof value === 'object' && value !== null && !Array.isArray(value);
754
946
  }
947
+ function panelDimensions() {
948
+ const rootFontSize = Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize);
949
+ const rem = Number.isFinite(rootFontSize) && rootFontSize > 0 ? rootFontSize : 16;
950
+ return {
951
+ defaultWidth: 34 * rem,
952
+ minimumWidth: 20 * rem,
953
+ keyboardStep: 2 * rem,
954
+ };
955
+ }
755
956
 
756
957
  class PersistentPanelService {
757
958
  constructor() {