Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions apps/portal/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,15 @@ export default class App extends React.Component {
initStatus: 'running',
lastPage: null,
customSiteUrl: props.customSiteUrl,
locale: props.locale
locale: props.locale,
scrollbarWidth: 0
};
}

componentDidMount() {
const scrollbarWidth = this.getScrollbarWidth();
this.setState({scrollbarWidth});

this.initSetup();
}

Expand All @@ -75,10 +79,19 @@ export default class App extends React.Component {
if (this.state.showPopup) {
/** When modal is opened, store current overflow and set as hidden */
this.bodyScroll = window.document?.body?.style?.overflow;
this.bodyMargin = window.getComputedStyle(document.body).getPropertyValue('margin-right');
window.document.body.style.overflow = 'hidden';
if (this.state.scrollbarWidth) {
window.document.body.style.marginRight = `calc(${this.bodyMargin} + ${this.state.scrollbarWidth}px)`;
}
} else {
/** When the modal is hidden, reset overflow property for body */
window.document.body.style.overflow = this.bodyScroll || '';
if (!this.bodyMargin || this.bodyMargin === '0px') {
window.document.body.style.marginRight = '';
} else {
window.document.body.style.marginRight = this.bodyMargin;
}
}
} catch (e) {
/** Ignore any errors for scroll handling */
Expand Down Expand Up @@ -115,6 +128,27 @@ export default class App extends React.Component {
}
}

// User for adding trailing margin to prevent layout shift when popup appears
getScrollbarWidth() {
// Create a temporary div
const div = document.createElement('div');
div.style.visibility = 'hidden';
div.style.overflow = 'scroll'; // forcing scrollbar to appear
document.body.appendChild(div);

// Create an inner div
// const inner = document.createElement('div');
document.body.appendChild(div);

// Calculate the width difference
const scrollbarWidth = div.offsetWidth - div.clientWidth;

// Clean up
document.body.removeChild(div);

return scrollbarWidth;
}

/** Setup custom trigger buttons handling on page */
setupCustomTriggerButton() {
// Handler for custom buttons
Expand Down Expand Up @@ -161,7 +195,7 @@ export default class App extends React.Component {
const {site, member, page, showPopup, popupNotification, lastPage, pageQuery, pageData} = await this.fetchData();
const i18nLanguage = this.props.siteI18nEnabled ? this.props.locale || site.locale || 'en' : 'en';
const i18n = i18nLib(i18nLanguage, 'portal');

const state = {
site,
member,
Expand Down Expand Up @@ -926,7 +960,7 @@ export default class App extends React.Component {

/**Get final App level context from App state*/
getContextFromState() {
const {site, member, action, page, lastPage, showPopup, pageQuery, pageData, popupNotification, customSiteUrl, t, dir} = this.state;
const {site, member, action, page, lastPage, showPopup, pageQuery, pageData, popupNotification, customSiteUrl, t, dir, scrollbarWidth} = this.state;
const contextPage = this.getContextPage({site, page, member});
const contextMember = this.getContextMember({page: contextPage, member, customSiteUrl});
return {
Expand All @@ -944,6 +978,7 @@ export default class App extends React.Component {
customSiteUrl,
t,
dir,
scrollbarWidth,
onAction: (_action, data) => this.dispatchAction(_action, data)
};
}
Expand Down
20 changes: 18 additions & 2 deletions apps/portal/src/components/TriggerButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,18 @@ export default class TriggerButton extends React.Component {
this.state = {
width: null
};
this.buttonRef = React.createRef();
}

componentDidMount() {
setTimeout(() => {
if (this.buttonRef.current) {
const iframeElement = this.buttonRef.current.node;
if (iframeElement) {
this.buttonMargin = window.getComputedStyle(iframeElement).getPropertyValue('margin-right');
}
}
}, 0);
}

onWidthChange(width) {
Expand Down Expand Up @@ -251,7 +263,7 @@ export default class TriggerButton extends React.Component {
render() {
const site = this.context.site;
const {portal_button: portalButton} = site;
const {showPopup} = this.context;
const {showPopup, scrollbarWidth} = this.context;

if (!portalButton || !isSigninAllowed({site}) || hasMode(['offerPreview'])) {
return null;
Expand All @@ -268,8 +280,12 @@ export default class TriggerButton extends React.Component {
frameStyle.width = `${updatedWidth}px`;
}

if (scrollbarWidth && showPopup) {
frameStyle.marginRight = `calc(${scrollbarWidth}px + ${this.buttonMargin})`;
}

return (
<Frame dataTestId='portal-trigger-frame' className='gh-portal-triggerbtn-iframe' style={frameStyle} title="portal-trigger" head={this.renderFrameStyles()}>
<Frame ref={this.buttonRef} dataTestId='portal-trigger-frame' className='gh-portal-triggerbtn-iframe' style={frameStyle} title="portal-trigger" head={this.renderFrameStyles()}>
<TriggerButtonContent isPopupOpen={showPopup} updateWidth={width => this.onWidthChange(width)} />
</Frame>
);
Expand Down