@ship-ui/core 0.17.12 → 0.17.15

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.
@@ -1061,6 +1061,12 @@
1061
1061
  ],
1062
1062
  "outputs": [],
1063
1063
  "methods": [
1064
+ {
1065
+ "name": "cancelAnimationFrame",
1066
+ "parameters": "this.rafId);\n }\n this.rafId = requestAnimationFrame(this.calculateTooltipPosition);\n };\n\n private calculateTooltipPosition = (",
1067
+ "returnType": "void =>",
1068
+ "description": ""
1069
+ },
1064
1070
  {
1065
1071
  "name": "untracked",
1066
1072
  "parameters": "() => {\n if (this.isOpen() && openRef?.component === this && openRef?.wrapperComponentRef",
@@ -3201,12 +3207,24 @@
3201
3207
  }
3202
3208
  ],
3203
3209
  "methods": [
3210
+ {
3211
+ "name": "onCleanup",
3212
+ "parameters": "() => {\n const index = ShipMenu.openMenus.indexOf(this);\n if (index > -1",
3213
+ "returnType": "any",
3214
+ "description": ""
3215
+ },
3204
3216
  {
3205
3217
  "name": "toggleIsOpen",
3206
3218
  "parameters": "event: MouseEvent",
3207
3219
  "returnType": "any",
3208
3220
  "description": ""
3209
3221
  },
3222
+ {
3223
+ "name": "open",
3224
+ "parameters": "",
3225
+ "returnType": "any",
3226
+ "description": ""
3227
+ },
3210
3228
  {
3211
3229
  "name": "nextActiveIndex",
3212
3230
  "parameters": "activeIndex: number",
@@ -2663,6 +2663,8 @@ class ShipPopover {
2663
2663
  }, {
2664
2664
  signal: this.openAbort?.signal,
2665
2665
  });
2666
+ if (!popoverEl.isConnected)
2667
+ return;
2666
2668
  popoverEl.showPopover();
2667
2669
  if (!this.SUPPORTS_ANCHOR) {
2668
2670
  setTimeout(() => {
@@ -3840,9 +3842,22 @@ class ShipMenu {
3840
3842
  this.activeOptionIndex = signal(-1, ...(ngDevMode ? [{ debugName: "activeOptionIndex" }] : []));
3841
3843
  this.inputRef = viewChild('inputRef', ...(ngDevMode ? [{ debugName: "inputRef" }] : []));
3842
3844
  this.optionsRef = viewChild('optionsRef', ...(ngDevMode ? [{ debugName: "optionsRef" }] : []));
3845
+ this.openMenusEffect = effect((onCleanup) => {
3846
+ if (this.isOpen()) {
3847
+ ShipMenu.openMenus.push(this);
3848
+ }
3849
+ onCleanup(() => {
3850
+ const index = ShipMenu.openMenus.indexOf(this);
3851
+ if (index > -1) {
3852
+ ShipMenu.openMenus.splice(index, 1);
3853
+ }
3854
+ });
3855
+ }, ...(ngDevMode ? [{ debugName: "openMenusEffect" }] : []));
3843
3856
  this.options = observeChildren(this.optionsRef, this.customOptionElementSelectors);
3844
3857
  this.optionsEl = computed(() => this.options.signal().filter((x) => !x.disabled), ...(ngDevMode ? [{ debugName: "optionsEl" }] : []));
3845
3858
  this.inputValue = createFormInputSignal(this.inputRef);
3859
+ this.optionsId = generateUniqueId();
3860
+ this.activeOptionId = signal(undefined, ...(ngDevMode ? [{ debugName: "activeOptionId" }] : []));
3846
3861
  this.abortController = null;
3847
3862
  this.optionsEffect = effect(() => {
3848
3863
  if (this.abortController !== null) {
@@ -3884,6 +3899,9 @@ class ShipMenu {
3884
3899
  }
3885
3900
  }, ...(ngDevMode ? [{ debugName: "optionsEffect" }] : []));
3886
3901
  this.keyDownEventListener = (e) => {
3902
+ // Only handle events if this is the most recently opened menu
3903
+ if (ShipMenu.openMenus.at(-1) !== this)
3904
+ return;
3887
3905
  const activeOptionIndex = this.activeOptionIndex();
3888
3906
  if (e.key === 'ArrowDown') {
3889
3907
  e.preventDefault();
@@ -3896,8 +3914,20 @@ class ShipMenu {
3896
3914
  else if (e.key === 'Enter') {
3897
3915
  e.preventDefault();
3898
3916
  if (activeOptionIndex > -1) {
3899
- this.activeElements()[activeOptionIndex].click();
3900
- queueMicrotask(() => this.close('active'));
3917
+ const el = this.activeElements()[activeOptionIndex];
3918
+ const parent = el.parentElement;
3919
+ // For nested menu's
3920
+ if (parent?.hasAttribute('trigger')) {
3921
+ const event = new CustomEvent('ship-menu-open', {
3922
+ bubbles: true,
3923
+ cancelable: true,
3924
+ });
3925
+ el.dispatchEvent(event);
3926
+ }
3927
+ else {
3928
+ el.click();
3929
+ queueMicrotask(() => this.close('active'));
3930
+ }
3901
3931
  }
3902
3932
  }
3903
3933
  else if (e.key === 'Tab') {
@@ -3920,6 +3950,10 @@ class ShipMenu {
3920
3950
  this._lastElementList = allOptions;
3921
3951
  for (let i = 0; i < allOptions.length; i++) {
3922
3952
  this.#renderer.removeStyle(allOptions[i], 'order');
3953
+ if (!allOptions[i].id) {
3954
+ allOptions[i].id = `${this.optionsId}-option-${i}`;
3955
+ }
3956
+ allOptions[i].setAttribute('role', 'option');
3923
3957
  }
3924
3958
  return;
3925
3959
  }
@@ -3943,31 +3977,61 @@ class ShipMenu {
3943
3977
  }
3944
3978
  this.activeElements.set(optionElements);
3945
3979
  this._lastElementList = optionElements;
3980
+ // Assign IDs to options for ARIA support
3981
+ for (let i = 0; i < optionElements.length; i++) {
3982
+ if (!optionElements[i].id) {
3983
+ optionElements[i].id = `${this.optionsId}-option-${i}`;
3984
+ }
3985
+ optionElements[i].setAttribute('role', 'option');
3986
+ }
3946
3987
  }, ...(ngDevMode ? [{ debugName: "inputValueEffect" }] : []));
3947
3988
  this.activeOptionIndexEffect = effect(() => {
3948
3989
  const optionElements = this.activeElements();
3949
3990
  const activeOptionIndex = this.activeOptionIndex();
3950
3991
  for (let index = 0; index < optionElements.length; index++) {
3951
3992
  optionElements[index].classList.remove('active');
3993
+ optionElements[index].removeAttribute('aria-selected');
3952
3994
  }
3953
3995
  if (activeOptionIndex > -1) {
3954
- optionElements[activeOptionIndex].scrollIntoView({ block: 'center' });
3955
- optionElements[activeOptionIndex].classList.add('active');
3996
+ const activeOption = optionElements[activeOptionIndex];
3997
+ activeOption.scrollIntoView({ block: 'center' });
3998
+ activeOption.classList.add('active');
3999
+ activeOption.setAttribute('aria-selected', 'true');
4000
+ this.activeOptionId.set(activeOption.id);
4001
+ }
4002
+ else {
4003
+ this.activeOptionId.set(undefined);
3956
4004
  }
3957
4005
  }, ...(ngDevMode ? [{ debugName: "activeOptionIndexEffect" }] : []));
3958
4006
  }
3959
4007
  #document;
3960
4008
  #renderer;
4009
+ static { this.openMenus = []; }
3961
4010
  toggleIsOpen(event) {
3962
4011
  event.preventDefault();
3963
4012
  event.stopPropagation();
3964
4013
  if (this.disabled())
3965
4014
  return;
3966
- this.isOpen.set(!this.isOpen());
3967
- if (this.searchable() && this.isOpen()) {
4015
+ if (this.isOpen()) {
4016
+ this.close('fromPopover');
4017
+ }
4018
+ else {
4019
+ this.open();
4020
+ }
4021
+ }
4022
+ open() {
4023
+ if (this.disabled())
4024
+ return;
4025
+ this.isOpen.set(true);
4026
+ if (this.searchable()) {
3968
4027
  setTimeout(() => this.inputRef()?.nativeElement.focus());
3969
4028
  }
3970
4029
  }
4030
+ onShipMenuOpen(event) {
4031
+ event.preventDefault();
4032
+ event.stopPropagation();
4033
+ this.open();
4034
+ }
3971
4035
  #calculateMatchScore(option, input) {
3972
4036
  if (!input)
3973
4037
  return 0;
@@ -4052,6 +4116,7 @@ class ShipMenu {
4052
4116
  const optionElements = this.optionsEl();
4053
4117
  for (let index = 0; index < optionElements.length; index++) {
4054
4118
  optionElements[index].classList.remove('active');
4119
+ optionElements[index].removeAttribute('aria-selected');
4055
4120
  }
4056
4121
  }
4057
4122
  ngOnDestroy() {
@@ -4059,9 +4124,13 @@ class ShipMenu {
4059
4124
  this.abortController.abort();
4060
4125
  this.abortController = null;
4061
4126
  }
4127
+ const index = ShipMenu.openMenus.indexOf(this);
4128
+ if (index > -1) {
4129
+ ShipMenu.openMenus.splice(index, 1);
4130
+ }
4062
4131
  }
4063
4132
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: ShipMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4064
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: ShipMenu, isStandalone: true, selector: "sh-menu", inputs: { asMultiLayer: { classPropertyName: "asMultiLayer", publicName: "asMultiLayer", isSignal: true, isRequired: false, transformFunction: null }, openIndicator: { classPropertyName: "openIndicator", publicName: "openIndicator", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, customOptionElementSelectors: { classPropertyName: "customOptionElementSelectors", publicName: "customOptionElementSelectors", isSignal: true, isRequired: false, transformFunction: null }, keepClickedOptionActive: { classPropertyName: "keepClickedOptionActive", publicName: "keepClickedOptionActive", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", closed: "closed" }, host: { properties: { "class.disabled": "disabled()", "class.has-search": "searchable()", "class.multi-layer": "asMultiLayer()" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }, { propertyName: "optionsRef", first: true, predicate: ["optionsRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
4133
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: ShipMenu, isStandalone: true, selector: "sh-menu", inputs: { asMultiLayer: { classPropertyName: "asMultiLayer", publicName: "asMultiLayer", isSignal: true, isRequired: false, transformFunction: null }, openIndicator: { classPropertyName: "openIndicator", publicName: "openIndicator", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, customOptionElementSelectors: { classPropertyName: "customOptionElementSelectors", publicName: "customOptionElementSelectors", isSignal: true, isRequired: false, transformFunction: null }, keepClickedOptionActive: { classPropertyName: "keepClickedOptionActive", publicName: "keepClickedOptionActive", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpenChange", closed: "closed" }, host: { listeners: { "ship-menu-open": "onShipMenuOpen($event)" }, properties: { "class.disabled": "disabled()", "class.has-search": "searchable()", "class.multi-layer": "asMultiLayer()" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }, { propertyName: "optionsRef", first: true, predicate: ["optionsRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
4065
4134
  <sh-popover
4066
4135
  #formFieldWrapper
4067
4136
  [(isOpen)]="isOpen"
@@ -4072,7 +4141,15 @@ class ShipMenu {
4072
4141
  closeOnButton: false,
4073
4142
  closeOnEsc: true,
4074
4143
  }">
4075
- <div trigger [class.is-open]="isOpen()" (click)="toggleIsOpen($event)">
4144
+ <div
4145
+ trigger
4146
+ [class.is-open]="isOpen()"
4147
+ (click)="toggleIsOpen($event)"
4148
+ role="combobox"
4149
+ [attr.aria-expanded]="isOpen()"
4150
+ aria-haspopup="listbox"
4151
+ [attr.aria-controls]="optionsId"
4152
+ [attr.aria-activedescendant]="activeOptionId()">
4076
4153
  <ng-content />
4077
4154
 
4078
4155
  @if (openIndicator()) {
@@ -4082,7 +4159,15 @@ class ShipMenu {
4082
4159
 
4083
4160
  <div class="form-field-wrap">
4084
4161
  <sh-form-field class="small stretch" [class.hidden]="searchable() === false">
4085
- <input type="text" #inputRef placeholder="Search" />
4162
+ <input
4163
+ type="text"
4164
+ #inputRef
4165
+ placeholder="Search"
4166
+ role="combobox"
4167
+ [attr.aria-expanded]="isOpen()"
4168
+ [attr.aria-controls]="optionsId"
4169
+ [attr.aria-activedescendant]="activeOptionId()"
4170
+ aria-autocomplete="list" />
4086
4171
  </sh-form-field>
4087
4172
  </div>
4088
4173
 
@@ -4090,7 +4175,10 @@ class ShipMenu {
4090
4175
  class="options"
4091
4176
  #optionsRef
4092
4177
  (click)="close('active')"
4093
- [class.searching]="searchable() && inputValue() !== ''">
4178
+ [class.searching]="searchable() && inputValue() !== ''"
4179
+ role="listbox"
4180
+ [id]="optionsId"
4181
+ [attr.aria-activedescendant]="activeOptionId()">
4094
4182
  <ng-content select="[menu]" />
4095
4183
  </div>
4096
4184
  </sh-popover>
@@ -4112,7 +4200,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
4112
4200
  closeOnButton: false,
4113
4201
  closeOnEsc: true,
4114
4202
  }">
4115
- <div trigger [class.is-open]="isOpen()" (click)="toggleIsOpen($event)">
4203
+ <div
4204
+ trigger
4205
+ [class.is-open]="isOpen()"
4206
+ (click)="toggleIsOpen($event)"
4207
+ role="combobox"
4208
+ [attr.aria-expanded]="isOpen()"
4209
+ aria-haspopup="listbox"
4210
+ [attr.aria-controls]="optionsId"
4211
+ [attr.aria-activedescendant]="activeOptionId()">
4116
4212
  <ng-content />
4117
4213
 
4118
4214
  @if (openIndicator()) {
@@ -4122,7 +4218,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
4122
4218
 
4123
4219
  <div class="form-field-wrap">
4124
4220
  <sh-form-field class="small stretch" [class.hidden]="searchable() === false">
4125
- <input type="text" #inputRef placeholder="Search" />
4221
+ <input
4222
+ type="text"
4223
+ #inputRef
4224
+ placeholder="Search"
4225
+ role="combobox"
4226
+ [attr.aria-expanded]="isOpen()"
4227
+ [attr.aria-controls]="optionsId"
4228
+ [attr.aria-activedescendant]="activeOptionId()"
4229
+ aria-autocomplete="list" />
4126
4230
  </sh-form-field>
4127
4231
  </div>
4128
4232
 
@@ -4130,7 +4234,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
4130
4234
  class="options"
4131
4235
  #optionsRef
4132
4236
  (click)="close('active')"
4133
- [class.searching]="searchable() && inputValue() !== ''">
4237
+ [class.searching]="searchable() && inputValue() !== ''"
4238
+ role="listbox"
4239
+ [id]="optionsId"
4240
+ [attr.aria-activedescendant]="activeOptionId()">
4134
4241
  <ng-content select="[menu]" />
4135
4242
  </div>
4136
4243
  </sh-popover>
@@ -4142,7 +4249,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.0", ngImpor
4142
4249
  '[class.multi-layer]': 'asMultiLayer()',
4143
4250
  },
4144
4251
  }]
4145
- }], propDecorators: { asMultiLayer: [{ type: i0.Input, args: [{ isSignal: true, alias: "asMultiLayer", required: false }] }], openIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "openIndicator", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], customOptionElementSelectors: [{ type: i0.Input, args: [{ isSignal: true, alias: "customOptionElementSelectors", required: false }] }], keepClickedOptionActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepClickedOptionActive", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }, { type: i0.Output, args: ["isOpenChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], inputRef: [{ type: i0.ViewChild, args: ['inputRef', { isSignal: true }] }], optionsRef: [{ type: i0.ViewChild, args: ['optionsRef', { isSignal: true }] }] } });
4252
+ }], propDecorators: { asMultiLayer: [{ type: i0.Input, args: [{ isSignal: true, alias: "asMultiLayer", required: false }] }], openIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "openIndicator", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], customOptionElementSelectors: [{ type: i0.Input, args: [{ isSignal: true, alias: "customOptionElementSelectors", required: false }] }], keepClickedOptionActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "keepClickedOptionActive", required: false }] }], closeOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnClick", required: false }] }], isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }, { type: i0.Output, args: ["isOpenChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], inputRef: [{ type: i0.ViewChild, args: ['inputRef', { isSignal: true }] }], optionsRef: [{ type: i0.ViewChild, args: ['optionsRef', { isSignal: true }] }], onShipMenuOpen: [{
4253
+ type: HostListener,
4254
+ args: ['ship-menu-open', ['$event']]
4255
+ }] } });
4146
4256
 
