@ship-ui/core 0.15.16 → 0.15.18

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.
@@ -1016,6 +1016,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImpor
1016
1016
  args: ['window:resize', ['$event']]
1017
1017
  }] } });
1018
1018
 
1019
+ const BASE_SPACE = 4;
1019
1020
  const SCROLLABLE_STYLES = ['scroll', 'auto'];
1020
1021
  const DEFAULT_OPTIONS = {
1021
1022
  width: undefined,
@@ -1026,7 +1027,6 @@ const DEFAULT_OPTIONS = {
1026
1027
  class ShipPopoverComponent {
1027
1028
  constructor() {
1028
1029
  this.#document = inject(DOCUMENT);
1029
- this.#BASE_SPACE = 4;
1030
1030
  this.SUPPORTS_ANCHOR = typeof CSS !== 'undefined' && CSS.supports('position-anchor', '--abc') && CSS.supports('anchor-name', '--abc');
1031
1031
  this.asMultiLayer = input(false, ...(ngDevMode ? [{ debugName: "asMultiLayer" }] : []));
1032
1032
  this.disableOpenByClick = input(false, ...(ngDevMode ? [{ debugName: "disableOpenByClick" }] : []));
@@ -1039,6 +1039,7 @@ class ShipPopoverComponent {
1039
1039
  }), ...(ngDevMode ? [{ debugName: "defaultOptionMerge" }] : []));
1040
1040
  this.triggerRef = viewChild.required('triggerRef');
1041
1041
  this.popoverRef = viewChild('popoverRef', ...(ngDevMode ? [{ debugName: "popoverRef" }] : []));
1042
+ this.popoverContentRef = viewChild('popoverContentRef', ...(ngDevMode ? [{ debugName: "popoverContentRef" }] : []));
1042
1043
  this.id = signal('--' + generateUniqueId(), ...(ngDevMode ? [{ debugName: "id" }] : []));
1043
1044
  this.menuStyle = signal(null, ...(ngDevMode ? [{ debugName: "menuStyle" }] : []));
1044
1045
  this.openAbort = null;
@@ -1046,16 +1047,16 @@ class ShipPopoverComponent {
1046
1047
  const open = this.isOpen();
1047
1048
  queueMicrotask(() => {
1048
1049
  const popoverEl = this.popoverRef()?.nativeElement;
1049
- if (!popoverEl)
1050
+ if (!popoverEl) {
1051
+ this.openAbort?.abort();
1052
+ this.openAbort = null;
1050
1053
  return;
1054
+ }
1051
1055
  if (open) {
1052
1056
  if (this.openAbort) {
1053
1057
  this.openAbort.abort();
1054
1058
  }
1055
1059
  this.openAbort = new AbortController();
1056
- const abortOptions = {
1057
- signal: this.openAbort?.signal,
1058
- };
1059
1060
  this.#document.addEventListener('keydown', (e) => {
1060
1061
  if (e.key === 'Escape' && !this.defaultOptionMerge().closeOnEsc) {
1061
1062
  e.preventDefault();
@@ -1063,13 +1064,19 @@ class ShipPopoverComponent {
1063
1064
  if (e.key === 'Escape' && this.defaultOptionMerge().closeOnEsc) {
1064
1065
  this.isOpen.set(false);
1065
1066
  }
1066
- }, abortOptions);
1067
+ }, {
1068
+ signal: this.openAbort?.signal,
1069
+ });
1067
1070
  popoverEl.showPopover();
1068
1071
  if (!this.SUPPORTS_ANCHOR) {
1069
1072
  setTimeout(() => {
1070
1073
  const scrollableParent = this.#findScrollableParent(popoverEl);
1071
- scrollableParent.addEventListener('scroll', () => this.#calculateMenuPosition(), abortOptions);
1072
- window?.addEventListener('resize', () => this.#calculateMenuPosition(), abortOptions);
1074
+ scrollableParent.addEventListener('scroll', () => this.#calculateMenuPosition(), {
1075
+ signal: this.openAbort?.signal,
1076
+ });
1077
+ window?.addEventListener('resize', () => this.#calculateMenuPosition(), {
1078
+ signal: this.openAbort?.signal,
1079
+ });
1073
1080
  this.#calculateMenuPosition();
1074
1081
  });
1075
1082
  }
@@ -1083,7 +1090,6 @@ class ShipPopoverComponent {
1083
1090
  }, ...(ngDevMode ? [{ debugName: "openEffect" }] : []));
1084
1091
  }
1085
1092
  #document;
1086
- #BASE_SPACE;
1087
1093
  toggleIsOpen(event) {
1088
1094
  if (!this.disableOpenByClick()) {
1089
1095
  event.preventDefault();
@@ -1107,45 +1113,68 @@ class ShipPopoverComponent {
1107
1113
  }
1108
1114
  return this.#document.documentElement;
1109
1115
  }
1116
+ #alignLeftUnder(triggerRect, menuRect) {
1117
+ const newLeft = triggerRect.left;
1118
+ const newTop = triggerRect.bottom + BASE_SPACE;
1119
+ return {
1120
+ left: newLeft,
1121
+ top: newTop,
1122
+ };
1123
+ }
1124
+ #alignTopRight(triggerRect, menuRect) {
1125
+ const newLeft = triggerRect.right + BASE_SPACE;
1126
+ const newTop = triggerRect.top;
1127
+ return {
1128
+ left: newLeft,
1129
+ top: newTop,
1130
+ };
1131
+ }
1132
+ #alignBottomRight(triggerRect, menuRect) {
1133
+ const newLeft = triggerRect.right + BASE_SPACE;
1134
+ const newTop = triggerRect.bottom;
1135
+ return {
1136
+ left: newLeft,
1137
+ top: newTop,
1138
+ };
1139
+ }
1140
+ #alignLeftOver(triggerRect, menuRect) {
1141
+ const newLeft = triggerRect.left;
1142
+ const newTop = triggerRect.bottom - triggerRect.height - menuRect.height - BASE_SPACE;
1143
+ return {
1144
+ left: newLeft,
1145
+ top: newTop,
1146
+ };
1147
+ }
1110
1148
  #calculateMenuPosition() {
