@onsvisual/svelte-components 1.0.37 → 1.0.38

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 (226) hide show
  1. package/README.md +24 -24
  2. package/dist/css/main.css +513 -513
  3. package/dist/datavis/BarChart/BarChart.stories.svelte +84 -84
  4. package/dist/datavis/BarChart/docs/component.md +19 -19
  5. package/dist/datavis/Chart/Chart.stories.svelte +128 -128
  6. package/dist/datavis/Chart/docs/component.md +31 -31
  7. package/dist/datavis/Chart/docs/example.md +28 -28
  8. package/dist/datavis/ColumnChart/ColumnChart.stories.svelte +84 -84
  9. package/dist/datavis/ColumnChart/docs/component.md +19 -19
  10. package/dist/datavis/DataCard/DataCard.stories.svelte +45 -45
  11. package/dist/datavis/DataCard/DataCard.svelte +70 -70
  12. package/dist/datavis/DataCard/Sparkline.svelte +117 -117
  13. package/dist/datavis/DataCard/docs/component.md +20 -18
  14. package/dist/datavis/DataCard/docs/example.md +25 -25
  15. package/dist/datavis/DotPlotChart/DotPlotChart.stories.svelte +40 -40
  16. package/dist/datavis/DotPlotChart/docs/component.md +19 -19
  17. package/dist/datavis/LineChart/LineChart.stories.svelte +64 -64
  18. package/dist/datavis/LineChart/docs/component.md +31 -31
  19. package/dist/datavis/ScatterChart/ScatterChart.stories.svelte +55 -55
  20. package/dist/datavis/ScatterChart/docs/component.md +53 -53
  21. package/dist/datavis/Table/Table.stories.svelte +48 -48
  22. package/dist/datavis/Table/Table.svelte +161 -161
  23. package/dist/datavis/Table/docs/component.md +20 -20
  24. package/dist/datavis/demo-data/data-scatter.js +40 -40
  25. package/dist/datavis/demo-data/data.js +18 -18
  26. package/dist/datavis/intro.mdx +21 -21
  27. package/dist/decorators/Blockquote/Blockquote.stories.svelte +25 -25
  28. package/dist/decorators/Blockquote/Blockquote.svelte +27 -27
  29. package/dist/decorators/Blockquote/docs/component.md +10 -10
  30. package/dist/decorators/Divider/Divider.stories.svelte +29 -29
  31. package/dist/decorators/Divider/Divider.svelte +52 -52
  32. package/dist/decorators/Divider/docs/component.md +12 -12
  33. package/dist/decorators/Em/Em.stories.svelte +30 -30
  34. package/dist/decorators/Em/Em.svelte +58 -58
  35. package/dist/decorators/Em/docs/component.md +12 -12
  36. package/dist/decorators/Icon/Icon.stories.svelte +27 -27
  37. package/dist/decorators/Icon/Icon.svelte +93 -93
  38. package/dist/decorators/Icon/docs/component.md +10 -10
  39. package/dist/decorators/Indent/Indent.stories.svelte +22 -22
  40. package/dist/decorators/Indent/Indent.svelte +3 -3
  41. package/dist/decorators/Indent/docs/component.md +10 -10
  42. package/dist/index.js +86 -86
  43. package/dist/inputs/Button/Button.stories.svelte +70 -70
  44. package/dist/inputs/Button/Button.svelte +147 -147
  45. package/dist/inputs/Button/Button.svelte.d.ts +2 -2
  46. package/dist/inputs/Button/docs/component.md +17 -17
  47. package/dist/inputs/ButtonGroup/ButtonGroup.stories.svelte +40 -40
  48. package/dist/inputs/ButtonGroup/ButtonGroup.svelte +57 -57
  49. package/dist/inputs/ButtonGroup/ButtonGroupItem.svelte +101 -101
  50. package/dist/inputs/ButtonGroup/docs/component.md +23 -21
  51. package/dist/inputs/Checkbox/Checkbox.stories.svelte +34 -34
  52. package/dist/inputs/Checkbox/Checkbox.svelte +180 -180
  53. package/dist/inputs/Checkbox/docs/component.md +14 -14
  54. package/dist/inputs/Checkboxes/Checkboxes.stories.svelte +34 -34
  55. package/dist/inputs/Checkboxes/Checkboxes.svelte +62 -62
  56. package/dist/inputs/Checkboxes/docs/component.md +20 -20
  57. package/dist/inputs/Checkboxes/docs/example.md +16 -16
  58. package/dist/inputs/Dropdown/Dropdown.stories.svelte +54 -54
  59. package/dist/inputs/Dropdown/Dropdown.svelte +66 -66
  60. package/dist/inputs/Dropdown/docs/component.md +22 -22
  61. package/dist/inputs/ErrorPanel/ErrorPanel.stories.svelte +25 -25
  62. package/dist/inputs/ErrorPanel/ErrorPanel.svelte +24 -24
  63. package/dist/inputs/ErrorPanel/docs/component.md +14 -14
  64. package/dist/inputs/ErrorSummary/ErrorSummary.stories.svelte +34 -34
  65. package/dist/inputs/ErrorSummary/ErrorSummary.svelte +47 -47
  66. package/dist/inputs/ErrorSummary/docs/component.md +17 -17
  67. package/dist/inputs/ErrorSummary/docs/example.md +12 -12
  68. package/dist/inputs/Input/Input.stories.svelte +73 -73
  69. package/dist/inputs/Input/Input.svelte +151 -151
  70. package/dist/inputs/Input/Input.svelte.d.ts +2 -2
  71. package/dist/inputs/Input/docs/component.md +16 -16
  72. package/dist/inputs/Radios/Radio.svelte +90 -90
  73. package/dist/inputs/Radios/Radios.stories.svelte +51 -51
  74. package/dist/inputs/Radios/Radios.svelte +62 -62
  75. package/dist/inputs/Radios/docs/component.md +24 -24
  76. package/dist/inputs/Radios/docs/example.md +21 -21
  77. package/dist/inputs/Select/Select.stories.svelte +63 -63
  78. package/dist/inputs/Select/Select.svelte +326 -326
  79. package/dist/inputs/Select/Select.svelte.d.ts +2 -2
  80. package/dist/inputs/Select/docs/component.md +27 -27
  81. package/dist/inputs/Textarea/Textarea.stories.svelte +40 -40
  82. package/dist/inputs/Textarea/Textarea.svelte +113 -113
  83. package/dist/inputs/Textarea/Textarea.svelte.d.ts +2 -2
  84. package/dist/inputs/Textarea/docs/component.md +16 -16
  85. package/dist/inputs/Toolbar/HelpModal.svelte +234 -234
  86. package/dist/inputs/Toolbar/ToolControl.svelte +23 -23
  87. package/dist/inputs/Toolbar/ToolControls.svelte +9 -9
  88. package/dist/inputs/Toolbar/Toolbar.stories.svelte +148 -148
  89. package/dist/inputs/Toolbar/Toolbar.svelte +70 -70
  90. package/dist/inputs/Toolbar/ToolbarButton.svelte +184 -184
  91. package/dist/inputs/Toolbar/ToolbarDivider.svelte +29 -29
  92. package/dist/inputs/Toolbar/ToolbarIcon.svelte +106 -106
  93. package/dist/inputs/Toolbar/ToolbarsContainer.svelte +69 -69
  94. package/dist/inputs/Toolbar/docs/component.md +101 -99
  95. package/dist/intro.mdx +66 -66
  96. package/dist/js/menuOptions.js +14 -14
  97. package/dist/js/utils.js +133 -133
  98. package/dist/js/withParams.js +43 -43
  99. package/dist/layout/Accordion/Accordion.stories.svelte +30 -30
  100. package/dist/layout/Accordion/Accordion.svelte +55 -55
  101. package/dist/layout/Accordion/AccordionItem.svelte +51 -51
  102. package/dist/layout/Accordion/accordion.js +64 -64
  103. package/dist/layout/Accordion/details.js +83 -83
  104. package/dist/layout/Accordion/docs/component.md +19 -19
  105. package/dist/layout/AnalyticsBanner/AnalyticsBanner.stories.svelte +16 -16
  106. package/dist/layout/AnalyticsBanner/AnalyticsBanner.svelte +314 -314
  107. package/dist/layout/AnalyticsBanner/docs/component.md +44 -44
  108. package/dist/layout/BackLink/BackLink.stories.svelte +16 -16
  109. package/dist/layout/BackLink/BackLink.svelte +30 -30
  110. package/dist/layout/BackLink/docs/component.md +12 -12
  111. package/dist/layout/Breadcrumb/Breadcrumb.stories.svelte +31 -31
  112. package/dist/layout/Breadcrumb/Breadcrumb.svelte +69 -69
  113. package/dist/layout/Breadcrumb/docs/component.md +15 -15
  114. package/dist/layout/Card/Card.stories.svelte +39 -39
  115. package/dist/layout/Card/Card.svelte +127 -127
  116. package/dist/layout/Card/docs/component.md +14 -14
  117. package/dist/layout/Card/docs/eg-images.md +27 -27
  118. package/dist/layout/Card/docs/eg-links.md +12 -12
  119. package/dist/layout/Card/docs/eg-spans.md +12 -12
  120. package/dist/layout/Contents/Contents.stories.svelte +27 -27
  121. package/dist/layout/Contents/Contents.svelte +51 -51
  122. package/dist/layout/Contents/docs/component.md +18 -18
  123. package/dist/layout/DescriptionList/DescriptionList.stories.svelte +22 -22
  124. package/dist/layout/DescriptionList/DescriptionList.svelte +59 -59
  125. package/dist/layout/DescriptionList/docs/component.md +18 -18
  126. package/dist/layout/Details/Details.stories.svelte +32 -32
  127. package/dist/layout/Details/Details.svelte +75 -75
  128. package/dist/layout/Details/docs/component.md +14 -14
  129. package/dist/layout/DocumentList/Document.svelte +103 -103
  130. package/dist/layout/DocumentList/DocumentList.stories.svelte +88 -88
  131. package/dist/layout/DocumentList/DocumentList.svelte +33 -33
  132. package/dist/layout/DocumentList/docs/component.md +28 -28
  133. package/dist/layout/DocumentList/docs/example.md +23 -23
  134. package/dist/layout/ErrorPage/ErrorPage.stories.svelte +18 -18
  135. package/dist/layout/ErrorPage/ErrorPage.svelte +48 -48
  136. package/dist/layout/ErrorPage/docs/component.md +13 -13
  137. package/dist/layout/Footer/Footer.stories.svelte +24 -24
  138. package/dist/layout/Footer/Footer.svelte +366 -366
  139. package/dist/layout/Footer/docs/component.md +10 -10
  140. package/dist/layout/Grid/Grid.stories.svelte +50 -50
  141. package/dist/layout/Grid/Grid.svelte +117 -117
  142. package/dist/layout/Grid/GridCell.svelte +65 -65
  143. package/dist/layout/Grid/docs/component.md +14 -14
  144. package/dist/layout/Header/Header.stories.svelte +26 -26
  145. package/dist/layout/Header/Header.svelte +875 -875
  146. package/dist/layout/Header/docs/component.md +11 -11
  147. package/dist/layout/Hero/Hero.stories.svelte +79 -79
  148. package/dist/layout/Hero/Hero.svelte +364 -364
  149. package/dist/layout/Hero/docs/component.md +14 -14
  150. package/dist/layout/Highlight/Highlight.stories.svelte +29 -29
  151. package/dist/layout/Highlight/Highlight.svelte +77 -77
  152. package/dist/layout/Highlight/docs/component.md +12 -12
  153. package/dist/layout/Image/Image.stories.svelte +23 -23
  154. package/dist/layout/Image/Image.svelte +29 -29
  155. package/dist/layout/Image/docs/component.md +15 -15
  156. package/dist/layout/List/Li.svelte +3 -3
  157. package/dist/layout/List/List.stories.svelte +40 -40
  158. package/dist/layout/List/List.svelte +46 -46
  159. package/dist/layout/List/docs/component.md +14 -14
  160. package/dist/layout/List/docs/example.md +12 -12
  161. package/dist/layout/NavSections/NavSection.svelte +90 -90
  162. package/dist/layout/NavSections/NavSections.stories.svelte +51 -51
  163. package/dist/layout/NavSections/NavSections.svelte +160 -160
  164. package/dist/layout/NavSections/docs/component.md +25 -25
  165. package/dist/layout/Notice/Notice.stories.svelte +61 -61
  166. package/dist/layout/Notice/Notice.svelte +56 -56
  167. package/dist/layout/Notice/docs/component.md +14 -14
  168. package/dist/layout/PhaseBanner/PhaseBanner.stories.svelte +24 -24
  169. package/dist/layout/PhaseBanner/PhaseBanner.svelte +66 -66
  170. package/dist/layout/PhaseBanner/docs/component.md +14 -14
  171. package/dist/layout/RelatedContent/RelatedContent.stories.svelte +36 -36
  172. package/dist/layout/RelatedContent/RelatedContent.svelte +54 -54
  173. package/dist/layout/RelatedContent/docs/component.md +16 -16
  174. package/dist/layout/Scroller/Scroller.stories.svelte +60 -60
  175. package/dist/layout/Scroller/Scroller.svelte +368 -368
  176. package/dist/layout/Scroller/ScrollerSection.svelte +70 -70
  177. package/dist/layout/Scroller/docs/component.md +39 -39
  178. package/dist/layout/Section/Section.stories.svelte +33 -33
  179. package/dist/layout/Section/Section.svelte +60 -60
  180. package/dist/layout/Section/docs/component.md +12 -12
  181. package/dist/layout/ShareButtons/ShareButtons.stories.svelte +20 -20
  182. package/dist/layout/ShareButtons/ShareButtons.svelte +131 -131
  183. package/dist/layout/ShareButtons/docs/component.md +14 -14
  184. package/dist/layout/SkipLink/SkipLink.stories.svelte +16 -16
  185. package/dist/layout/SkipLink/SkipLink.svelte +9 -9
  186. package/dist/layout/SkipLink/docs/component.md +11 -11
  187. package/dist/layout/Summary/Summary.stories.svelte +21 -21
  188. package/dist/layout/Summary/Summary.svelte +60 -60
  189. package/dist/layout/Summary/docs/component.md +17 -17
  190. package/dist/layout/Tabs/Tab.svelte +53 -53
  191. package/dist/layout/Tabs/Tabs.stories.svelte +29 -29
  192. package/dist/layout/Tabs/Tabs.svelte +89 -89
  193. package/dist/layout/Tabs/docs/component.md +16 -16
  194. package/dist/layout/Tabs/tabs.js +302 -302
  195. package/dist/layout/Timeline/Timeline.stories.svelte +44 -44
  196. package/dist/layout/Timeline/Timeline.svelte +17 -17
  197. package/dist/layout/Timeline/TimelineItem.svelte +14 -14
  198. package/dist/layout/Timeline/docs/component.md +27 -27
  199. package/dist/layout/Timeline/docs/example.md +20 -20
  200. package/dist/templates/EmbedArticle/EmbedArticle.stories.svelte +72 -72
  201. package/dist/templates/EmbedArticle/docs/component.md +56 -56
  202. package/dist/templates/FeatureArticle/FeatureArticle.stories.svelte +150 -150
  203. package/dist/templates/FeatureArticle/docs/component.md +125 -125
  204. package/dist/templates/StandardArticle/StandardArticle.stories.svelte +86 -86
  205. package/dist/templates/StandardArticle/docs/component.md +76 -76
  206. package/dist/templates/intro.mdx +18 -18
  207. package/dist/wrappers/Container/Container.stories.svelte +38 -38
  208. package/dist/wrappers/Container/Container.svelte +77 -77
  209. package/dist/wrappers/Container/docs/component.md +12 -12
  210. package/dist/wrappers/Embed/Embed.stories.svelte +24 -24
  211. package/dist/wrappers/Embed/Embed.svelte +44 -44
  212. package/dist/wrappers/Embed/docs/component.md +15 -15
  213. package/dist/wrappers/LazyLoad/LazyLoad.stories.svelte +37 -37
  214. package/dist/wrappers/LazyLoad/LazyLoad.svelte +50 -50
  215. package/dist/wrappers/LazyLoad/docs/component.md +29 -29
  216. package/dist/wrappers/Main/Main.stories.svelte +24 -24
  217. package/dist/wrappers/Main/Main.svelte +11 -11
  218. package/dist/wrappers/Main/docs/component.md +16 -16
  219. package/dist/wrappers/Observe/Observe.stories.svelte +29 -29
  220. package/dist/wrappers/Observe/Observe.svelte +35 -35
  221. package/dist/wrappers/Observe/docs/component.md +22 -22
  222. package/dist/wrappers/Theme/Theme.stories.svelte +70 -70
  223. package/dist/wrappers/Theme/Theme.svelte +76 -76
  224. package/dist/wrappers/Theme/docs/component.md +10 -10
  225. package/dist/wrappers/Theme/themes.js +70 -70
  226. package/package.json +89 -89
