@communitiesuk/svelte-component-library 0.1.18 → 0.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +30 -6
  2. package/dist/assets/css/base.css +9 -0
  3. package/dist/assets/css/code-block.css +116 -0
  4. package/dist/assets/css/components.css +47 -0
  5. package/dist/assets/css/fonts.css +19 -0
  6. package/dist/assets/css/govuk-additional.css +142 -0
  7. package/dist/assets/css/govuk-frontend.min.css +2 -2
  8. package/dist/assets/css/moduk.css +1 -0
  9. package/dist/assets/css/moj-frontend.min copy.css +4108 -0
  10. package/dist/assets/css/moj-frontend.min.css +2 -0
  11. package/dist/assets/css/moj-frontend.min.css.map +1 -0
  12. package/dist/assets/css/utilities.css +0 -0
  13. package/dist/assets/images/govuk-crest.svg +1 -1
  14. package/dist/assets/js/govuk-frontend.min.js +1 -0
  15. package/dist/assets/js/moj-frontend.min.js +1 -0
  16. package/dist/assets/rebrand/images/favicon.ico +0 -0
  17. package/dist/assets/rebrand/images/favicon.svg +1 -0
  18. package/dist/assets/rebrand/images/govuk-crest.svg +1 -0
  19. package/dist/assets/rebrand/images/govuk-icon-180.png +0 -0
  20. package/dist/assets/rebrand/images/govuk-icon-192.png +0 -0
  21. package/dist/assets/rebrand/images/govuk-icon-512.png +0 -0
  22. package/dist/assets/rebrand/images/govuk-icon-mask.svg +1 -0
  23. package/dist/assets/rebrand/images/govuk-opengraph-image.png +0 -0
  24. package/dist/assets/rebrand/manifest.json +39 -0
  25. package/dist/components/data-vis/line-chart/Line.svelte +48 -40
  26. package/dist/components/data-vis/line-chart/Line.svelte.d.ts +6 -4
  27. package/dist/components/data-vis/line-chart/LineChart.svelte +145 -36
  28. package/dist/components/data-vis/line-chart/LineChart.svelte.d.ts +25 -9
  29. package/dist/components/data-vis/line-chart/Lines.svelte +10 -23
  30. package/dist/components/data-vis/line-chart/Lines.svelte.d.ts +8 -4
  31. package/dist/components/data-vis/line-chart/Marker.svelte +31 -5
  32. package/dist/components/data-vis/line-chart/Marker.svelte.d.ts +6 -2
  33. package/dist/components/data-vis/line-chart/SeriesLabel.svelte +7 -8
  34. package/dist/components/data-vis/line-chart/SeriesLabel.svelte.d.ts +2 -2
  35. package/dist/components/data-vis/line-chart/ValueLabel.svelte +26 -34
  36. package/dist/components/data-vis/line-chart/ValueLabel.svelte.d.ts +8 -4
  37. package/dist/components/data-vis/map/Map.svelte +299 -71
  38. package/dist/components/data-vis/map/Map.svelte.d.ts +39 -12
  39. package/dist/components/data-vis/map/NonStandardControls.svelte +10 -1
  40. package/dist/components/data-vis/map/NonStandardControls.svelte.d.ts +12 -11
  41. package/dist/components/data-vis/map/Tooltip.svelte +3 -4
  42. package/dist/components/data-vis/map/Tooltip.svelte.d.ts +0 -2
  43. package/dist/components/data-vis/map/mapUtils.d.ts +2 -0
  44. package/dist/components/data-vis/map/mapUtils.js +50 -0
  45. package/dist/components/data-vis/table/Table.svelte +28 -40
  46. package/dist/components/data-vis/table/Table.svelte.d.ts +0 -2
  47. package/dist/components/layout/Breadcrumbs.svelte +10 -12
  48. package/dist/components/layout/Breadcrumbs.svelte.d.ts +1 -0
  49. package/dist/components/layout/Footer.svelte +69 -4
  50. package/dist/components/layout/Footer.svelte.d.ts +3 -0
  51. package/dist/components/layout/Header.svelte +56 -16
  52. package/dist/components/layout/Header.svelte.d.ts +1 -0
  53. package/dist/components/layout/InternalHeader.svelte +155 -150
  54. package/dist/components/layout/InternalHeader.svelte.d.ts +1 -0
  55. package/dist/components/ui/Button.svelte +78 -4
  56. package/dist/components/ui/Button.svelte.d.ts +2 -0
  57. package/dist/components/ui/CookieBanner.svelte +356 -0
  58. package/dist/components/ui/CookieBanner.svelte.d.ts +18 -0
  59. package/dist/components/ui/FilterPanel.svelte +167 -158
  60. package/dist/components/ui/FilterPanel.svelte.d.ts +2 -0
  61. package/dist/components/ui/Masthead.svelte +35 -23
  62. package/dist/components/ui/Masthead.svelte.d.ts +2 -0
  63. package/dist/components/ui/PostcodeOrAreaSearch.svelte +200 -0
  64. package/dist/components/ui/PostcodeOrAreaSearch.svelte.d.ts +37 -0
  65. package/dist/components/ui/Search.svelte +2 -2
  66. package/dist/components/ui/SearchAutocomplete.svelte +104 -14
  67. package/dist/components/ui/SearchAutocomplete.svelte.d.ts +4 -0
  68. package/dist/data/IMD2019.json +32846 -0
  69. package/dist/data/places.csv +20039 -0
  70. package/dist/data/places.json +100192 -0
  71. package/dist/data/svgFontDimensions.json +90 -0
  72. package/dist/data/testData.json +52632 -0
  73. package/dist/index.d.ts +2 -0
  74. package/dist/index.js +2 -0
  75. package/dist/package-wrapping/BaseInformation.svelte +0 -33
  76. package/dist/package-wrapping/SidebarContainer.svelte +0 -7
  77. package/dist/utils/area-search/geoConfig.d.ts +435 -0
  78. package/dist/utils/area-search/geoConfig.js +291 -0
  79. package/dist/utils/cookiesNavigation.d.ts +44 -0
  80. package/dist/utils/cookiesNavigation.js +63 -0
  81. package/dist/utils/data-transformations/convert-csv-to-json-proper.cjs +88 -0
  82. package/dist/utils/data-transformations/convert-csv-to-json-proper.d.cts +1 -0
  83. package/dist/utils/data-transformations/convertCSV.d.ts +6 -0
  84. package/dist/utils/data-transformations/convertCSV.js +40 -21
  85. package/dist/utils/text-string-conversion/textStringConversion.d.ts +6 -0
  86. package/dist/utils/text-string-conversion/textStringConversion.js +10 -0
  87. package/package.json +18 -7
  88. package/dist/components/ui/Breadcrumbs.svelte +0 -198
  89. package/dist/components/ui/Breadcrumbs.svelte.d.ts +0 -24
  90. package/dist/components/ui/Footer.svelte +0 -171
  91. package/dist/components/ui/Footer.svelte.d.ts +0 -30
  92. package/dist/components/ui/Header.svelte +0 -43
  93. package/dist/components/ui/Header.svelte.d.ts +0 -7
  94. package/dist/components/ui/ServiceNavigation.svelte +0 -143
  95. package/dist/components/ui/ServiceNavigation.svelte.d.ts +0 -13
  96. package/dist/components/ui/SideNavigation.svelte +0 -346
  97. package/dist/components/ui/SideNavigation.svelte.d.ts +0 -25
