Skip to content

Commit dc87ad0

Browse files
feat(Search): Use Vite asset imports for cancel and suggestion icons
Refactors Search and SearchAutocomplete components to use Vite's ?url import suffix for SVG icons used in CSS (icon-close.svg and icon-autocomplete-search-suggestion.svg). This ensures that: Vite bundles and hashes these assets correctly. CSS url() references are resolved to the correct, hashed asset paths at build time. Icons are reliably displayed when components are consumed by other applications. The implementation uses CSS Custom Properties to pass the Vite-generated asset URLs from the Svelte script scope to the CSS style scope. This addresses issues where relative paths in <style> tags were not being correctly resolved at runtime in consuming applications.
1 parent f4155fc commit dc87ad0

File tree

2 files changed

+47
-40
lines changed

2 files changed

+47
-40
lines changed

src/lib/components/ui/Search.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { browser } from "$app/environment";
44
import { onMount } from "svelte";
55
import IconSearch from "$lib/icons/IconSearch.svelte";
6+
import closeIconUrl from "$lib/assets/govuk_publishing_components/images/icon-close.svg?url";
67
78
// SSR-safe HTML sanitizer: no-op on server
89
let sanitize = $state<(html: string) => string>((html) => html);
@@ -216,6 +217,7 @@
216217
: undefined}
217218
autocorrect={correctionValue}
218219
autocapitalize={correctionValue}
220+
style={`--cancel-icon: url("${closeIconUrl}")`}
219221
/>
220222
</div>
221223
<div class="gem-c-search__item gem-c-search__submit-wrapper">
@@ -358,8 +360,7 @@
358360
359361
.gem-c-search__input[type="search"]::-webkit-search-cancel-button {
360362
-webkit-appearance: none;
361-
/* Use a relative path so Vite bundles the asset */
362-
background-image: url(../../assets/govuk_publishing_components/images/icon-close.svg);
363+
background-image: var(--cancel-icon);
363364
background-position: center;
364365
background-repeat: no-repeat;
365366
cursor: pointer;

src/lib/components/ui/SearchAutocomplete.svelte

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import Search from "$lib/components/ui/Search.svelte"; // Base component
55
import "accessible-autocomplete/dist/accessible-autocomplete.min.css";
66
import { browser } from "$app/environment";
7+
import suggestionIconUrl from "$lib/assets/govuk_publishing_components/images/icon-autocomplete-search-suggestion.svg?url";
8+
import closeIconUrl from "$lib/assets/govuk_publishing_components/images/icon-close.svg?url"; // Import for the cancel button
9+
710
811
// SSR-safe HTML sanitizer: no-op on server
912
let sanitize: (html: string) => string = (html) => html;
@@ -341,42 +344,45 @@
341344
// autocompleteInputElement,
342345
// ); // Updated log
343346
344-
// Post-initialisation tweaks
345-
if (autocompleteInputElement) {
346-
// Post-init: dynamically show a 'too-short' warning when the user types fewer than minLength characters
347-
// Find the dropdown menu <ul> generated by accessible-autocomplete
348-
const suggestionsMenu = containerElement.querySelector<HTMLUListElement>(
349-
".gem-c-search-with-autocomplete__menu",
350-
);
351-
// Listen for input changes on the autocomplete field
352-
autocompleteInputElement.addEventListener("input", () => {
353-
const val = autocompleteInputElement.value;
354-
// Remove any existing 'too-short' warning before adding a new one to ensure we don't accumulate multiple warning items.
355-
suggestionsMenu
356-
?.querySelector(".gem-c-search-with-autocomplete__option--too-short")
357-
?.remove();
358-
if (val.length < minLength) {
359-
// Force the menu open so the warning is shown
360-
autocompleteInputElement.setAttribute("aria-expanded", "true");
361-
suggestionsMenu?.classList.add(
362-
"gem-c-search-with-autocomplete__menu--visible",
347+
// Post-initialisation tweaks
348+
if (autocompleteInputElement) {
349+
// Post-init: dynamically show a 'too-short' warning when the user types fewer than minLength characters
350+
// Find the dropdown menu <ul> generated by accessible-autocomplete
351+
const suggestionsMenu =
352+
containerElement.querySelector<HTMLUListElement>(
353+
".gem-c-search-with-autocomplete__menu",
363354
);
364-
suggestionsMenu?.classList.remove(
365-
"gem-c-search-with-autocomplete__menu--hidden",
366-
);
367-
// Create a new <li> element with the warning text. Classes match the library's own suggestion items (so it looks and behaves consistently). Set role="option" and aria-disabled="true" for accessibility
368-
const li = document.createElement("li");
369-
li.className =
370-
"gem-c-search-with-autocomplete__option gem-c-search-with-autocomplete__option--too-short";
371-
li.setAttribute("role", "option");
372-
li.setAttribute("aria-disabled", "true");
373-
li.textContent = tooShort(minLength);
374-
// Insert the warning at the top of the suggestions list menu
375-
suggestionsMenu?.prepend(li);
376-
}
377-
});
378-
autocompleteInputElement.setAttribute("type", "search"); // Ensure input type is search
379-
// autocompleteInputElement.classList.add("autocomplete__input"); // Add specific class if needed
355+
// Listen for input changes on the autocomplete field
356+
autocompleteInputElement.addEventListener("input", () => {
357+
const val = autocompleteInputElement.value;
358+
// Remove any existing 'too-short' warning before adding a new one to ensure we don't accumulate multiple warning items.
359+
suggestionsMenu
360+
?.querySelector(
361+
".gem-c-search-with-autocomplete__option--too-short",
362+
)
363+
?.remove();
364+
if (val.length < minLength) {
365+
// Force the menu open so the warning is shown
366+
autocompleteInputElement.setAttribute("aria-expanded", "true");
367+
suggestionsMenu?.classList.add(
368+
"gem-c-search-with-autocomplete__menu--visible",
369+
);
370+
suggestionsMenu?.classList.remove(
371+
"gem-c-search-with-autocomplete__menu--hidden",
372+
);
373+
// Create a new <li> element with the warning text. Classes match the library's own suggestion items (so it looks and behaves consistently). Set role="option" and aria-disabled="true" for accessibility
374+
const li = document.createElement("li");
375+
li.className =
376+
"gem-c-search-with-autocomplete__option gem-c-search-with-autocomplete__option--too-short";
377+
li.setAttribute("role", "option");
378+
li.setAttribute("aria-disabled", "true");
379+
li.textContent = tooShort(minLength);
380+
// Insert the warning at the top of the suggestions list menu
381+
suggestionsMenu?.prepend(li);
382+
}
383+
});
384+
autocompleteInputElement.setAttribute("type", "search"); // Ensure input type is search
385+
// autocompleteInputElement.classList.add("autocomplete__input"); // Add specific class if needed
380386
381387
// Add Enter key workaround from original JS
382388
autocompleteInputElement.addEventListener("keydown", (e) => {
@@ -426,6 +432,7 @@
426432
data-source-key={source_key}
427433
data-source-property={source_property}
428434
{...outerDataAttributes}
435+
style={`--suggestion-icon: url("${suggestionIconUrl}"); --cancel-icon: url("${closeIconUrl}")`}
429436
>
430437
<!-- Render the base Search component initially -->
431438
<!-- accessible-autocomplete will enhance the input inside it -->
@@ -546,9 +553,8 @@
546553
height: 40px;
547554
margin-right: 10px;
548555
flex: none;
549-
/* Use relative paths so Vite bundles the asset */
550-
mask-image: url(../../assets/govuk_publishing_components/images/icon-autocomplete-search-suggestion.svg);
551-
-webkit-mask-image: url(../../assets/govuk_publishing_components/images/icon-autocomplete-search-suggestion.svg);
556+
mask-image: var(--suggestion-icon);
557+
-webkit-mask-image: var(--suggestion-icon);
552558
background-color: #505a5f;
553559
}
554560

0 commit comments

Comments
 (0)