1111
1149
  const triggerRect = this.triggerRef()?.nativeElement.getBoundingClientRect();
1112
- const menuRect = this.popoverRef()?.nativeElement.getBoundingClientRect();
1113
- if (!menuRect)
1114
- return;
1115
- const actionLeftInViewport = triggerRect.left;
1116
- const actionBottomInViewport = triggerRect.bottom;
1117
- let newLeft = actionLeftInViewport;
1118
- let newTop = actionBottomInViewport + this.#BASE_SPACE;
1119
- const outOfBoundsRight = newLeft + menuRect.width > window?.innerWidth;
1120
- const outOfBoundsBottom = newTop + menuRect.height > window?.innerHeight;
1121
- if (!this.SUPPORTS_ANCHOR) {
1122
- newLeft = actionLeftInViewport;
1123
- newTop = actionBottomInViewport + this.#BASE_SPACE;
1124
- if (outOfBoundsBottom) {
1125
- const _newTop = triggerRect.top - menuRect.height - this.#BASE_SPACE;
1126
- const outOfBoundsTop = _newTop < 0;
1127
- if (!outOfBoundsTop)
1128
- newTop = _newTop;
1129
- }
1130
- if (outOfBoundsRight) {
1131
- newLeft = triggerRect.right - menuRect.width;
1132
- if (newLeft < 0) {
1133
- newLeft = 0;
1134
- }
1150
+ const menuRect = this.popoverContentRef()?.nativeElement.getBoundingClientRect();
1151
+ const tryOrderMultiLayer = [this.#alignTopRight, this.#alignBottomRight];
1152
+ const tryOrderDefault = [this.#alignLeftUnder, this.#alignLeftOver];
1153
+ const tryOrder = this.asMultiLayer() ? tryOrderMultiLayer : tryOrderDefault;
1154
+ for (let i = 0; i < tryOrder.length; i++) {
1155
+ const position = tryOrder[i](triggerRect, menuRect);
1156
+ const outOfBoundsRight = position.left + (menuRect?.width || 0) > window.innerWidth;
1157
+ const outOfBoundsBottom = position.top + (menuRect?.height || 0) > window.innerHeight;
1158
+ if (!outOfBoundsRight && !outOfBoundsBottom) {
1159
+ this.menuStyle.set({
1160
+ left: position.left + 'px',
1161
+ top: position.top + 'px',
1162
+ });
1163
+ return;
1135
1164
  }
1136
- const style = {
1137
- left: newLeft + 'px',
1138
- top: newTop + 'px',
1139
- };
1140
- this.menuStyle.set(style);
1141
1165
  }
1166
+ const fallbackPosition = tryOrder[0](triggerRect, menuRect);
1167
+ this.menuStyle.set({
1168
+ left: fallbackPosition.left + 'px',
1169
+ top: fallbackPosition.top + 'px',
1170
+ });
1142
1171
  }
1143
1172
  ngOnDestroy() {
1144
1173
  this.openAbort?.abort();
1145
1174
  this.openAbort = null;
1146
1175
  }
1147
1176
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: ShipPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1148
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: ShipPopoverComponent, isStandalone: true, selector: "sh-popover", inputs: { asMultiLayer: { classPropertyName: "asMultiLayer", publicName: "asMultiLayer", isSignal: true, isRequired: false, transformFunction: null }, disableOpenByClick: { classPropertyName: "disableOpenByClick", publicName: "disableOpenByClick", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", closed: "closed" }, host: { properties: { "class.multi-layer": "asMultiLayer()" } }, viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerRef"], descendants: true, isSignal: true }, { propertyName: "popoverRef", first: true, predicate: ["popoverRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
1177
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: ShipPopoverComponent, isStandalone: true, selector: "sh-popover", inputs: { asMultiLayer: { classPropertyName: "asMultiLayer", publicName: "asMultiLayer", isSignal: true, isRequired: false, transformFunction: null }, disableOpenByClick: { classPropertyName: "disableOpenByClick", publicName: "disableOpenByClick", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", closed: "closed" }, host: { properties: { "class.multi-layer": "asMultiLayer()" } }, viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerRef"], descendants: true, isSignal: true }, { propertyName: "popoverRef", first: true, predicate: ["popoverRef"], descendants: true, isSignal: true }, { propertyName: "popoverContentRef", first: true, predicate: ["popoverContentRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
1149
1178
  <div class="trigger" #triggerRef [attr.popovertarget]="id() + 'hello'" (click)="toggleIsOpen($event)">
1150
1179
  <div class="trigger-wrapper">
1151
1180
  <ng-content select="[trigger]" />
@@ -1158,7 +1187,7 @@ class ShipPopoverComponent {
1158
1187
  @if (isOpen()) {
1159
1188
  <div [attr.id]="id() + 'hello'" popover="manual" #popoverRef class="popover">
1160
1189
  <div class="overlay" (click)="eventClose($event)"></div>
1161
- <div class="popover-content" [style.position-anchor]="id()" [style]="menuStyle()">
1190
+ <div class="popover-content" #popoverContentRef [style.position-anchor]="id()" [style]="menuStyle()">
1162
1191
  <ng-content />
1163
1192
  </div>
1164
1193
  </div>
@@ -1183,7 +1212,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImpor
1183
1212
  @if (isOpen()) {
1184
1213
  <div [attr.id]="id() + 'hello'" popover="manual" #popoverRef class="popover">
1185
1214
  <div class="overlay" (click)="eventClose($event)"></div>
1186
- <div class="popover-content" [style.position-anchor]="id()" [style]="menuStyle()">
1215
+ <div class="popover-content" #popoverContentRef [style.position-anchor]="id()" [style]="menuStyle()">
1187
1216
  <ng-content />
1188
1217
  </div>
1189
1218
  </div>