Skip to content

Commit c9343ff

Browse files
committed
fix: padding calculation in sticky mode
1 parent c97d6b2 commit c9343ff

File tree

2 files changed

+47
-36
lines changed

2 files changed

+47
-36
lines changed

.changeset/fifty-boxes-cry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@inventage-web-components/portal-navigation': minor
3+
---
4+
5+
Rewrite the anchor padding updating mechanism in sticky mode to use `requestAnimationFrame` for a maximum of `100` times after each update. This should fix the padding issues in sticky mode once and for all…

packages/portal-navigation/src/PortalNavigation.ts

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { baseStyles, CSSResultArray, html, LitElement, nothing, PropertyValues, TemplateResult } from '@inventage-web-components/common';
22
import { property, state, query } from '@inventage-web-components/common/lib/src/decorators.js';
33
import { classMap, ClassInfo, ifDefined } from '@inventage-web-components/common/lib/src/directives.js';
4-
import { debounce } from 'ts-debounce';
54
import '@inventage-web-components/hamburger-menu/lib/src/hamburger-menu.js';
65

76
import { IdPath } from './IdPath.js';
@@ -335,6 +334,10 @@ export class PortalNavigation extends LitElement {
335334

336335
private initialAnchorElementPadding?: string;
337336

337+
private anchorElementPaddingRefreshInterval?: number;
338+
private anchorElementPaddingRefreshCount = 0;
339+
private anchorElementPaddingRefreshMaxCount = 100;
340+
338341
static get styles(): CSSResultArray {
339342
return [baseStyles, styles];
340343
}
@@ -375,13 +378,8 @@ export class PortalNavigation extends LitElement {
375378
this.__setActiveUrlEventListener = this.__setActiveUrlEventListener.bind(this);
376379
this.__globalClickListener = this.__globalClickListener.bind(this);
377380

378-
// Always debounce anchor padding updates
379-
/**
380-
* @internal
381-
*/
382-
this.updateAnchorPaddingWhenSticky = debounce(this.updateAnchorPaddingWhenSticky, 100, {
383-
isImmediate: true,
384-
}).bind(this);
381+
// We bind this as well since we bind it to the global resize event listener
382+
this.updateAnchorPaddingWhenSticky = this.updateAnchorPaddingWhenSticky.bind(this);
385383
}
386384

387385
connectedCallback(): void {
@@ -481,13 +479,22 @@ export class PortalNavigation extends LitElement {
481479
this.dispatchEvent(new CustomEvent(NavigationEvents.breakpointChanged, { detail: this.isMobileBreakpoint, composed: true, bubbles: true }));
482480
}
483481

484-
// This code will be run ASAP after Style and Layout information have been calculated and the paint has occurred.
485-
// @see https://firefox-source-docs.mozilla.org/performance/bestpractices.html
486-
requestAnimationFrame(() => {
487-
setTimeout(() => {
488-
this.updateAnchorPaddingWhenStickyInternal();
489-
}, 0);
490-
});
482+
this.anchorElementPaddingRefreshInterval && cancelAnimationFrame(this.anchorElementPaddingRefreshInterval);
483+
if (this.shouldUpdateAnchorPadding()) {
484+
this.anchorElementPaddingRefreshCount = 0;
485+
this.anchorElementPaddingRefreshInterval = window.requestAnimationFrame(() => this.anchorElementPaddingRefresh());
486+
}
487+
}
488+
489+
private anchorElementPaddingRefresh() {
490+
if (++this.anchorElementPaddingRefreshCount >= this.anchorElementPaddingRefreshMaxCount) {
491+
this.anchorElementPaddingRefreshCount = 0;
492+
this.anchorElementPaddingRefreshInterval && cancelAnimationFrame(this.anchorElementPaddingRefreshInterval);
493+
return;
494+
}
495+
496+
this.updateAnchorPaddingWhenSticky();
497+
this.anchorElementPaddingRefreshInterval = window.requestAnimationFrame(() => this.anchorElementPaddingRefresh());
491498
}
492499

493500
render(): unknown {
@@ -1164,28 +1171,11 @@ export class PortalNavigation extends LitElement {
11641171

11651172
/**
11661173
* Updates the padding of the anchor when navigation should be sticky.
1167-
* This function is bound to events and is debounced by default.
1168-
* Use updateAnchorPaddingWhenStickyInternal() when you want to call the non-debounced version.
11691174
*
11701175
* @private
11711176
*/
11721177
private updateAnchorPaddingWhenSticky() {
1173-
this.updateAnchorPaddingWhenStickyInternal();
1174-
}
1175-
1176-
/**
1177-
* Updates the padding of the anchor when navigation should be sticky.
1178-
*
1179-
* @private
1180-
*/
1181-
private updateAnchorPaddingWhenStickyInternal() {
1182-
// Bail when anchor is available, or we're not in sticky mode
1183-
if (!this.sticky || !this.anchorElement) {
1184-
return;
1185-
}
1186-
1187-
// Do nothing to the padding when the mobile menu is open
1188-
if (this.isMobileBreakpoint && this.hamburgerMenuExpanded) {
1178+
if (!this.shouldUpdateAnchorPadding()) {
11891179
return;
11901180
}
11911181

@@ -1195,16 +1185,32 @@ export class PortalNavigation extends LitElement {
11951185
}
11961186

11971187
const targetPadding = `${height}px`;
1198-
if (this.anchorElement.style.paddingTop === targetPadding) {
1188+
if (this.anchorElement!.style.paddingTop === targetPadding) {
11991189
return;
12001190
}
12011191

12021192
// Save initial padding in case we need to restore it later
12031193
if (this.initialAnchorElementPadding === undefined) {
1204-
this.initialAnchorElementPadding = this.anchorElement.style.paddingTop;
1194+
this.initialAnchorElementPadding = this.anchorElement!.style.paddingTop;
12051195
}
12061196

1207-
this.anchorElement.style.paddingTop = targetPadding;
1197+
this.anchorElement!.style.paddingTop = targetPadding;
1198+
}
1199+
1200+
/**
1201+
* The anchor padding should be updated when we're in sticky mode, the anchor is available,
1202+
* and we're not in mobile breakpoint with an expanded hamburger menu.
1203+
*
1204+
* @private
1205+
*/
1206+
private shouldUpdateAnchorPadding() {
1207+
// Bail when anchor is available, or we're not in sticky mode
1208+
if (!this.sticky || !this.anchorElement) {
1209+
return false;
1210+
}
1211+
1212+
// Do nothing to the padding when the mobile menu is open
1213+
return !(this.isMobileBreakpoint && this.hamburgerMenuExpanded);
12081214
}
12091215

12101216
/**

0 commit comments

Comments
 (0)