@@ -1,326 +1,326 @@
1
- <script>
2
- // @ts-nocheck
3
-
4
- import { onMount, createEventDispatcher } from "svelte";
5
- import Dropdown from "../Dropdown/Dropdown.svelte";
6
- import Input from "../Input/Input.svelte";
7
-
8
- const dispatch = createEventDispatcher();
9
- const sleep = (ms = 1000) => new Promise((resolve) => setTimeout(resolve, ms));
10
- const chevron = (opts) =>
11
- `<svg class="${opts?.className}" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 11.75 7.7" width="18" style="z-index:1"><path fill="currentColor" d="m1.37.15 4.5 5.1 4.5-5.1a.37.37 0 0 1 .6 0l.7.7a.45.45 0 0 1 0 .5l-5.5 6.2a.37.37 0 0 1-.6 0l-5.5-6.1a.64.64 0 0 1 0-.6l.7-.7a.64.64 0 0 1 .6 0Z"></path></svg>`;
12
-
13
- let inputElement;
14
- let scriptLoaded;
15
- let accessibleAutocomplete;
16
- let hideMenu = false;
17
-
18
- /**
19
- * Unique id for the HTML element
20
- * @type {string}
21
- */
22
- export let id = "autocomplete";
23
- /**
24
- * Name for the HTML element
25
- * @type {string}
26
- */
27
- export let name = id;
28
- /**
29
- * The mode can be either "default" or "search"
30
- * @type {"default"|"search"}
31
- */
32
- export let mode = "default";
33
- /**
34
- * Defines whether the selection can be cleared
35
- * @type {boolean}
36
- */
37
- export let clearable = mode !== "search";
38
- /**
39
- * Clear value on selection (default for "search" mode)
40
- * @type {boolean}
41
- */
42
- export let autoClear = mode === "search";
43
- /**
44
- * A label to describe the element (expected for accessibility)
45
- * @type {string}
46
- */
47
- export let label = mode === "search" ? "Type to select" : "Select an option";
48
- /**
49
- * Visually hide the label
50
- * @type {boolean}
51
- */
52
- export let hideLabel = false;
53
- /**
54
- * An optional placeholder text
55
- * @type {string}
56
- */
57
- export let placeholder = mode === "search" ? "Enter text" : "Select one";
58
- /**
59
- * A prop to bind to for the selected value
60
- * @type {object}
61
- */
62
- export let value = null;
63
- /**
64
- * An array of options, formatted {id, label}
65
- * @type {array}
66
- */
67
- export let options = [];
68
- /**
69
- * The attribute of an option that defines its label/name
70
- * @type {string}
71
- */
72
- export let labelKey = "label";
73
- /**
74
- * The attribute of an option that defines its group (optional)
75
- * @type {string|null}
76
- */
77
- export let groupKey = null;
78
- /**
79
- * When using SSR or pre-rendering, this option will render a text input or dropdown before the page is hydrated (allows for progressive enhancement).
80
- * @type {boolean}
81
- */
82
- export let renderFallback = false;
83
- /**
84
- * Optional: Minimum query length to return results
85
- * @type {number}
86
- */
87
- export let minLength = mode === "search" ? 1 : 0;
88
- /**
89
- * Optional: Override function for loading/filtering options based on the entered text
90
- * @type {function}
91
- */
92
- export let loadOptions = (query, populateResults) => {
93
- const filteredResults =
94
- mode !== "search" && options.map((opt) => opt[labelKey]).includes(query)
95
- ? options
96
- : options.filter((opt) =>
97
- opt[labelKey].match(new RegExp(`\\b${query.replace(/[^\w\s]/gi, "")}`, "i"))
98
- );
99
- populateResults(filteredResults);
100
- };
101
- /**
102
- * Optional: Override the default CDN URL for the accessible-autocomplete script
103
- * @type {string}
104
- */
105
- export let scriptUrl =
106
- "https://cdn.ons.gov.uk/vendor/accessible-autocomplete/3.0.1/accessible-autocomplete.min.js";
107
- /**
108
- * Call this function externally to clear the input
109
- * @type {function}
110
- */
111
- export let clearInput = async () => {
112
- await setInputValue(null);
113
- dispatch("clear", null);
114
- };
115
- /**
116
- * Optional: Set an additional CSS class for the component
117
- * @type {string|null}
118
- */
119
- export let cls = null;
120
-
121
- // This method is a bit of a hack, but no better options available at present
122
- // https://github.com/alphagov/accessible-autocomplete/issues/390
123
- async function setInputValue(textValue) {
124
- hideMenu = true;
125
- inputElement.value = textValue || "";
126
- await sleep(110);
127
- inputElement.focus({ preventScroll: true });
128
- inputElement.blur();
129
- hideMenu = false;
130
- }
131
-
132
- function inputValueTemplate(result) {
133
- return result && result[labelKey];
134
- }
135
-
136
- function highlight(text, query = "") {
137
- return text.replace(
138
- new RegExp(`\\b${query.replace(/[^\w\s]/gi, "")}`, "i"),
139
- (str) => `<b>${str}</b>`
140
- );
141
- }
142
-
143
- function suggestionTemplate(result) {
144
- const query = inputElement?.value || "";
145
- return (
146
- result &&
147
- (groupKey
148
- ? `${highlight(result?.[labelKey] || "", query)} <span class="muted-text">${
149
- result[groupKey]
150
- }</span>`
151
- : highlight(result?.[labelKey] || "", query))
152
- );
153
- }
154
-
155
- async function select(option) {
156
- if (option && value !== option) {
157
- value = option;
158
- dispatch("change", value);
159
- if (value && autoClear) {
160
- await sleep(0);
161
- clearInput();
162
- }
163
- }
164
- }
165
-
166
- function inputChange(e) {
167
- if (!e.target.value) select(null);
168
- }
169
-
170
- function handleScriptLoad() {
171
- if (!scriptLoaded && window?.accessibleAutocomplete) {
172
- accessibleAutocomplete = window.accessibleAutocomplete;
173
- scriptLoaded = true;
174
- }
175
- }
176
-
177
- function initAutocomplete(element) {
178
- accessibleAutocomplete({
179
- element,
180
- id,
181
- name,
182
- source: loadOptions,
183
- autoselect: true,
184
- onConfirm: select,
185
- confirmOnBlur: false,
186
- placeholder,
187
- displayMenu: "overlay",
188
- showAllValues: mode === "default",
189
- dropdownArrow: chevron,
190
- minLength,
191
- templates: {
192
- inputValue: inputValueTemplate,
193
- suggestion: suggestionTemplate
194
- }
195
- });
196
- inputElement = element.querySelector(`#${id}`);
197
- setInputValue(value?.[labelKey] || "");
198
- inputElement.addEventListener("blur", inputChange);
199
- }
200
-
201
- // In case input value is updated from outside component
202
- function bindInputValue(value) {
203
- if (inputElement) {
204
- const textValue = value?.[labelKey];
205
- if (textValue && inputElement.value !== textValue) setInputValue(textValue);
206
- else if (!value && inputElement.value) setInputValue("");
207
- }
208
- }
209
- $: bindInputValue(value);
210
-
211
- onMount(handleScriptLoad);
212
- </script>
213
-
214
- <svelte:head>
215
- <script src={scriptUrl} on:load={handleScriptLoad}></script>
216
- </svelte:head>
217
-
218
- {#if renderFallback && !scriptLoaded}
219
- {#if mode === "search"}
220
- <Input {id} {name} {label} {hideLabel} value={value?.[labelKey]} />
221
- {:else}
222
- <Dropdown {id} {name} {options} {label} {hideLabel} {placeholder} {value} />
223
- {/if}
224
- {:else}
225
- <div class="ons-field {cls}">
226
- {#if label}<label for={id} class="ons-label" class:ons-u-vh={hideLabel}>{label}</label>{/if}
227
- <div class="ons-autocomplete-wrapper">
228
- {#if scriptLoaded}
229
- <div
230
- id="{id}-container"
231
- class="ons-autocomplete"
232
- class:hide-menu={hideMenu}
233
- use:initAutocomplete
234
- ></div>
235
- {#if clearable && !autoClear && value}
236
- <button
237
- type="reset"
238
- title="Clear selection"
239
- aria-label="Clear selection"
240
- on:click={clearInput}
241
- class="ons-autocomplete-clear"
242
- >
243
- <svg
244
- xmlns="http://www.w3.org/2000/svg"
245
- aria-hidden="true"
246
- viewBox="0 0 14 14"
247
- width="18"
248
- >
249
- <path
250
- fill="currentColor"
251
- d="M13.6 1 l -0.71 -0.71 a 0.5 0.5 0 0 0 -0.71 0 l -5.25 5.25 l -5.25 -5.25 a 0.51 0.51 0 0 0 -0.71 0 l -0.71 0.71 a 0.5 0.5 0 0 0 0 0.71 l 5.25 5.25 l -5.25 5.25 a 0.5 0.5 0 0 0 0 0.71 l 0.71 0.71 a 0.5 0.5 0 0 0 0.71 0 l 5.25 -5.25 l 5.25 5.25 a 0.5 0.5 0 0 0 0.71 0 l 0.71 -0.71 a 0.5 0.5 0 0 0 0 -0.71 l -5.25 -5.25 l 5.25 -5.25 a 0.5 0.5 0 0 0 0 -0.71Z"
252
- ></path>
253
- </svg>
254
- </button>
255
- {/if}
256
- {/if}
257
- </div>
258
- </div>
259
- {/if}
260
-
261
- <style>
262
- .ons-autocomplete-wrapper {
263
- position: relative;
264
- }
265
- .ons-autocomplete-clear {
266
- position: absolute;
267
- display: flex;
268
- align-items: center;
269
- align-content: center;
270
- z-index: 1;
271
- right: 3px;
272
- top: calc(50% - 14px);
273
- height: 28px;
274
- width: 28px;
275
- border: none;
276
- background: var(--ons-color-input-bg, white);
277
- }
278
- .ons-autocomplete-clear:focus {
279
- outline: 3px solid var(--ons-color-focus, #fbc900) !important;
280
- }
281
- .hide-menu :global(.autocomplete__menu) {
282
- display: none;
283
- }
284
- .ons-autocomplete :global(.autocomplete__input) {
285
- border-radius: 3px !important;
286
- border-width: 1px !important;
287
- background: var(--ons-color-input-bg, white);
288
- }
289
- .ons-autocomplete :global(.autocomplete__input--focused) {
290
- box-shadow: inset 0 0 0 1px black !important;
291
- outline-color: var(--ons-color-focus, #fbc900) !important;
292
- }
293
- .ons-autocomplete :global(.autocomplete__dropdown-arrow-down) {
294
- width: 18px !important;
295
- transform: translateY(-2px);
296
- }
297
- .ons-autocomplete :global(.muted-text) {
298
- opacity: 0.8;
299
- font-size: smaller;
300
- }
301
- .ons-autocomplete-wrapper :global(*) {
302
- font-size: 18px;
303
- }
304
- .ons-autocomplete-wrapper :global(.autocomplete__hint),
305
- .ons-autocomplete-wrapper :global(.autocomplete__input) {
306
- height: 40px;
307
- }
308
- .ons-autocomplete-wrapper :global(.autocomplete__option) {
309
- margin: 0;
310
- }
311
- .ons-autocomplete-wrapper :global(.autocomplete__menu) {
312
- transform: translateY(5px);
313
- border: 1px solid currentColor;
314
- border-radius: 3px;
315
- }
316
- .ons-autocomplete-wrapper :global(.autocomplete__option--focused),
317
- .ons-autocomplete-wrapper :global(.autocomplete__option:hover) {
318
- background-color: var(--ons-color-branded-secondary, #003c57);
319
- }
320
- .ons-autocomplete-wrapper :global(.autocomplete__option:focus) {
321
- outline: none !important;
322
- }
323
- .ons-autocomplete-wrapper :global(input) {
324
- padding: 0 35px 0 8px;
325
- }
326
- </style>
1
+ <script>
2
+ // @ts-nocheck
3
+
4
+ import { onMount, createEventDispatcher } from "svelte";
5
+ import Dropdown from "../Dropdown/Dropdown.svelte";
6
+ import Input from "../Input/Input.svelte";
7
+
8
+ const dispatch = createEventDispatcher();
9
+ const sleep = (ms = 1000) => new Promise((resolve) => setTimeout(resolve, ms));
10
+ const chevron = (opts) =>
11
+ `<svg class="${opts?.className}" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 11.75 7.7" width="18" style="z-index:1"><path fill="currentColor" d="m1.37.15 4.5 5.1 4.5-5.1a.37.37 0 0 1 .6 0l.7.7a.45.45 0 0 1 0 .5l-5.5 6.2a.37.37 0 0 1-.6 0l-5.5-6.1a.64.64 0 0 1 0-.6l.7-.7a.64.64 0 0 1 .6 0Z"></path></svg>`;
12
+
13
+ let inputElement;
14
+ let scriptLoaded;
15
+ let accessibleAutocomplete;
16
+ let hideMenu = false;
17
+
18
+ /**
19
+ * Unique id for the HTML element
20
+ * @type {string}
21
+ */
22
+ export let id = "autocomplete";
23
+ /**
24
+ * Name for the HTML element
25
+ * @type {string}
26
+ */
27
+ export let name = id;
28
+ /**
29
+ * The mode can be either "default" or "search"
30
+ * @type {"default"|"search"}
31
+ */
32
+ export let mode = "default";
33
+ /**
34
+ * Defines whether the selection can be cleared
35
+ * @type {boolean}
36
+ */
37
+ export let clearable = mode !== "search";
38
+ /**
39
+ * Clear value on selection (default for "search" mode)
40
+ * @type {boolean}
41
+ */
42
+ export let autoClear = mode === "search";
43
+ /**
44
+ * A label to describe the element (expected for accessibility)
45
+ * @type {string|null}
46
+ */
47
+ export let label = mode === "search" ? "Type to select" : "Select an option";
48
+ /**
49
+ * Visually hide the label
50
+ * @type {boolean}
51
+ */
52
+ export let hideLabel = false;
53
+ /**
54
+ * An optional placeholder text
55
+ * @type {string}
56
+ */
57
+ export let placeholder = mode === "search" ? "Enter text" : "Select one";
58
+ /**
59
+ * A prop to bind to for the selected value
60
+ * @type {object}
61
+ */
62
+ export let value = null;
63
+ /**
64
+ * An array of options, formatted {id, label}
65
+ * @type {array}
66
+ */
67
+ export let options = [];
68
+ /**
69
+ * The attribute of an option that defines its label/name
70
+ * @type {string}
71
+ */
72
+ export let labelKey = "label";
73
+ /**
74
+ * The attribute of an option that defines its group (optional)
75
+ * @type {string|null}
76
+ */
77
+ export let groupKey = null;
78
+ /**
79
+ * When using SSR or pre-rendering, this option will render a text input or dropdown before the page is hydrated (allows for progressive enhancement).
80
+ * @type {boolean}
81
+ */
82
+ export let renderFallback = false;
83
+ /**
84
+ * Optional: Minimum query length to return results
85
+ * @type {number}
86
+ */
87
+ export let minLength = mode === "search" ? 1 : 0;
88
+ /**
89
+ * Optional: Override function for loading/filtering options based on the entered text
90
+ * @type {function}
91
+ */
92
+ export let loadOptions = (query, populateResults) => {
93
+ const filteredResults =
94
+ mode !== "search" && options.map((opt) => opt[labelKey]).includes(query)
95
+ ? options
96
+ : options.filter((opt) =>
97
+ opt[labelKey].match(new RegExp(`\\b${query.replace(/[^\w\s]/gi, "")}`, "i"))
98
+ );
99
+ populateResults(filteredResults);
100
+ };
101
+ /**
102
+ * Optional: Override the default CDN URL for the accessible-autocomplete script
103
+ * @type {string}
104
+ */
105
+ export let scriptUrl =
106
+ "https://cdn.ons.gov.uk/vendor/accessible-autocomplete/3.0.1/accessible-autocomplete.min.js";
107
+ /**
108
+ * Call this function externally to clear the input
109
+ * @type {function}
110
+ */
111
+ export let clearInput = async () => {
112
+ await setInputValue(null);
113
+ dispatch("clear", null);
114
+ };
115
+ /**
116
+ * Optional: Set an additional CSS class for the component
117
+ * @type {string|null}
118
+ */
119
+ export let cls = null;
120
+
121
+ // This method is a bit of a hack, but no better options available at present
122
+ // https://github.com/alphagov/accessible-autocomplete/issues/390
123
+ async function setInputValue(textValue) {
124
+ hideMenu = true;
125
+ inputElement.value = textValue || "";
126
+ await sleep(110);
127
+ inputElement.focus({ preventScroll: true });
128
+ inputElement.blur();
129
+ hideMenu = false;
130
+ }
131
+
132
+ function inputValueTemplate(result) {
133
+ return result && result[labelKey];
134
+ }
135
+
136
+ function highlight(text, query = "") {
137
+ return text.replace(
138
+ new RegExp(`\\b${query.replace(/[^\w\s]/gi, "")}`, "i"),
139
+ (str) => `<b>${str}</b>`
140
+ );
141
+ }
142
+
143
+ function suggestionTemplate(result) {
144
+ const query = inputElement?.value || "";
145
+ return (
146
+ result &&
147
+ (groupKey
148
+ ? `${highlight(result?.[labelKey] || "", query)} <span class="muted-text">${
149
+ result[groupKey]
150
+ }</span>`
151
+ : highlight(result?.[labelKey] || "", query))
152
+ );
153
+ }
154
+
155
+ async function select(option) {
156
+ if (option && value !== option) {
157
+ value = option;
158
+ dispatch("change", value);
159
+ if (value && autoClear) {
160
+ await sleep(0);
161
+ clearInput();
162
+ }
163
+ }
164
+ }
165
+
166
+ function inputChange(e) {
167
+ if (!e.target.value) select(null);
168
+ }
169
+
170
+ function handleScriptLoad() {
171
+ if (!scriptLoaded && window?.accessibleAutocomplete) {
172
+ accessibleAutocomplete = window.accessibleAutocomplete;
173
+ scriptLoaded = true;
174
+ }
175
+ }
176
+
177
+ function initAutocomplete(element) {
178
+ accessibleAutocomplete({
179
+ element,
180
+ id,
181
+ name,
182
+ source: loadOptions,
183
+ autoselect: true,
184
+ onConfirm: select,
185
+ confirmOnBlur: false,
186
+ placeholder,
187
+ displayMenu: "overlay",
188
+ showAllValues: mode === "default",
189
+ dropdownArrow: chevron,
190
+ minLength,
191
+ templates: {
192
+ inputValue: inputValueTemplate,
193
+ suggestion: suggestionTemplate
194
+ }
195
+ });
196
+ inputElement = element.querySelector(`#${id}`);
197
+ setInputValue(value?.[labelKey] || "");
198
+ inputElement.addEventListener("blur", inputChange);
199
+ }
200
+
201
+ // In case input value is updated from outside component
202
+ function bindInputValue(value) {
203
+ if (inputElement) {
204
+ const textValue = value?.[labelKey];
205
+ if (textValue && inputElement.value !== textValue) setInputValue(textValue);
206
+ else if (!value && inputElement.value) setInputValue("");
207
+ }
208
+ }
209
+ $: bindInputValue(value);
210
+
211
+ onMount(handleScriptLoad);
212
+ </script>
213
+
214
+ <svelte:head>
215
+ <script src={scriptUrl} on:load={handleScriptLoad}></script>
216
+ </svelte:head>
217
+
218
+ {#if renderFallback && !scriptLoaded}
219
+ {#if mode === "search"}
220
+ <Input {id} {name} {label} {hideLabel} value={value?.[labelKey]} />
221
+ {:else}
222
+ <Dropdown {id} {name} {options} {label} {hideLabel} {placeholder} {value} />
223
+ {/if}
224
+ {:else}
225
+ <div class="ons-field {cls}">
226
+ {#if label}<label for={id} class="ons-label" class:ons-u-vh={hideLabel}>{label}</label>{/if}
227
+ <div class="ons-autocomplete-wrapper">
228
+ {#if scriptLoaded}
229
+ <div
230
+ id="{id}-container"
231
+ class="ons-autocomplete"
232
+ class:hide-menu={hideMenu}
233
+ use:initAutocomplete
234
+ ></div>
235
+ {#if clearable && !autoClear && value}
236
+ <button
237
+ type="reset"
238
+ title="Clear selection"
239
+ aria-label="Clear selection"
240
+ on:click={clearInput}
241
+ class="ons-autocomplete-clear"
242
+ >
243
+ <svg
244
+ xmlns="http://www.w3.org/2000/svg"
245
+ aria-hidden="true"
246
+ viewBox="0 0 14 14"
247
+ width="18"
248
+ >
249
+ <path
250
+ fill="currentColor"
251
+ d="M13.6 1 l -0.71 -0.71 a 0.5 0.5 0 0 0 -0.71 0 l -5.25 5.25 l -5.25 -5.25 a 0.51 0.51 0 0 0 -0.71 0 l -0.71 0.71 a 0.5 0.5 0 0 0 0 0.71 l 5.25 5.25 l -5.25 5.25 a 0.5 0.5 0 0 0 0 0.71 l 0.71 0.71 a 0.5 0.5 0 0 0 0.71 0 l 5.25 -5.25 l 5.25 5.25 a 0.5 0.5 0 0 0 0.71 0 l 0.71 -0.71 a 0.5 0.5 0 0 0 0 -0.71 l -5.25 -5.25 l 5.25 -5.25 a 0.5 0.5 0 0 0 0 -0.71Z"
252
+ ></path>
253
+ </svg>
254
+ </button>
255
+ {/if}
256
+ {/if}
257
+ </div>
258
+ </div>
259
+ {/if}
260
+
261
+ <style>
262
+ .ons-autocomplete-wrapper {
263
+ position: relative;
264
+ }
265
+ .ons-autocomplete-clear {
266
+ position: absolute;
267
+ display: flex;
268
+ align-items: center;
269
+ align-content: center;
270
+ z-index: 1;
271
+ right: 3px;
272
+ top: calc(50% - 14px);
273
+ height: 28px;
274
+ width: 28px;
275
+ border: none;
276
+ background: var(--ons-color-input-bg, white);
277
+ }
278
+ .ons-autocomplete-clear:focus {
279
+ outline: 3px solid var(--ons-color-focus, #fbc900) !important;
280
+ }
281
+ .hide-menu :global(.autocomplete__menu) {
282
+ display: none;
283
+ }
284
+ .ons-autocomplete :global(.autocomplete__input) {
285
+ border-radius: 3px !important;
286
+ border-width: 1px !important;
287
+ background: var(--ons-color-input-bg, white);
288
+ }
289
+ .ons-autocomplete :global(.autocomplete__input--focused) {
290
+ box-shadow: inset 0 0 0 1px black !important;
291
+ outline-color: var(--ons-color-focus, #fbc900) !important;
292
+ }
293
+ .ons-autocomplete :global(.autocomplete__dropdown-arrow-down) {
294
+ width: 18px !important;
295
+ transform: translateY(-2px);
296
+ }
297
+ .ons-autocomplete :global(.muted-text) {
298
+ opacity: 0.8;
299
+ font-size: smaller;
300
+ }
301
+ .ons-autocomplete-wrapper :global(*) {
302
+ font-size: 18px;
303
+ }
304
+ .ons-autocomplete-wrapper :global(.autocomplete__hint),
305
+ .ons-autocomplete-wrapper :global(.autocomplete__input) {
306
+ height: 40px;
307
+ }
308
+ .ons-autocomplete-wrapper :global(.autocomplete__option) {
309
+ margin: 0;
310
+ }
311
+ .ons-autocomplete-wrapper :global(.autocomplete__menu) {
312
+ transform: translateY(5px);
313
+ border: 1px solid currentColor;
314
+ border-radius: 3px;
315
+ }
316
+ .ons-autocomplete-wrapper :global(.autocomplete__option--focused),
317
+ .ons-autocomplete-wrapper :global(.autocomplete__option:hover) {
318
+ background-color: var(--ons-color-branded-secondary, #003c57);
319
+ }
320
+ .ons-autocomplete-wrapper :global(.autocomplete__option:focus) {
321
+ outline: none !important;
322
+ }
323
+ .ons-autocomplete-wrapper :global(input) {
324
+ padding: 0 35px 0 8px;
325
+ }
326
+ </style>
@@ -4,7 +4,7 @@
4
4
  export default class Select extends SvelteComponentTyped<{
5
5
  cls?: string | null | undefined;
6
6
  id?: string | undefined;
7
- label?: string | undefined;
7
+ label?: string | null | undefined;
8
8
  name?: string | undefined;
9
9
  mode?: "default" | "search" | undefined;
10
10
  value?: object | undefined;
@@ -35,7 +35,7 @@ declare const __propDef: {
35
35
  props: {
36
36
  cls?: string | null | undefined;
37
37
  id?: string | undefined;
38
- label?: string | undefined;
38
+ label?: string | null | undefined;
39
39
  name?: string | undefined;
40
40
  mode?: "default" | "search" | undefined;
41
41
  value?: object | undefined;