diff --git a/css/pb.css b/css/pb.css index a4aafc8112a84471a0294b3e1e8006a3bb63c352..fbc50419b069cb473e1fa48b08aa6715be1af556 100644 --- a/css/pb.css +++ b/css/pb.css @@ -627,6 +627,13 @@ outline: none; } +.search__search_term::-webkit-search-cancel-button, +.search__search_term::-webkit-search-decoration, +.search__search_term::-webkit-search-results-button, +.search__search_term::-webkit-search-results-decoration { + display: none; +} + .search__search-bar { position: relative; height: 50px; @@ -644,6 +651,16 @@ inset-inline-end: 30px; } +.search__search-clear { + position: absolute; + top: 0; + height: 100%; + cursor: pointer; + border: none; + background: none; + inset-inline-end: 60px; +} + .search__search_term::placeholder { display: flex; align-items: center; diff --git a/images/cross--dark-color-scheme.svg b/images/cross--dark-color-scheme.svg new file mode 100644 index 0000000000000000000000000000000000000000..6d0119f6389a9878f80452fc7816ec83c2d12952 --- /dev/null +++ b/images/cross--dark-color-scheme.svg @@ -0,0 +1,3 @@ +<svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#FFF" > + <path d="M1.293 1.293a1 1 0 0 1 1.414 0L8 6.586l5.293-5.293a1 1 0 1 1 1.414 1.414L9.414 8l5.293 5.293a1 1 0 0 1-1.414 1.414L8 9.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L6.586 8 1.293 2.707a1 1 0 0 1 0-1.414z"/> +</svg> diff --git a/images/cross.svg b/images/cross.svg new file mode 100644 index 0000000000000000000000000000000000000000..11daaf2bc3653fb93ebf61a78b67847697a91320 --- /dev/null +++ b/images/cross.svg @@ -0,0 +1,3 @@ +<svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#75767B" > + <path d="M1.293 1.293a1 1 0 0 1 1.414 0L8 6.586l5.293-5.293a1 1 0 1 1 1.414 1.414L9.414 8l5.293 5.293a1 1 0 0 1-1.414 1.414L8 9.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L6.586 8 1.293 2.707a1 1 0 0 1 0-1.414z"/> +</svg> diff --git a/sveltejs/public/build/bundle.js b/sveltejs/public/build/bundle.js index c7a30c9f188e28939a4dd6825e5095a90f3c00ee..7f06822dadab7e05705d0149813941bcb051c961 100644 Binary files a/sveltejs/public/build/bundle.js and b/sveltejs/public/build/bundle.js differ diff --git a/sveltejs/public/build/bundle.js.map b/sveltejs/public/build/bundle.js.map index ca335be89d7be0d9aa159df912a03b3f3c441430..34fd1b2813a25d81de76e4634704b7315f539208 100644 Binary files a/sveltejs/public/build/bundle.js.map and b/sveltejs/public/build/bundle.js.map differ diff --git a/sveltejs/src/Search/Search.svelte b/sveltejs/src/Search/Search.svelte index 97d8fd9e1c61f222c9a53f9ce86bb5be7d8b6027..75c93cb29611c19acf7b1d272f718c399db95e89 100644 --- a/sveltejs/src/Search/Search.svelte +++ b/sveltejs/src/Search/Search.svelte @@ -136,6 +136,12 @@ onAdvancedFilter(); } + function clearText() { + $searchString = ''; + onSearch(); + document.getElementById('pb-text').focus(); + } + /** * Actions performed when clicking filter resets such as "recommended" * @param {string} maintenanceId @@ -174,7 +180,29 @@ name="text" bind:value={$searchString} on:keyup={Drupal.debounce(onSearch, 250, false)} + on:keydown={(e) => { + if (e.key === 'Escape') { + e.preventDefault(); + clearText(); + } + }} /> + {#if $searchString} + <button + class="search__search-clear" + id="clear-text" + type="button" + on:click={clearText} + aria-label={Drupal.t('Clear search text')} + > + <img + src="{FULL_MODULE_PATH}/images/cross{DARK_COLOR_SCHEME + ? '--dark-color-scheme' + : ''}.svg" + alt="" + /> + </button> + {/if} <img class="search__search-icon" id="search-icon" diff --git a/tests/src/FunctionalJavascript/ProjectBrowserUiTest.php b/tests/src/FunctionalJavascript/ProjectBrowserUiTest.php index cd9a0a73a2fcbd99d173c5852112068d7c476ff8..34889d352fb112673dc1a19beffff2fd831abd04 100644 --- a/tests/src/FunctionalJavascript/ProjectBrowserUiTest.php +++ b/tests/src/FunctionalJavascript/ProjectBrowserUiTest.php @@ -974,4 +974,40 @@ class ProjectBrowserUiTest extends WebDriverTestBase { $this->assertFalse($ui_install_input->hasAttribute('disabled')); } + /** + * Tests that we can clear search results with one click. + */ + function testClearKeywordSearch() { + $page = $this->getSession()->getPage(); + $this->assertSession(); + $this->drupalGet('admin/modules/browse'); + $this->svelteInitHelper('css', '.pb-search-results'); + + // Get the original result count. + $results = $page->find('css', '.pb-search-results'); + $script = "document.querySelector('.pb-search-results').textContent.includes('Results')"; + $this->getSession()->wait(10000, $script); + $this->assertNotEmpty($results); + $original_text = $results->getText(); + $this->assertNotEmpty($original_text); + + // Search for something to change it. + $this->inputSearchField('abcdefghijklmnop'); + $results = $page->find('css', '.pb-search-results'); + $this->assertNotEmpty($results); + $new_text = $results->getText(); + $this->assertNotSame($original_text, $new_text); + + // Remove the search text and make sure it auto-updates. + // Use our clear search button to do it. + // Clearing it should bring us back to the original value. + $clear_button = $page->find('css', '.search__search-clear'); + $this->assertNotEmpty($clear_button); + $clear_button->click(); + $results = $page->find('css', '.pb-search-results'); + $this->assertNotEmpty($results); + $final_text = $results->getText(); + $this->assertEquals($original_text, $final_text); + } + }