Skip to content

Commit 1811486

Browse files
committed
Apply modal pattern to search box pop-up
1 parent 477de81 commit 1811486

File tree

5 files changed

+94
-68
lines changed

5 files changed

+94
-68
lines changed

src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ var findSearchInput = () => {
194194
} else {
195195
// must be at least one persistent form, use the first persistent one
196196
form = document.querySelector(
197-
"div:not(.search-button__search-container) > form.bd-search",
197+
":not(.search-button__search-container) > form.bd-search",
198198
);
199199
}
200200
return form.querySelector("input");
@@ -212,18 +212,26 @@ var toggleSearchField = () => {
212212

213213
// if the input field is the hidden one (the one associated with the
214214
// search button) then toggle the button state (to show/hide the field)
215-
let searchPopupWrapper = document.querySelector(".search-button__wrapper");
216-
let hiddenInput = searchPopupWrapper.querySelector("input");
215+
let searchDialog = document.querySelector(".search-button__search-container");
216+
let hiddenInput = searchDialog.querySelector("input");
217217
if (input === hiddenInput) {
218-
searchPopupWrapper.classList.toggle("show");
219-
}
220-
// when toggling off the search field, remove its focus
221-
if (document.activeElement === input) {
222-
input.blur();
218+
if (searchDialog.open) {
219+
searchDialog.close();
220+
} else {
221+
// Note: browsers should focus the input field inside the modal dialog
222+
// automatically when it is opened.
223+
searchDialog.showModal();
224+
}
223225
} else {
224-
input.focus();
225-
input.select();
226-
input.scrollIntoView({ block: "center" });
226+
// if the input field is not the hidden one, then toggle its focus state
227+
228+
if (document.activeElement === input) {
229+
input.blur();
230+
} else {
231+
input.focus();
232+
input.select();
233+
input.scrollIntoView({ block: "center" });
234+
}
227235
}
228236
};
229237

@@ -295,11 +303,27 @@ var setupSearchButtons = () => {
295303
btn.onclick = toggleSearchField;
296304
});
297305

298-
// Add the search button overlay event callback
299-
let overlay = document.querySelector(".search-button__overlay");
300-
if (overlay) {
301-
overlay.onclick = toggleSearchField;
302-
}
306+
// If user clicks outside the search modal dialog, then close it.
307+
const searchDialog = document.querySelector(
308+
".search-button__search-container",
309+
);
310+
searchDialog.addEventListener("click", (event) => {
311+
if (!searchDialog.open) {
312+
return;
313+
}
314+
315+
const { left, right, top, bottom } = searchDialog.getBoundingClientRect();
316+
// 0, 0 means top left
317+
const clickWasOutsideDialog =
318+
event.clientX < left ||
319+
right < event.clientX ||
320+
event.clientY < top ||
321+
bottom < event.clientY;
322+
323+
if (clickWasOutsideDialog) {
324+
searchDialog.close();
325+
}
326+
});
303327
};
304328

305329
/*******************************************************************************

src/pydata_sphinx_theme/assets/styles/components/_search.scss

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
color: var(--pst-color-text-muted);
1717
}
1818

19+
// Hoist the focus ring from the input field to its parent
20+
&:focus-within {
21+
box-shadow: $focus-ring-box-shadow;
22+
23+
input:focus {
24+
box-shadow: none;
25+
}
26+
}
27+
1928
.icon {
2029
position: absolute;
2130
color: var(--pst-color-border);
@@ -28,7 +37,15 @@
2837
color: var(--pst-color-text-muted);
2938
}
3039

31-
input {
40+
label {
41+
display: flex;
42+
}
43+
44+
input.form-control {
45+
background-color: var(--pst-color-background);
46+
color: var(--pst-color-text-base);
47+
border: none;
48+
3249
// Inner-text of the search bar
3350
&::placeholder {
3451
color: var(--pst-color-text-muted);
@@ -39,46 +56,36 @@
3956
&::-webkit-search-decoration {
4057
appearance: none;
4158
}
59+
60+
&:focus,
61+
&:focus-visible {
62+
color: var(--pst-color-text-muted);
63+
}
4264
}
4365

4466
// Shows off the keyboard shortcuts for the button
4567
.search-button__kbd-shortcut {
4668
display: flex;
47-
position: absolute;
48-
right: 0.5rem;
69+
margin-inline-end: 0.5rem;
4970
color: var(--pst-color-border);
5071
}
5172
}
5273

53-
.form-control {
54-
background-color: var(--pst-color-background);
55-
color: var(--pst-color-text-base);
56-
57-
&:focus,
58-
&:focus-visible {
59-
border: none;
60-
background-color: var(--pst-color-background);
61-
color: var(--pst-color-text-muted);
62-
}
63-
}
64-
6574
/**
6675
* Search button - located in the navbar
6776
*/
68-
69-
// Search link icon should be a bit bigger since it is separate from icon links
7077
.search-button i {
78+
// Search link icon should be a bit bigger since it is separate from icon links
7179
font-size: 1.3rem;
7280
}
7381