@@ -0,0 +1,200 @@
1
+ <script lang="ts">
2
+ import SearchAutocomplete from "./SearchAutocomplete.svelte";
3
+ import { capitalise } from "./../../utils/text-string-conversion/textStringConversion";
4
+ import {
5
+ geoNames,
6
+ geoCodesLookup,
7
+ essGeocodes,
8
+ } from "./../../utils/area-search/geoConfig";
9
+ import defaultPlacesData from "./../../data/places.json";
10
+
11
+ // --- Define Types ---
12
+ type SuggestionObject = { label: string; value: any; [key: string]: any };
13
+ type Suggestion = string | SuggestionObject;
14
+
15
+ type Place = SuggestionObject & {
16
+ areacd: string;
17
+ areanm: string;
18
+ parentcd?: string;
19
+ group?: string;
20
+ };
21
+
22
+ type Props = {
23
+ // Data source configuration
24
+ customPlacesData?: any[]; // Custom places data (JSON format: [{areacd, areanm, parentcd}])
25
+ essOnly?: boolean; // Whether to filter to essential geocodes only
26
+
27
+ // Custom lookup functions/data (for flexibility)
28
+ customTypeLookup?: Record<
29
+ string,
30
+ { label: string; plural: string; childGroup?: boolean }
31
+ >;
32
+ customEssGeocodes?: string[];
33
+ customGetTypeLabel?: (type: string) => string;
34
+
35
+ // Postcode API configuration
36
+ postcodeApiUrl?: string;
37
+ postcodeApiKey?: string; // Key in response containing suggestions
38
+ postcodeApiProperty?: string; // Property to extract from API objects
39
+ postcodeApiPathBased?: boolean; // Whether the API uses path-based URLs
40
+
41
+ // Source selection logic
42
+ customSourceSelector?: (
43
+ query: string,
44
+ options: Suggestion[],
45
+ ) => "api" | "options";
46
+
47
+ // Pass-through props to SearchAutocomplete
48
+ selectedValue?: any;
49
+ label_text?: string;
50
+ button_text?: string;
51
+ name?: string;
52
+ placeholder?: string;
53
+ hint?: string;
54
+ size?: "large" | "";
55
+ on_govuk_blue?: boolean;
56
+ homepage?: boolean;
57
+ minLength?: number;
58
+ required?: boolean;
59
+ [key: string]: any; // Allow other props
60
+ };
61
+
62
+ let {
63
+ customPlacesData = undefined,
64
+ essOnly = false,
65
+ customTypeLookup = undefined,
66
+ customEssGeocodes = undefined,
67
+ customGetTypeLabel = undefined,
68
+ postcodeApiUrl = "https://api.postcodes.io/postcodes",
69
+ postcodeApiKey = "result",
70
+ postcodeApiProperty = "postcode",
71
+ postcodeApiPathBased = false,
72
+ customSourceSelector = undefined,
73
+ selectedValue = $bindable(),
74
+ label_text = "Search for a postcode or area",
75
+ button_text = "Search",
76
+ name = "location",
77
+ placeholder = "e.g. SW1A 1AA or Westminster",
78
+ hint = "Enter a UK postcode or area name",
79
+ size = "",
80
+ on_govuk_blue = false,
81
+ homepage = false,
82
+ minLength = 2,
83
+ required = false,
84
+ ...restProps
85
+ }: Props = $props();
86
+
87
+ // --- Use custom lookups or defaults ---
88
+ const typeLookup =
89
+ customTypeLookup && Object.keys(customTypeLookup).length > 0
90
+ ? customTypeLookup
91
+ : geoNames;
92
+ const essGeocodesArray =
93
+ customEssGeocodes && customEssGeocodes.length > 0
94
+ ? customEssGeocodes
95
+ : essGeocodes;
96
+
97
+ // --- Helper Functions ---
98
+ const getTypeLabel = (type: string) => {
99
+ // If custom function is provided and returns a non-null value, use it
100
+ if (customGetTypeLabel) {
101
+ const customLabel = customGetTypeLabel(type);
102
+ if (customLabel !== null && customLabel !== undefined) {
103
+ return customLabel;
104
+ }
105
+ }
106
+ // Otherwise use lookup table (custom or default)
107
+ return typeLookup[type]
108
+ ? typeLookup[type].label
109
+ : geoCodesLookup[type]?.label || type;
110
+ };
111
+
112
+ // Default source selector: use API for postcode-like inputs, options for area names
113
+ const defaultSourceSelector = (query: string, options: Suggestion[]) => {
114
+ // If input has 3+ chars and contains a digit, likely a postcode
115
+ return query.length >= 3 && /\d/.test(query) ? "api" : "options";
116
+ };
117
+
118
+ const sourceSelector = (query: string, options: Suggestion[]) => {
119
+ // If custom function is provided and returns a non-null value, use it
120
+ if (customSourceSelector) {
121
+ const customResult = customSourceSelector(query, options);
122
+ if (customResult !== null && customResult !== undefined) {
123
+ return customResult;
124
+ }
125
+ }
126
+ // Otherwise use default selector
127
+ return defaultSourceSelector(query, options);
128
+ };
129
+
130
+ // --- Process Places Data ---
131
+ const places = $derived.by(() => {
132
+ // Use custom data if provided and not empty, otherwise use default
133
+ let placesData =
134
+ customPlacesData && customPlacesData.length > 0
135
+ ? customPlacesData
136
+ : defaultPlacesData;
137
+
138
+ // Filter to essential geocodes if requested
139
+ if (essOnly) {
140
+ placesData = placesData.filter((p: any) =>
141
+ essGeocodesArray.includes(p.areacd.slice(0, 3)),
142
+ );
143
+ }
144
+
145
+ // Sort by area name
146
+ const sortedData = [...placesData].sort((a: any, b: any) =>
147
+ a.areanm.localeCompare(b.areanm),
148
+ );
149
+
150
+ // Create lookup for parent relationships
151
+ const lookup: Record<string, any> = {};
152
+ for (const p of sortedData) lookup[p.areacd] = p;
153
+
154
+ // Add group information and format for autocomplete
155
+ const processedPlaces: Place[] = sortedData.map((p: any) => {
156
+ const type = p.areacd.slice(0, 3);
157
+ const group =
158
+ type === "K02"
159
+ ? ""
160
+ : p.parentcd && lookup[p.parentcd]
161
+ ? `${capitalise(getTypeLabel(type))} in ${lookup[p.parentcd].areanm}`
162
+ : capitalise(getTypeLabel(type));
163
+
164
+ return {
165
+ areacd: p.areacd,
166
+ areanm: p.areanm,
167
+ parentcd: p.parentcd,
168
+ group,
169
+ label: p.areanm,
170
+ value: p.areacd,
171
+ };
172
+ });
173
+
174
+ return processedPlaces;
175
+ });
176
+
177
+ // --- Autocomplete Configuration ---
178
+ const autocompleteProps = $derived({
179
+ options: places,
180
+ source_url: postcodeApiUrl,
181
+ source_key: postcodeApiKey,
182
+ source_property: postcodeApiProperty,
183
+ pathBasedApi: postcodeApiPathBased,
184
+ groupKey: "group",
185
+ sourceSelector,
186
+ label_text,
187
+ button_text,
188
+ name,
189
+ placeholder,
190
+ hint,
191
+ size,
192
+ on_govuk_blue,
193
+ homepage,
194
+ minLength,
195
+ required,
196
+ ...restProps,
197
+ });
198
+ </script>
199
+
200
+ <SearchAutocomplete {...autocompleteProps} bind:selectedValue />
@@ -0,0 +1,37 @@
1
+ type SuggestionObject = {
2
+ label: string;
3
+ value: any;
4
+ [key: string]: any;
5
+ };
6
+ type Suggestion = string | SuggestionObject;
7
+ type Props = {
8
+ customPlacesData?: any[];
9
+ essOnly?: boolean;
10
+ customTypeLookup?: Record<string, {
11
+ label: string;
12
+ plural: string;
13
+ childGroup?: boolean;
14
+ }>;
15
+ customEssGeocodes?: string[];
16
+ customGetTypeLabel?: (type: string) => string;
17
+ postcodeApiUrl?: string;
18
+ postcodeApiKey?: string;
19
+ postcodeApiProperty?: string;
20
+ postcodeApiPathBased?: boolean;
21
+ customSourceSelector?: (query: string, options: Suggestion[]) => "api" | "options";
22
+ selectedValue?: any;
23
+ label_text?: string;
24
+ button_text?: string;
25
+ name?: string;
26
+ placeholder?: string;
27
+ hint?: string;
28
+ size?: "large" | "";
29
+ on_govuk_blue?: boolean;
30
+ homepage?: boolean;
31
+ minLength?: number;
32
+ required?: boolean;
33
+ [key: string]: any;
34
+ };
35
+ declare const PostcodeOrAreaSearch: import("svelte").Component<Props, {}, "selectedValue">;
36
+ type PostcodeOrAreaSearch = ReturnType<typeof PostcodeOrAreaSearch>;
37
+ export default PostcodeOrAreaSearch;
@@ -2,8 +2,8 @@
2
2
  import { clsx } from "clsx";
