-
Notifications
You must be signed in to change notification settings - Fork 341
Apply modal pattern to search box pop-up #1932
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
Changes from 1 commit
1811486
200d871
0741fea
c58f131
a223828
c30a5bc
dd5eb7d
64dd4d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -194,7 +194,7 @@ var findSearchInput = () => { | |
} else { | ||
// must be at least one persistent form, use the first persistent one | ||
form = document.querySelector( | ||
"div:not(.search-button__search-container) > form.bd-search", | ||
":not(.search-button__search-container) > form.bd-search", | ||
); | ||
} | ||
return form.querySelector("input"); | ||
|
@@ -212,18 +212,26 @@ var toggleSearchField = () => { | |
|
||
// if the input field is the hidden one (the one associated with the | ||
// search button) then toggle the button state (to show/hide the field) | ||
let searchPopupWrapper = document.querySelector(".search-button__wrapper"); | ||
let hiddenInput = searchPopupWrapper.querySelector("input"); | ||
let searchDialog = document.querySelector(".search-button__search-container"); | ||
Carreau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let hiddenInput = searchDialog.querySelector("input"); | ||
Carreau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (input === hiddenInput) { | ||
searchPopupWrapper.classList.toggle("show"); | ||
} | ||
// when toggling off the search field, remove its focus | ||
if (document.activeElement === input) { | ||
input.blur(); | ||
if (searchDialog.open) { | ||
searchDialog.close(); | ||
} else { | ||
// Note: browsers should focus the input field inside the modal dialog | ||
// automatically when it is opened. | ||
searchDialog.showModal(); | ||
} | ||
} else { | ||
input.focus(); | ||
input.select(); | ||
input.scrollIntoView({ block: "center" }); | ||
// if the input field is not the hidden one, then toggle its focus state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the left side, the logic in this else-branch was always run. That was because the old way of opening the search pop-up did not automatically focus the search input field. However, when the search input field is inside a dialog, then when you open the dialog, it is automatically focussed. So if you then run the code below, you get a buggy sequence of actions:
So the solution is to put this toggle logic in an else-branch to handle the case when the search field is on already on the page (for example, the search results page, or a page with a persistent search bar). |
||
|
||
if (document.activeElement === input) { | ||
input.blur(); | ||
} else { | ||
input.focus(); | ||
input.select(); | ||
input.scrollIntoView({ block: "center" }); | ||
} | ||
} | ||
}; | ||
|
||
|
@@ -295,11 +303,27 @@ var setupSearchButtons = () => { | |
btn.onclick = toggleSearchField; | ||
}); | ||
|
||
// Add the search button overlay event callback | ||
let overlay = document.querySelector(".search-button__overlay"); | ||
if (overlay) { | ||
overlay.onclick = toggleSearchField; | ||
} | ||
// If user clicks outside the search modal dialog, then close it. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default behavior for modal dialogs is to stay on the screen even if you click on the dialog's backdrop. To me the old behavior seemed natural though - i.e., if the user clicks the backdrop, we remove the pop-up search bar. So I restore that behavior here. |
||
const searchDialog = document.querySelector( | ||
".search-button__search-container", | ||
); | ||
searchDialog.addEventListener("click", (event) => { | ||
if (!searchDialog.open) { | ||
return; | ||
} | ||
|
||
const { left, right, top, bottom } = searchDialog.getBoundingClientRect(); | ||
// 0, 0 means top left | ||
const clickWasOutsideDialog = | ||
event.clientX < left || | ||
right < event.clientX || | ||
event.clientY < top || | ||
bottom < event.clientY; | ||
|
||
if (clickWasOutsideDialog) { | ||
searchDialog.close(); | ||
} | ||
}); | ||
Carreau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
/******************************************************************************* | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,15 @@ | |
color: var(--pst-color-text-muted); | ||
} | ||
|
||
// Hoist the focus ring from the input field to its parent | ||
&:focus-within { | ||
box-shadow: $focus-ring-box-shadow; | ||
|
||
input:focus { | ||
box-shadow: none; | ||
} | ||
} | ||
|
||
.icon { | ||
position: absolute; | ||
color: var(--pst-color-border); | ||
|
@@ -28,7 +37,15 @@ | |
color: var(--pst-color-text-muted); | ||
} | ||
|
||
input { | ||
label { | ||
display: flex; | ||
gabalafou marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
input.form-control { | ||
background-color: var(--pst-color-background); | ||
color: var(--pst-color-text-base); | ||
border: none; | ||
|
||
// Inner-text of the search bar | ||
&::placeholder { | ||
color: var(--pst-color-text-muted); | ||
|
@@ -39,46 +56,36 @@ | |
&::-webkit-search-decoration { | ||
appearance: none; | ||
} | ||
|
||
&:focus, | ||
&:focus-visible { | ||
color: var(--pst-color-text-muted); | ||
} | ||
} | ||
|
||
// Shows off the keyboard shortcuts for the button | ||
.search-button__kbd-shortcut { | ||
display: flex; | ||
position: absolute; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
right: 0.5rem; | ||
margin-inline-end: 0.5rem; | ||
color: var(--pst-color-border); | ||
} | ||
} | ||
|
||
.form-control { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I merged these rules in with the |
||
background-color: var(--pst-color-background); | ||
color: var(--pst-color-text-base); | ||
|
||
&:focus, | ||
&:focus-visible { | ||
border: none; | ||
background-color: var(--pst-color-background); | ||
color: var(--pst-color-text-muted); | ||
} | ||
} | ||
|
||
/** | ||
* Search button - located in the navbar | ||
*/ | ||
|
||
// Search link icon should be a bit bigger since it is separate from icon links | ||
.search-button i { | ||
// Search link icon should be a bit bigger since it is separate from icon links | ||
font-size: 1.3rem; | ||
} | ||
|
||
// __search-container will only show up when we use the search pop-up bar | ||
.search-button__search-container, | ||
.search-button__overlay { | ||
/** | ||
* The search pop-up <dialog> | ||
gabalafou marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
.search-button__search-container { | ||
display: none; | ||
} | ||
|
||
.search-button__wrapper.show { | ||
.search-button__search-container { | ||
&[open] { | ||
display: flex; | ||
|
||
// Center in middle of screen just underneath header | ||
|
@@ -91,30 +98,24 @@ | |
margin-top: 0.5rem; | ||
width: 90%; | ||
max-width: 800px; | ||
} | ||
background-color: transparent; | ||
padding: $focus-ring-width; | ||
border: none; | ||
Carreau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
.search-button__overlay { | ||
display: flex; | ||
position: fixed; | ||
z-index: $zindex-modal-backdrop; | ||
background-color: black; | ||
opacity: 0.5; | ||
width: 100%; | ||
height: 100%; | ||
top: 0; | ||
left: 0; | ||
} | ||
&::backdrop { | ||
background-color: black; | ||
opacity: 0.5; | ||
} | ||
|
||
form.bd-search { | ||
flex-grow: 1; | ||
padding-top: 0; | ||
padding-bottom: 0; | ||
Comment on lines
-110
to
-111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These padding rules are not needed. The form already has 0 top and bottom padding. |
||
} | ||
form.bd-search { | ||
flex-grow: 1; | ||
|
||
// Font and input text a bit bigger | ||
svg, | ||
input { | ||
font-size: var(--pst-font-size-icon); | ||
// Font and input text a bit bigger | ||
svg, | ||
input { | ||
font-size: var(--pst-font-size-icon); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -141,7 +142,7 @@ | |
border-radius: $search-button-border-radius; | ||
} | ||
|
||
// The keyboard shotcut text | ||
// The keyboard shortcut text | ||
.search-button__default-text { | ||
font-size: var(--bs-nav-link-font-size); | ||
font-weight: var(--bs-nav-link-font-weight); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,13 +2,13 @@ | |
<form class="bd-search d-flex align-items-center" | ||
action="{{ pathto('search') }}" | ||
method="get"> | ||
<i class="fa-solid fa-magnifying-glass"></i> | ||
<label for="{{ search_input_id }}" | ||
aria-label="{{ theme_search_bar_text }}"><i class="fa-solid fa-magnifying-glass"></i></label> | ||
gabalafou marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<input type="search" | ||
class="form-control" | ||
name="q" | ||
id="search-input" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's misleading to put an id on this element because this template can currently be rendered on the same page more than once. This definitely happens in the PST docs, for example, on the search results page. |
||
id="{{ search_input_id }}" | ||
placeholder="{{ theme_search_bar_text }}" | ||
aria-label="{{ theme_search_bar_text }}" | ||
autocomplete="off" | ||
autocorrect="off" | ||
autocapitalize="off" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,10 +63,10 @@ | |
id="pst-secondary-sidebar-checkbox"/> | ||
<label class="overlay overlay-secondary" for="pst-secondary-sidebar-checkbox"></label> | ||
{# A search field pop-up that will only show when the search button is clicked #} | ||
<div class="search-button__wrapper"> | ||
<div class="search-button__overlay"></div> | ||
<div class="search-button__search-container">{% include "../components/search-field.html" %}</div> | ||
</div> | ||
<dialog class="search-button__search-container"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wondering if this class should be renamed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a question in another comments if this should even be made an id, as the js assume there is only one I think. Don't trust me on Js. |
||
{%- set search_input_id="search-input-hidden" -%} | ||
{% include "../components/search-field.html" %} | ||
Carreau marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</dialog> | ||
|
||
{% include "sections/announcement.html" %} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.