-
Notifications
You must be signed in to change notification settings - Fork 326
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
Apply modal pattern to search box pop-up #1932
Changes from all commits
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(#pst-search-dialog) > form.bd-search", | ||
); | ||
} | ||
return form.querySelector("input"); | ||
|
@@ -208,22 +208,30 @@ var findSearchInput = () => { | |
*/ | ||
var toggleSearchField = () => { | ||
// Find the search input to highlight | ||
let input = findSearchInput(); | ||
const input = findSearchInput(); | ||
|
||
// 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"); | ||
const searchDialog = document.getElementById("pst-search-dialog"); | ||
const hiddenInput = searchDialog.querySelector("input"); | ||
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 | ||
|
||
if (document.activeElement === input) { | ||
input.blur(); | ||
} else { | ||
input.focus(); | ||
input.select(); | ||
input.scrollIntoView({ block: "center" }); | ||
} | ||
} | ||
}; | ||
|
||
|
@@ -295,11 +303,30 @@ 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.getElementById("pst-search-dialog"); | ||
// Dialog click handler includes clicks on dialog ::backdrop. | ||
searchDialog.addEventListener("click", (event) => { | ||
if (!searchDialog.open) { | ||
return; | ||
} | ||
|
||
// Dialog.getBoundingClientRect() does not include ::backdrop. (This is the | ||
// trick that allows us to determine if click was inside or outside of the | ||
// dialog: click handler includes backdrop, getBoundingClientRect does not.) | ||
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,11 @@ | |
color: var(--pst-color-text-muted); | ||
} | ||
|
||
input { | ||
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 +52,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 modal <dialog> | ||
*/ | ||
#pst-search-dialog { | ||
display: none; | ||
} | ||
|
||
.search-button__wrapper.show { | ||
.search-button__search-container { | ||
&[open] { | ||
display: flex; | ||
|
||
// Center in middle of screen just underneath header | ||
|
@@ -91,30 +94,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 +138,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 |
---|---|---|
|
@@ -6,7 +6,6 @@ | |
<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. |
||
placeholder="{{ theme_search_bar_text }}" | ||
aria-label="{{ theme_search_bar_text }}" | ||
autocomplete="off" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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:
searchDialog.showModal()
puts focus on search input fieldinput.blur()
removes focus from search input fieldSo 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).