3
3
  import { browser } from "$app/environment";
4
4
  import { onMount } from "svelte";
5
- import IconSearch from "../../icons/IconSearch.svelte";
6
- import closeIconUrl from "../../assets/govuk_publishing_components/images/icon-close.svg?url";
5
+ import IconSearch from "./../../icons/IconSearch.svelte";
6
+ import closeIconUrl from "./../../assets/govuk_publishing_components/images/icon-close.svg?url";
7
7
 
8
8
  // SSR-safe HTML sanitizer: no-op on server
9
9
  let sanitize = $state<(html: string) => string>((html) => html);
@@ -4,15 +4,14 @@
4
4
  import Search from "./Search.svelte"; // Base component
5
5
  import "accessible-autocomplete/dist/accessible-autocomplete.min.css";
6
6
  import { browser } from "$app/environment";
7
- import suggestionIconUrl from "../../assets/govuk_publishing_components/images/icon-autocomplete-search-suggestion.svg?url";
8
- import closeIconUrl from "../../assets/govuk_publishing_components/images/icon-close.svg?url"; // Import for the cancel button
9
-
7
+ import suggestionIconUrl from "./../../assets/govuk_publishing_components/images/icon-autocomplete-search-suggestion.svg?url";
8
+ import closeIconUrl from "./../../assets/govuk_publishing_components/images/icon-close.svg?url"; // Import for the cancel button
10
9
 
