@@ -49,7 +49,6 @@ function setupMobileToggle() {
4949 const isHidden = docNav . classList . contains ( 'hidden' ) ;
5050 docNav . classList . toggle ( 'hidden' ) ;
5151 const search = docNav . querySelector ( '.search' ) ;
52- // console.log(search);
5352 const searchHasResults = search . classList . contains ( 'has-results' ) ;
5453 if ( isHidden && searchHasResults ) {
5554 search . classList . remove ( 'mobile-hidden' ) ;
@@ -145,6 +144,72 @@ function setupSearch() {
145144 }
146145 } ) ;
147146 searchInput . addEventListener ( 'input' , onInputChange ) ;
147+ setupSearchKeymaps ( ) ;
148+ }
149+
150+ function setupSearchKeymaps ( ) {
151+ const searchInput = document . querySelector ( '#search input' ) ;
152+ // Keyboard shortcut indicator
153+ const searchKeys = document . createElement ( 'div' ) ;
154+ const modifierKeyPrefix = navigator . platform . includes ( 'Mac' ) ? '⌘' : 'Ctrl' ;
155+ searchKeys . setAttribute ( 'id' , 'search-keys' ) ;
156+ searchKeys . innerHTML = '<kbd>' + modifierKeyPrefix + '</kbd><kbd>k</kbd>' ;
157+ searchInput . parentElement ?. appendChild ( searchKeys ) ;
158+ searchInput . addEventListener ( 'focus' , ( ) => searchKeys . classList . add ( 'hide' ) ) ;
159+ searchInput . addEventListener ( 'blur' , ( ) => searchKeys . classList . remove ( 'hide' ) ) ;
160+ // Global shortcuts to focus searchInput
161+ document . addEventListener ( 'keydown' , ( ev ) => {
162+ if ( ev . key === '/' || ( ( ev . ctrlKey || ev . metaKey ) && ev . key === 'k' ) ) {
163+ ev . preventDefault ( ) ;
164+ searchInput . focus ( ) ;
165+ }
166+ } ) ;
167+ // Shortcuts while searchInput is focused
168+ let selectedIdx = - 1 ;
169+ function selectResult ( results , newIdx ) {
170+ if ( selectedIdx !== - 1 ) {
171+ results [ selectedIdx ] . classList . remove ( 'selected' ) ;
172+ }
173+ results [ newIdx ] . classList . add ( 'selected' ) ;
174+ results [ newIdx ] . scrollIntoView ( { behavior : 'smooth' , block : 'end' , inline : 'nearest' } ) ;
175+ selectedIdx = newIdx ;
176+ }
177+ searchInput . addEventListener ( 'keydown' , ( ev ) => {
178+ const searchResults = document . querySelectorAll ( '.search .result' ) ;
179+ switch ( ev . key ) {
180+ case 'Escape' :
181+ searchInput . blur ( ) ;
182+ break ;
183+ case 'Enter' :
184+ if ( ! searchResults . length || selectedIdx === - 1 ) break ;
185+ searchResults [ selectedIdx ] . querySelector ( 'a' ) . click ( ) ;
186+ break ;
187+ case 'ArrowDown' :
188+ ev . preventDefault ( ) ;
189+ if ( ! searchResults . length ) break ;
190+ if ( selectedIdx >= searchResults . length - 1 ) {
191+ // Cycle to first if last is selected
192+ selectResult ( searchResults , 0 ) ;
193+ } else {
194+ // Select next
195+ selectResult ( searchResults , selectedIdx + 1 ) ;
196+ }
197+ break ;
198+ case 'ArrowUp' :
199+ ev . preventDefault ( ) ;
200+ if ( ! searchResults . length ) break ;
201+ if ( selectedIdx <= 0 ) {
202+ // Cycle to last if first is selected (or select it if none is selcted yet)
203+ selectResult ( searchResults , searchResults . length - 1 ) ;
204+ } else {
205+ // Select previous
206+ selectResult ( searchResults , selectedIdx - 1 ) ;
207+ }
208+ break ;
209+ default :
210+ selectedIdx = - 1 ;
211+ }
212+ } ) ;
148213}
149214
150215function createSearchResult ( data ) {
@@ -194,11 +259,3 @@ function debounce(func, timeout) {
194259 timer = setTimeout ( next , timeout > 0 ? timeout : 300 ) ;
195260 } ;
196261}
197-
198- document . addEventListener ( 'keypress' , ( ev ) => {
199- if ( ev . key == '/' ) {
200- const search = document . getElementById ( 'search' ) ;
201- ev . preventDefault ( ) ;
202- search . focus ( ) ;
203- }
204- } ) ;
0 commit comments