Merge pull request #1689 from joachimesque/details-fixes

Front-end: Fix Safari details display and enhance dropdown on mobile
This commit is contained in:
Mouse Reeve 2021-12-27 13:00:29 -08:00 committed by GitHub
commit 935cca2dd7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 11 deletions

View file

@ -93,6 +93,9 @@ body {
display: inline !important;
}
/** File input styles
******************************************************************************/
input[type=file]::file-selector-button {
-moz-appearance: none;
-webkit-appearance: none;
@ -119,17 +122,11 @@ input[type=file]::file-selector-button:hover {
color: #363636;
}
details .dropdown-menu {
display: block !important;
}
/** General `details` element styles
******************************************************************************/
details.dropdown[open] summary.dropdown-trigger::before {
content: "";
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
summary::-webkit-details-marker {
display: none;
}
summary::marker {
@ -147,6 +144,57 @@ summary::marker {
margin-top: 1em;
}
/** Details dropdown
******************************************************************************/
details.dropdown[open] summary.dropdown-trigger::before {
content: "";
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
details .dropdown-menu {
display: block !important;
}
details .dropdown-menu button {
/* Fix weird Safari defaults */
box-sizing: border-box;
}
details.dropdown .dropdown-menu button:focus-visible,
details.dropdown .dropdown-menu a:focus-visible {
outline-style: auto;
outline-offset: -2px;
}
@media only screen and (max-width: 768px) {
details.dropdown[open] summary.dropdown-trigger::before {
background-color: rgba(0, 0, 0, 0.5);
z-index: 30;
}
details .dropdown-menu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex !important;
align-items: center;
justify-content: center;
pointer-events: none;
z-index: 100;
}
details .dropdown-menu > * {
pointer-events: all;
}
}
/** Shelving
******************************************************************************/

View file

@ -51,6 +51,12 @@ let BookWyrm = new class {
'click',
this.duplicateInput.bind(this)
))
document.querySelectorAll('details.dropdown')
.forEach(node => node.addEventListener(
'toggle',
this.handleDetailsDropdown.bind(this)
))
}
@ -482,4 +488,101 @@ let BookWyrm = new class {
textareaEl.parentNode.appendChild(copyButtonEl)
}
/**
* Handle the details dropdown component.
*
* @param {Event} event - Event fired by a `details` element
* with the `dropdown` class name, on toggle.
* @return {undefined}
*/
handleDetailsDropdown(event) {
const detailsElement = event.target;
const summaryElement = detailsElement.querySelector('summary');
const menuElement = detailsElement.querySelector('.dropdown-menu');
const htmlElement = document.querySelector('html');
if (detailsElement.open) {
// Focus first menu element
menuElement.querySelectorAll(
'a[href]:not([disabled]), button:not([disabled])'
)[0].focus();
// Enable focus trap
menuElement.addEventListener('keydown', this.handleFocusTrap);
// Close on Esc
detailsElement.addEventListener('keydown', handleEscKey);
// Clip page if Mobile
if (this.isMobile()) {
htmlElement.classList.add('is-clipped');
}
} else {
summaryElement.focus();
// Disable focus trap
menuElement.removeEventListener('keydown', this.handleFocusTrap);
// Unclip page
if (this.isMobile()) {
htmlElement.classList.remove('is-clipped');
}
}
function handleEscKey(event) {
if (event.key !== 'Escape') {
return;
}
summaryElement.click();
}
}
/**
* Check if windows matches mobile media query.
*
* @return {Boolean}
*/
isMobile() {
return window.matchMedia("(max-width: 768px)").matches;
}
/**
* Focus trap handler
*
* @param {Event} event - Keydown event.
* @return {undefined}
*/
handleFocusTrap(event) {
if (event.key !== 'Tab') {
return;
}
const focusableEls = event.currentTarget.querySelectorAll(
[
'a[href]:not([disabled])',
'button:not([disabled])',
'textarea:not([disabled])',
'input:not([type="hidden"]):not([disabled])',
'select:not([disabled])',
'details:not([disabled])',
'[tabindex]:not([tabindex="-1"]):not([disabled])'
].join(',')
);
const firstFocusableEl = focusableEls[0];
const lastFocusableEl = focusableEls[focusableEls.length - 1];
if (event.shiftKey ) /* Shift + tab */ {
if (document.activeElement === firstFocusableEl) {
lastFocusableEl.focus();
event.preventDefault();
}
} else /* Tab */ {
if (document.activeElement === lastFocusableEl) {
firstFocusableEl.focus();
event.preventDefault();
}
}
}
}();

View file

@ -15,7 +15,7 @@
{% block dropdown-trigger %}{% endblock %}
</summary>
<div class="dropdown-menu control">
<div class="dropdown-menu">
<ul
id="menu_options_{{ uuid }}"
class="dropdown-content p-0 is-clipped"