11
10
  // SSR-safe HTML sanitizer: no-op on server
12
11
  let sanitize: (html: string) => string = (html) => html;
13
12
 
14
13
  // --- Define Props ---
15
- type SuggestionObject = { label: string; value: any };
14
+ type SuggestionObject = { label: string; value: any; [key: string]: any }; // Allow additional properties for grouping
16
15
  type Suggestion = string | SuggestionObject;
17
16
  type Props = {
18
17
  // User can supply either an options array or an API source
@@ -20,6 +19,12 @@
20
19
  source_url?: string; // Optional: URL for autocomplete suggestions
21
20
  source_key?: string; // Optional: Key in the JSON response containing suggestions array
22
21
  source_property?: string; // Property to extract from API objects
22
+ pathBasedApi?: boolean; // Whether to use path-based URLs (RESTful) instead of query parameters
23
+ groupKey?: string; // Optional: Key to group suggestions by (e.g., "region", "category")
24
+ sourceSelector?: (
25
+ query: string,
26
+ options: Suggestion[],
27
+ ) => "api" | "options"; // Function to determine which source to use
23
28
  outerClasses?: string; // Optional classes for the outer wrapper
24
29
  outerDataAttributes?: Record<string, string>; // Optional data attributes for the outer wrapper
25
30
  // Add other expected props passed down (e.g., size, on_govuk_blue, id, name etc.)
@@ -52,9 +57,12 @@
52
57
  source_url = undefined,
53
58
  source_key = undefined,
54
59
  source_property = undefined,
55
- size = "", // Default size from Search
60
+ pathBasedApi = false,
61
+ groupKey = undefined,
62
+ sourceSelector = undefined,
63
+ size = "",
56
64
  on_govuk_blue = false,
57
- homepage = false, // Added homepage prop handling
65
+ homepage = false,
58
66
  outerClasses = "",
59
67
  outerDataAttributes = {},
60
68
  id, // Pass down id
@@ -81,6 +89,12 @@
81
89
  let containerElement: HTMLDivElement; // bind:this target for the outer div
82
90
  let autocompleteInstance: { inputElement?: HTMLInputElement } | null = null; // To store instance if needed
83
91
 
92
+ // Track which source is currently being used for dynamic data attributes
93
+ let currentSource = $state<"api" | "options" | "auto">("auto");
94
+ let currentSourceUrl = $state<string | undefined>(undefined);
95
+ let currentSourceKey = $state<string | undefined>(undefined);
96
+ let currentSourceProperty = $state<string | undefined>(undefined);
97
+
84
98
  // --- Derived Values ---
85
99
  const wrapperClasses = $derived(
86
100
  clsx(
@@ -148,6 +162,12 @@
148
162
  query: string,
149
163
  populateResults: (results: string[]) => void,
150
164
  ) => {
165
+ // Update current source tracking
166
+ currentSource = "api";
167
+ currentSourceUrl = source_url;
168
+ currentSourceKey = source_key;
169
+ currentSourceProperty = source_property;
170
+
151
171
  if (!source_url || !source_key) {
152
172
  console.error(
153
173
  "SearchAutocomplete: source_url and source_key are required for API mode.",
@@ -155,8 +175,21 @@
155
175
  populateResults([]);
156
176
  return;
157
177
  }
158
- const url = new URL(source_url);
159
- url.searchParams.set("q", query);
178
+
179
+ // Construct URL based on pathBasedApi setting
180
+ let url: URL;
181
+ if (pathBasedApi) {
182
+ // For RESTful APIs like Zippopotam.us: append query to path
183
+ const baseUrl = source_url.endsWith("/")
184
+ ? source_url.slice(0, -1)
185
+ : source_url;
186
+ url = new URL(`${baseUrl}/${encodeURIComponent(query)}`);
187
+ } else {
188
+ // For query parameter APIs: add ?q=query
189
+ url = new URL(source_url);
190
+ url.searchParams.set("q", query);
191
+ }
192
+
160
193
  fetch(url, { headers: { Accept: "application/json" } })
161
194
  .then((response) => {
162
195
  if (!response.ok)
@@ -209,6 +242,12 @@
209
242
  query: string,
210
243
  populateResults: (results: Suggestion[]) => void,
211
244
  ) => {
245
+ // Update current source tracking
246
+ currentSource = "options";
247
+ currentSourceUrl = undefined;
248
+ currentSourceKey = undefined;
249
+ currentSourceProperty = undefined;
250
+
212
251
  if (!options) {
213
252
  populateResults([]);
214
253
  return;
@@ -227,6 +266,43 @@
227
266
  ? getResultsFromOptions
228
267
  : getResultsFromApi;
229
268
 
269
+ // Initialise current source tracking based on initial configuration
270
+ if (sourceSelector) {
271
+ currentSource = "auto"; // Will be determined dynamically
272
+ currentSourceUrl = source_url;
273
+ currentSourceKey = source_key;
274
+ currentSourceProperty = source_property;
275
+ } else if (useOptions) {
276
+ currentSource = "options";
277
+ currentSourceUrl = undefined;
278
+ currentSourceKey = undefined;
279
+ currentSourceProperty = undefined;
280
+ } else {
281
+ currentSource = "api";
282
+ currentSourceUrl = source_url;
283
+ currentSourceKey = source_key;
284
+ currentSourceProperty = source_property;
285
+ }
286
+
287
+ // If sourceSelector is provided, create a dynamic source function
288
+ const dynamicSourceFunction = sourceSelector
289
+ ? (query: string, populateResults: (results: Suggestion[]) => void) => {
290
+ const selectedSource = sourceSelector(query, options || []);
291
+ // Handle invalid returns by falling back to default logic
292
+ if (selectedSource === "api") {
293
+ getResultsFromApi(query, populateResults);
294
+ } else if (selectedSource === "options") {
295
+ getResultsFromOptions(query, populateResults);
296
+ } else {
297
+ // Fall back to default logic if invalid return value
298
+ sourceFunction(query, populateResults);
299
+ }
300
+ }
301
+ : null;
302
+
303
+ // Use dynamic source if available, otherwise fall back to original logic
304
+ const finalSourceFunction = dynamicSourceFunction || sourceFunction;
305
+
230
306
  // Define suggestion template function (sanitize and highlight)
231
307
  const suggestionTemplate = (result: Suggestion): string => {
232
308
  const displayLabel = typeof result === "string" ? result : result.label;
@@ -256,11 +332,17 @@
256
332
  html = `${before}<mark class="gem-c-search-with-autocomplete__suggestion-highlight">${match}</mark>${after}`;
257
333
  }
258
334
 
259
- // Match the GOV.UK structure
335
+ // Get group text if groupKey is provided and result is an object
336
+ const groupText =
337
+ groupKey && typeof result === "object" && result[groupKey]
338
+ ? ` <span class="gem-c-search-with-autocomplete__suggestion-group">${sanitize(String(result[groupKey]))}</span>`
339
+ : "";
340
+
341
+ // Match the GOV.UK structure with integrated group text
260
342
  return `
261
343
  <div class="gem-c-search-with-autocomplete__option-wrapper">
262
344
  <span class="gem-c-search-with-autocomplete__suggestion-icon"></span>
263
- <span class="gem-c-search-with-autocomplete__suggestion-text">${html}</span>
345
+ <span class="gem-c-search-with-autocomplete__suggestion-text">${html}${groupText}</span>
264
346
  </div>
265
347
  `;
266
348
  };
@@ -313,7 +395,7 @@
313
395
  id: searchInput.id, // Use the ID from the *rendered* Search input
314
396
  name: searchInput.name, // Use the name from the *rendered* Search input
315
397
  inputClasses: searchInput.classList, // Pass original classes directly
316
- source: sourceFunction,
398
+ source: finalSourceFunction,
317
399
  minLength: minLength,
318
400
  confirmOnBlur: confirmOnBlur,
319
401
  showNoOptionsFound: showNoOptionsFound,
@@ -428,9 +510,11 @@
428
510
  bind:this={containerElement}
429
511
  class={wrapperClasses}
430
512
  data-module="gem-search-with-autocomplete"
431
- data-source-url={source_url}
432
- data-source-key={source_key}
433
- data-source-property={source_property}
513
+ data-source-url={currentSourceUrl}
514
+ data-source-key={currentSourceKey}
515
+ data-source-property={currentSourceProperty}
516
+ data-group-key={groupKey}
517
+ data-current-source={currentSource}
434
518
  {...outerDataAttributes}
435
519
  style={`--suggestion-icon: url("${suggestionIconUrl}"); --cancel-icon: url("${closeIconUrl}")`}
436
520
  >
@@ -567,6 +651,12 @@
567
651
  background: none;
568
652
  }
569
653
 
654
+ .gem-c-search-with-autocomplete__suggestion-group {
655
+ opacity: 0.8;
656
+ font-size: smaller;
657
+ font-weight: normal;
658
+ }
659
+
570
660
  .gem-c-search-with-autocomplete.gem-c-search-with-autocomplete--large
571
661
  .gem-c-search-with-autocomplete__menu {
572
662
  margin-right: -50px;
@@ -2,6 +2,7 @@ import "accessible-autocomplete/dist/accessible-autocomplete.min.css";
2
2
  type SuggestionObject = {
3
3
  label: string;
4
4
  value: any;
5
+ [key: string]: any;
5
6
  };
6
7
  type Suggestion = string | SuggestionObject;
7
8
  type Props = {
@@ -9,6 +10,9 @@ type Props = {
9
10
  source_url?: string;
10
11
  source_key?: string;
11
12
  source_property?: string;
13
+ pathBasedApi?: boolean;
14
+ groupKey?: string;
15
+ sourceSelector?: (query: string, options: Suggestion[]) => "api" | "options";
12
16
  outerClasses?: string;
13
17
  outerDataAttributes?: Record<string, string>;
14
18
  size?: "large" | "";