4147
4257
  class ShipProgressBar {
4148
4258
  constructor() {
@@ -6913,14 +7023,22 @@ class ShipTooltipWrapper {
6913
7023
  if (this.isOpen()) {
6914
7024
  setTimeout(() => {
6915
7025
  this.#selfRef.nativeElement.showPopover();
6916
- this.calculateTooltipPosition();
7026
+ this.schedulePositionUpdate();
6917
7027
  });
6918
7028
  }
6919
7029
  else {
6920
7030
  this.#selfRef.nativeElement.hidePopover();
6921
7031
  }
6922
7032
  }, ...(ngDevMode ? [{ debugName: "openEffect" }] : []));
7033
+ this.rafId = null;
7034
+ this.schedulePositionUpdate = () => {
7035
+ if (this.rafId !== null) {
7036
+ cancelAnimationFrame(this.rafId);
7037
+ }
7038
+ this.rafId = requestAnimationFrame(this.calculateTooltipPosition);
7039
+ };
6923
7040
  this.calculateTooltipPosition = () => {
7041
+ this.rafId = null;
6924
7042
  if (!this.anchorEl())
6925
7043
  return;
6926
7044
  const hostRect = this.anchorEl().nativeElement.getBoundingClientRect();
@@ -6929,7 +7047,9 @@ class ShipTooltipWrapper {
6929
7047
  if (tooltipRect.width === 0 && tooltipRect.height === 0)
6930
7048
  return;
6931
7049
  const outOfBoundsTop = hostRect.top - tooltipRect.height < 0;
6932
- this.isBelow.set(outOfBoundsTop);
7050
+ if (this.isBelow() !== outOfBoundsTop) {
7051
+ this.isBelow.set(outOfBoundsTop);
7052
+ }
6933
7053
  if (!this.SUPPORTS_ANCHOR) {
6934
7054
  const tooltipRect = tooltipEl.getBoundingClientRect();
6935
7055
  let newTop = hostRect.top - tooltipRect.height;
@@ -6943,9 +7063,17 @@ class ShipTooltipWrapper {
6943
7063
  if (newLeft < 0) {
6944
7064
  newLeft = -(tooltipRect.width / 2);
6945
7065
  }
6946
- this.#renderer.setStyle(tooltipEl, 'left', `${newLeft}px`);
6947
- this.#renderer.setStyle(tooltipEl, 'top', `${newTop}px`);
6948
- this.#renderer.setStyle(tooltipEl, 'position', 'fixed');
7066
+ const leftStyle = `${newLeft}px`;
7067
+ const topStyle = `${newTop}px`;
7068
+ if (tooltipEl.style.left !== leftStyle) {
7069
+ this.#renderer.setStyle(tooltipEl, 'left', leftStyle);
7070
+ }
7071
+ if (tooltipEl.style.top !== topStyle) {
7072
+ this.#renderer.setStyle(tooltipEl, 'top', topStyle);
7073
+ }
7074
+ if (tooltipEl.style.position !== 'fixed') {
7075
+ this.#renderer.setStyle(tooltipEl, 'position', 'fixed');
7076
+ }
6949
7077
  }
6950
7078
  };
6951
7079
  }
@@ -6954,13 +7082,20 @@ class ShipTooltipWrapper {
6954
7082
  #positionAbort;
6955
7083
  ngAfterViewInit() {
6956
7084
  this.#positionAbort = new AbortController();
6957
- const options = { signal: this.#positionAbort.signal, capture: true };
6958
- window?.addEventListener('scroll', this.calculateTooltipPosition, options);
6959
- window?.addEventListener('resize', this.calculateTooltipPosition, { signal: this.#positionAbort.signal });
6960
- setTimeout(() => this.calculateTooltipPosition());
7085
+ const options = { signal: this.#positionAbort.signal, capture: true, passive: true };
7086
+ window?.addEventListener('scroll', this.schedulePositionUpdate, options);
7087
+ window?.addEventListener('resize', this.schedulePositionUpdate, {
7088
+ signal: this.#positionAbort.signal,
7089
+ passive: true,
7090
+ });
7091
+ this.schedulePositionUpdate();
6961
7092
  }
6962
7093
  ngOnDestroy() {
6963
7094
  this.#positionAbort?.abort();
7095
+ if (this.rafId !== null) {
7096
+ cancelAnimationFrame(this.rafId);
7097
+ this.rafId = null;
7098
+ }
6964
7099
  }
6965
7100
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.0", ngImport: i0, type: ShipTooltipWrapper, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
6966
7101
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.0", type: ShipTooltipWrapper, isStandalone: true, selector: "ship-tooltip-wrapper", inputs: { positionAnchorName: { classPropertyName: "positionAnchorName", publicName: "positionAnchorName", isSignal: true, isRequired: true, transformFunction: null }, anchorEl: { classPropertyName: "anchorEl", publicName: "anchorEl", isSignal: true, isRequired: true, transformFunction: null }, isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, close: { classPropertyName: "close", publicName: "close", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "tooltip" }, properties: { "attr.popover": "\"manual\"", "style.position-anchor": "positionAnchorName()", "class.below": "isBelow()" } }, ngImport: i0, template: `