74-
// __search-container will only show up when we use the search pop-up bar
75-
.search-button__search-container,
76-
.search-button__overlay {
82+
/**
83+
* The search pop-up <dialog>
84+
*/
85+
.search-button__search-container {
7786
display: none;
78-
}
7987

80-
.search-button__wrapper.show {
81-
.search-button__search-container {
88+
&[open] {
8289
display: flex;
8390

8491
// Center in middle of screen just underneath header
@@ -91,30 +98,24 @@
9198
margin-top: 0.5rem;
9299
width: 90%;
93100
max-width: 800px;
94-
}
101+
background-color: transparent;
102+
padding: $focus-ring-width;
103+
border: none;
95104

96-
.search-button__overlay {
97-
display: flex;
98-
position: fixed;
99-
z-index: $zindex-modal-backdrop;
100-
background-color: black;
101-
opacity: 0.5;
102-
width: 100%;
103-
height: 100%;
104-
top: 0;
105-
left: 0;
106-
}
105+
&::backdrop {
106+
background-color: black;
107+
opacity: 0.5;
108+
}
107109

108-
form.bd-search {
109-
flex-grow: 1;
110-
padding-top: 0;
111-
padding-bottom: 0;
112-
}
110+
form.bd-search {
111+
flex-grow: 1;
113112

114-
// Font and input text a bit bigger
115-
svg,
116-
input {
117-
font-size: var(--pst-font-size-icon);
113+
// Font and input text a bit bigger
114+
svg,
115+
input {
116+
font-size: var(--pst-font-size-icon);
117+
}
118+
}
118119
}
119120
}
120121

@@ -141,7 +142,7 @@
141142
border-radius: $search-button-border-radius;
142143
}
143144

144-
// The keyboard shotcut text
145+
// The keyboard shortcut text
145146
.search-button__default-text {
146147
font-size: var(--bs-nav-link-font-size);
147148
font-weight: var(--bs-nav-link-font-weight);

src/pydata_sphinx_theme/theme/pydata_sphinx_theme/components/search-field.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
<form class="bd-search d-flex align-items-center"
33
action="{{ pathto('search') }}"
44
method="get">
5-
<i class="fa-solid fa-magnifying-glass"></i>
5+
<label for="{{ search_input_id }}"
6+
aria-label="{{ theme_search_bar_text }}"><i class="fa-solid fa-magnifying-glass"></i></label>
67
<input type="search"
78
class="form-control"
89
name="q"
9-
id="search-input"
10+
id="{{ search_input_id }}"
1011
placeholder="{{ theme_search_bar_text }}"
11-
aria-label="{{ theme_search_bar_text }}"
1212
autocomplete="off"
1313
autocorrect="off"
1414
autocapitalize="off"

src/pydata_sphinx_theme/theme/pydata_sphinx_theme/layout.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@
6363
id="pst-secondary-sidebar-checkbox"/>
6464
<label class="overlay overlay-secondary" for="pst-secondary-sidebar-checkbox"></label>
6565
{# A search field pop-up that will only show when the search button is clicked #}
66-
<div class="search-button__wrapper">
67-
<div class="search-button__overlay"></div>
68-
<div class="search-button__search-container">{% include "../components/search-field.html" %}</div>
69-
</div>
66+
<dialog class="search-button__search-container">
67+
{%- set search_input_id="search-input-hidden" -%}
68+
{% include "../components/search-field.html" %}
69+
</dialog>
7070

7171
{% include "sections/announcement.html" %}
7272

src/pydata_sphinx_theme/theme/pydata_sphinx_theme/search.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ <h1>{{ _("Search") }}</h1>
99
<p>{% trans %}Please activate JavaScript to enable the search functionality.{% endtrans %}</p>
1010
</div>
1111
</noscript>
12+
{%- set search_input_id="search-input-results-page" -%}
1213
{% include "../components/search-field.html" %}
1314
<div id="search-results"></div>
1415
</div>

0 commit comments

Comments
 (0)