Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal | JS | Add page scrolling option #1304

Merged
merged 8 commits into from
Aug 5, 2019
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{% set javascript %}
<script>
// If the browser body has scrollbar, set padding on the element the width of the scrollbar
const setScrollbarPadding = function(element, hasScrollbar, scrollbarWidth) {
if (!element) {
return;
}

if (hasScrollbar) {
const originalPadding = element.style.paddingRight;
const calculatedPadding = window.getComputedStyle(element)[
'padding-right'
];

// Save original padding value for later
element.setAttribute('data-padding-right', originalPadding);
element.style.paddingRight = parseFloat(calculatedPadding) + scrollbarWidth + 'px';
}
}

// Reset the padding on that element after modal is hidden
const resetScrollbarPadding = function(element) {
if (!element) {
return;
}

const padding = element.getAttribute('data-padding-right');

element.style.paddingRight = '';

if (typeof padding === 'undefined') {
element.style.paddingRight = '';
} else {
element.removeAttribute('data-padding-right');
// Restore original padding value
element.style.paddingRight = padding;
}
}

// Arbitrary fixed element, could be .c-page-header
const fixedElement = document.querySelector('.placeholder-fixed-element');

// Listen for 'modal:show' on the body, event will bubble up from the modal
document.body.addEventListener('modal:show', function(e) {
setScrollbarPadding(fixedElement, e.detail.hasScrollbar, e.detail.scrollbarWidth);
});

// Listen for 'modal:hidden', fires after the modal has animated out
document.body.addEventListener('modal:hidden', function(e) {
resetScrollbarPadding(fixedElement);
});
</script>
{% endset %}

<bolt-text headline font-size="xlarge" style="margin-top: 120px;">Modal Custom Events</bolt-text>
<bolt-text>Bolt Modal emits the following custom events: <code>modal:show</code>, <code>modal:shown</code>, <code>modal:hide</code>, <code>modal:hidden</code>.</bolt-text>
sghoweri marked this conversation as resolved.
Show resolved Hide resolved

<div class="placeholder-fixed-element" style="background: yellow; padding: 2rem; text-align: center; position: fixed; top: 0; height: 100px; width: 100%;">
Placeholder "fixed" element, should not shift when modal shows/hides.
</div>

<bolt-text headline font-size="large">Demo</bolt-text>
<div class="t-bolt-light u-bolt-padding-medium u-bolt-margin-bottom-small">
{% set modal_content %}
{% include "@bolt-components-video/video.twig" with {
videoId: "3861325118001",
accountId: "1900410236",
playerId: "r1CAdLzTW",
showMeta: true,
showMetaTitle: true,
attributes: {
class: "js-modal-video-123"
}
} only %}
{% endset %}

{% set trigger %}
{% include "@bolt-components-button/button.twig" with {
text: "Play the video",
size: "small",
width: "full",
attributes: {
"on-click": "show",
"on-click-target": "js-modal-123"
}
} only %}
{% include "@bolt-components-modal/modal.twig" with {
attributes: {
class: "js-modal-123"
},
content: modal_content,
width: "optimal",
spacing: "none",
theme: "none",
scroll: "overall",
} only %}
{{ javascript }}
{% endset %}
{% set description %}
<bolt-text headline font-size="large">Set padding on a "fixed" element when modal shows/hides</bolt-text>
<bolt-text>Use the <code>modal:show</code> and <code>modal:hidden</code> events to set padding on a fixed element to prevent it from shifting.</bolt-text>
<bolt-text>Note: for this example, you must use <code>modal:hidden</code> not <code>modal:hide</code> event, as <code>modal:hidden</code> fires after the modal animation, and that is key to getting the correct <code>hasScrollbar</code> state.</bolt-text>
{% endset %}
{% include "@bolt-components-grid/grid.twig" with {
items: [
{
column_start: "1 1@small",
column_span: "12 8@small 9@medium",
row_start: "2 1@small",
row_span: "1",
valign: "center",
content: description,
},
{
column_start: "1 10@small 11@medium",
column_span: "6 3@small 2@medium",
row_start: "1 1@small",
row_span: "1",
valign: "center",
content: trigger,
},
]
} only %}
</div>

<bolt-text headline font-size="large">Custom Javascript</bolt-text>
<bolt-code-snippet syntax="dark" lang="html">{% spaceless %}
{{ javascript | replace({
'<': '&lt;',
'>': '&gt;',
}) | trim | raw }}
{% endspaceless %}</bolt-code-snippet>
24 changes: 21 additions & 3 deletions packages/components/bolt-modal/src/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ class BoltModal extends withLitHtml() {
this.dispatchEvent(new CustomEvent('modal:ready'));
}

get _toggleEventOptions() {
return {
detail: {
hasScrollbar: this._bodyHasScrollbar,
scrollbarWidth: this.scrollbarWidth,
},
bubbles: true,
};
}

/**
* Show the dialog element, disable all the targets (siblings), trap the
* current focus within it, listen for some specific key presses and fire all
Expand All @@ -101,6 +111,8 @@ class BoltModal extends withLitHtml() {
// triggers re-render
this.open = true;

this.dispatchEvent(new CustomEvent('modal:show', this._toggleEventOptions));

this._setScrollbar();

// @todo: re-evaluate if the trigger element used needs to have it's tabindex messed with
Expand All @@ -113,7 +125,9 @@ class BoltModal extends withLitHtml() {
// this.dialog.setAttribute('open', '');
// this.container.removeAttribute('aria-hidden');

this.dispatchEvent(new CustomEvent('modal:show'));
this.dispatchEvent(
new CustomEvent('modal:shown', this._toggleEventOptions),
);
}

/**
Expand All @@ -133,13 +147,19 @@ class BoltModal extends withLitHtml() {
this.focusTrap.active = false;
this.open = false;
this.ready = false;

this.dispatchEvent(new CustomEvent('modal:hide', this._toggleEventOptions));

this.transitionDuration = getTransitionDuration(
this.renderRoot.querySelector('.c-bolt-modal'),
);

// Wait until after transition or modal will shift
setTimeout(() => {
this._resetScrollbar();
this.dispatchEvent(
new CustomEvent('modal:hidden', this._toggleEventOptions),
);
}, this.transitionDuration);

// @todo: refactor this to be more component / element agnostic
Expand Down Expand Up @@ -170,8 +190,6 @@ class BoltModal extends withLitHtml() {
// target.removeAttribute('aria-hidden');
// });
}

this.dispatchEvent(new CustomEvent('modal:hide'));
}

get _bodyHasScrollbar() {
Expand Down