@communitiesuk/svelte-component-library 0.1.19-beta.3 → 0.1.19-beta.33

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 (47) hide show
  1. package/README.md +7 -0
  2. package/dist/components/content/Tag.svelte +32 -0
  3. package/dist/components/content/Tag.svelte.d.ts +13 -0
  4. package/dist/components/data-vis/Histogram.svelte +302 -0
  5. package/dist/components/data-vis/Histogram.svelte.d.ts +75 -0
  6. package/dist/components/data-vis/axis/Axis.svelte +217 -34
  7. package/dist/components/data-vis/axis/Axis.svelte.d.ts +38 -30
  8. package/dist/components/data-vis/axis/Ticks.svelte +142 -78
  9. package/dist/components/data-vis/axis/Ticks.svelte.d.ts +28 -31
  10. package/dist/components/data-vis/line-chart/LineChart.svelte +51 -21
  11. package/dist/components/data-vis/line-chart/LineChart.svelte.d.ts +14 -6
  12. package/dist/components/data-vis/line-chart/ValueLabel.svelte +2 -1
  13. package/dist/components/data-vis/line-chart/ValueLabel.svelte.d.ts +2 -0
  14. package/dist/components/data-vis/position-chart/PositionChart.svelte +278 -122
  15. package/dist/components/data-vis/position-chart/PositionChart.svelte.d.ts +37 -5
  16. package/dist/components/data-vis/position-chart/PositionChartAxis.svelte +59 -48
  17. package/dist/components/data-vis/position-chart/PositionChartAxis.svelte.d.ts +4 -4
  18. package/dist/components/layout/Footer.svelte +9 -0
  19. package/dist/components/layout/Footer.svelte.d.ts +1 -0
  20. package/dist/components/layout/PhaseBanner.svelte +10 -1
  21. package/dist/components/layout/PhaseBanner.svelte.d.ts +1 -0
  22. package/dist/components/layout/ServiceNavigation.svelte +19 -1
  23. package/dist/components/layout/ServiceNavigation.svelte.d.ts +2 -0
  24. package/dist/components/ui/BasicMultiSelect.svelte +716 -0
  25. package/dist/components/ui/BasicMultiSelect.svelte.d.ts +18 -0
  26. package/dist/components/ui/Button.svelte +1 -0
  27. package/dist/components/ui/Card.svelte +48 -60
  28. package/dist/components/ui/Card.svelte.d.ts +26 -12
  29. package/dist/components/ui/CardHeader.svelte +46 -0
  30. package/dist/components/ui/CardHeader.svelte.d.ts +21 -0
  31. package/dist/components/ui/ChartExporter.svelte +142 -0
  32. package/dist/components/ui/ChartExporter.svelte.d.ts +16 -0
  33. package/dist/components/ui/CheckBox.svelte +1 -0
  34. package/dist/components/ui/Details.svelte +47 -8
  35. package/dist/components/ui/Details.svelte.d.ts +8 -10
  36. package/dist/components/ui/Masthead.svelte +44 -6
  37. package/dist/components/ui/Masthead.svelte.d.ts +6 -0
  38. package/dist/components/ui/RelatedContent.svelte +4 -1
  39. package/dist/components/ui/RelatedContent.svelte.d.ts +1 -0
  40. package/dist/components/ui/SearchAutocomplete.svelte +69 -44
  41. package/dist/components/ui/SearchAutocomplete.svelte.d.ts +1 -0
  42. package/dist/components/ui/Select.svelte +18 -7
  43. package/dist/components/ui/Tabs.svelte +192 -18
  44. package/dist/components/ui/Tabs.svelte.d.ts +1 -0
  45. package/dist/index.d.ts +5 -0
  46. package/dist/index.js +5 -0
  47. package/package.json +4 -1
@@ -30,11 +30,13 @@
30
30
  headingLevel = 2 as 1 | 2 | 3 | 4 | 5 | 6, // Main heading level (used by first 'main' section)
31
31
  listTruncateThreshold = 5, // Default threshold, can be overridden per section
32
32
  disableGa4 = false,
33
+ marginBottom = "60px",
33
34
  } = $props<{
34
35
  sections?: RelatedContentSection[];
35
36
  headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
36
37
  listTruncateThreshold?: number; // Default threshold
37
38
  disableGa4?: boolean;
39
+ marginBottom?: string;
38
40
  }>();
39
41
 
40
42
  // Helper to check if a link is external
@@ -229,6 +231,7 @@
229
231
  class="gem-c-related-navigation govuk-!-display-none-print {hasJavaScript
230
232
  ? 'govuk-frontend-supported'
231
233
  : ''}"
234
+ style="margin-bottom: {marginBottom};"
232
235
  role="complementary"
233
236
  >
234
237
  {#if mainSection && mainSection.title}
@@ -304,7 +307,7 @@
304
307
  <style>
305
308
  .gem-c-related-navigation {
306
309
  border-top: 2px solid #1d70b8;
307
- margin-bottom: 60px;
310
+ /* margin-bottom: 60px; */
308
311
  color: #0b0c0c;
309
312
  }
310
313
 
@@ -24,6 +24,7 @@ type $$ComponentProps = {
24
24
  headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
25
25
  listTruncateThreshold?: number;
26
26
  disableGa4?: boolean;
27
+ marginBottom?: string;
27
28
  };
28
29
  declare const RelatedContent: import("svelte").Component<$$ComponentProps, {}, "">;
29
30
  type RelatedContent = ReturnType<typeof RelatedContent>;
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { onMount } from "svelte";
3
3
  import { clsx } from "clsx";
4
+ import { on } from "svelte/events";
4
5
  import Search from "./Search.svelte"; // Base component
5
6
  import "accessible-autocomplete/dist/accessible-autocomplete.min.css";
6
7
  import { browser } from "$app/environment";
@@ -55,6 +56,7 @@
55
56
  hideHint?: boolean; // Hide the hint input element when autoselect is true
56
57
  prefixMatchOnly?: boolean; // Only show suggestions that start with the query (better for hint behavior)
57
58
  autoFocusSubmitOnSelection?: boolean; // Auto-focus submit button when selection is confirmed
59
+ allowFreeTextSubmission?: boolean; // Treat free-typed input as confirmed when submitted (works with or without form)
58
60
  };
59
61
 
60
62
  let {
@@ -93,6 +95,7 @@
93
95
  hideHint = false, // Default to false - show hint by default
94
96
  prefixMatchOnly = false, // Default to false - show all matches
95
97
  autoFocusSubmitOnSelection = false, // Default to false - don't auto-focus by default
98
+ allowFreeTextSubmission = false, // Default to false - only confirmed suggestions submit
96
99
  ...restSearchProps // Other props for the base Search component
97
100
  }: Props = $props();
98
101
 
@@ -105,8 +108,6 @@
105
108
  let currentSourceKey = $state<string | undefined>(undefined);
106
109
  let currentSourceProperty = $state<string | undefined>(undefined);
107
110
 
108
-
109
-
110
111
  // --- Derived Values ---
111
112
  const wrapperClasses = $derived(
112
113
  clsx(
@@ -408,55 +409,41 @@
408
409
  // Define confirm function
409
410
  let isSubmitting = false; // Prevent double submit
410
411
  const handleConfirm = (confirmedValue: Suggestion | undefined) => {
411
- console.log('handleConfirm called with:', confirmedValue, 'isSubmitting:', isSubmitting); // Debug log
412
-
413
- if (confirmedValue === undefined) return;
414
-
415
- // Reset submitting flag at the start of each new confirmation
416
- isSubmitting = false;
412
+ if (confirmedValue === undefined || isSubmitting) return;
413
+
414
+ isSubmitting = true;
417
415
 
418
- // Re-assign selectedValue before any form-based guard checks (!form) so bindings still update
419
- // (e.g. when no <form> exists around the component usage) and search component value is being used clienside without a page reload
416
+ // Update selectedValue
420
417
  selectedValue =
421
418
  typeof confirmedValue === "string"
422
419
  ? confirmedValue
423
420
  : confirmedValue.value;
424
421
 
425
- // Type assertion needed here
422
+ // Mark as accepted to prevent form submit handler from processing again
426
423
  const inputElement =
427
424
  autocompleteInstance?.inputElement as HTMLInputElement;
428
- const form = containerElement?.closest("form");
429
- const submitButton = containerElement?.querySelector('button[type="submit"]') as HTMLButtonElement;
430
-
431
- console.log('Submit button found:', !!submitButton); // Debug log
432
-
433
- // Always focus the submit button first, regardless of form presence (if feature is enabled)
434
- if (autoFocusSubmitOnSelection && submitButton) {
435
- console.log('Focusing submit button'); // Debug log
436
- // Use requestAnimationFrame to ensure the focus happens after DOM updates
437
- requestAnimationFrame(() => {
438
- submitButton.focus();
439
- console.log('Submit button focused, document.activeElement:', document.activeElement === submitButton);
440
- });
425
+ if (inputElement) {
426
+ inputElement.value = inputValueTemplate(confirmedValue);
427
+ inputElement.dataset.autocompleteAccepted = "true";
441
428
  }
442
429
 
443
- // Handle form submission separately
444
- if (inputElement && form) {
445
- isSubmitting = true;
446
- inputElement.value = inputValueTemplate(confirmedValue);
447
- inputElement.dataset.autocompleteAccepted = "true"; // Set tracking attribute
448
-
449
- // Submit form immediately
450
- console.log('Submitting form'); // Debug log
451
- if (form.requestSubmit) {
452
- form.requestSubmit();
453
- } else {
454
- form.submit(); // Fallback for older browsers
430
+ // Auto-focus submit button if enabled
431
+ if (autoFocusSubmitOnSelection) {
432
+ const submitButton = containerElement?.querySelector(
433
+ 'button[type="submit"]',
434
+ ) as HTMLButtonElement | null;
435
+ if (submitButton) {
436
+ requestAnimationFrame(() => submitButton.focus());
455
437
  }
456
-
457
- // Reset flag after submission
458
- isSubmitting = false;
459
438
  }
439
+
440
+ // Submit form if present
441
+ const form = containerElement?.closest("form");
442
+ if (form) {
443
+ form.requestSubmit?.() ?? form.submit();
444
+ }
445
+
446
+ isSubmitting = false;
460
447
  };
461
448
 
462
449
  // Initialise accessible-autocomplete
@@ -505,15 +492,15 @@
505
492
  ".gem-c-search-with-autocomplete__menu",
506
493
  );
507
494
  // Listen for input changes on the autocomplete field
508
- autocompleteInputElement.addEventListener("input", () => {
495
+ on(autocompleteInputElement, "input", () => {
509
496
  const val = autocompleteInputElement.value;
510
-
497
+
511
498
  // Reset isSubmitting flag when user starts typing again
512
499
  if (isSubmitting) {
513
- console.log('User typing, resetting isSubmitting flag');
500
+ console.log("User typing, resetting isSubmitting flag");
514
501
  isSubmitting = false;
515
502
  }
516
-
503
+
517
504
  // Remove any existing 'too-short' warning before adding a new one to ensure we don't accumulate multiple warning items.
518
505
  suggestionsMenu
519
506
  ?.querySelector(
@@ -544,7 +531,7 @@
544
531
  // autocompleteInputElement.classList.add("autocomplete__input"); // Add specific class if needed
545
532
 
546
533
  // Add Enter key workaround from original JS
547
- autocompleteInputElement.addEventListener("keydown", (e) => {
534
+ on(autocompleteInputElement, "keydown", (e) => {
548
535
  if (isSubmitting) return; // Don't interfere if already submitting
549
536
  const dropdownVisible =
550
537
  autocompleteInputElement.getAttribute("aria-expanded") === "true";
@@ -567,6 +554,44 @@
567
554
  // );
568
555
  }
569
556
 
557
+ // Handle free-text submission when allowFreeTextSubmission is enabled
558
+ // handleConfirm is only called by the library when selecting from dropdown
559
+ // We need to catch: (1) form submit events, (2) button clicks outside forms
560
+ if (allowFreeTextSubmission) {
561
+ const updateFreeText = () => {
562
+ if (!autocompleteInputElement) return;
563
+
564
+ const wasAccepted =
565
+ autocompleteInputElement.dataset.autocompleteAccepted === "true";
566
+ const value = autocompleteInputElement.value?.trim();
567
+
568
+ if (value && !wasAccepted) {
569
+ selectedValue = value;
570
+ }
571
+
572
+ // Reset flag after submission
573
+ setTimeout(() => {
574
+ if (autocompleteInputElement) {
575
+ autocompleteInputElement.dataset.autocompleteAccepted = "false";
576
+ }
577
+ }, 100);
578
+ };
579
+
580
+ // Handle form submission
581
+ const form = containerElement?.closest("form");
582
+ if (form) {
583
+ on(form, "submit", updateFreeText);
584
+ }
585
+
586
+ // Handle button clicks (for non-form usage)
587
+ const submitButton = containerElement?.querySelector(
588
+ 'button[type="submit"]',
589
+ ) as HTMLButtonElement | null;
590
+ if (submitButton && !form) {
591
+ on(submitButton, "click", updateFreeText);
592
+ }
593
+ }
594
+
570
595
  // IMPORTANT: Remove the original Search.svelte input, as accessible-autocomplete replaces it.
571
596
  // We render it initially so accessible-autocomplete can grab its id, name, value.
572
597
  if (searchInput) {
@@ -40,6 +40,7 @@ type Props = {
40
40
  hideHint?: boolean;
41
41
  prefixMatchOnly?: boolean;
42
42
  autoFocusSubmitOnSelection?: boolean;
43
+ allowFreeTextSubmission?: boolean;
43
44
  };
44
45
  declare const SearchAutocomplete: import("svelte").Component<Props, {}, "selectedValue">;
45
46
  type SearchAutocomplete = ReturnType<typeof SearchAutocomplete>;
@@ -225,20 +225,31 @@
225
225
 
226
226
  <style>
227
227
  .select-row {
228
- display: grid;
229
- grid-template-columns: 1fr auto;
230
- align-items: stretch;
231
- -moz-column-gap: 0;
232
- column-gap: 0;
228
+ display: flex;
229
+ flex-wrap: wrap;
230
+ align-items: flex-end;
231
+ gap: 0.5rem;
232
+ width: 100%;
233
233
  }
234
234
 
235
235
  .select-cell {
236
+ flex: 0 1 auto;
236
237
  min-width: 0;
238
+ max-width: 100%;
237
239
  }
238
240
 
239
241
  .select-addon {
240
242
  display: flex;
241
- align-items: stretch; /* match .choices container height */
242
- max-height: 46px;
243
+ align-items: stretch;
244
+ flex: 0 0 auto;
245
+ }
246
+
247
+ .govuk-select {
248
+ max-width: 100%;
249
+ min-width: 0;
250
+ padding-right: 2rem;
251
+ overflow: hidden;
252
+ white-space: nowrap;
253
+ text-overflow: ellipsis;
243
254
  }
244
255
  </style>
@@ -19,12 +19,14 @@
19
19
  idPrefix = "tab",
20
20
  selectedTabId = $bindable(),
21
21
  autoAddHeadings = true,
22
+ forceTabBehavior = false,
22
23
  } = $props<{
23
24
  title?: string;
24
25
  tabs: TabItem[];
25
26
  idPrefix?: string;
26
27
  selectedTabId?: string | null;
27
28
  autoAddHeadings?: boolean;
29
+ forceTabBehavior?: boolean;
28
30
  }>();
29
31
 
30
32
  // Component state variables
@@ -32,6 +34,9 @@
32
34
  let isSupported = $state(false);
33
35
  let isMobile = $state(false);
34
36
 
37
+ // Derived value: use mobile behavior only if isMobile is true AND forceTabBehavior is false
38
+ let useMobileBehavior = $derived(isMobile && !forceTabBehavior);
39
+
35
40
  // DOM element references for programmatic focus
36
41
  let tabElements: { [key: string]: HTMLAnchorElement } = {};
37
42
 
@@ -56,7 +61,7 @@
56
61
  }
57
62
 
58
63
  // Update URL hash on non-mobile views
59
- if (!isMobile) {
64
+ if (!useMobileBehavior) {
60
65
  // Use history.replaceState to update the displayed URL hash without causing scroll/navigation.
61
66
  const currentUrl = window.location.href;
62
67
  const hashIndex = currentUrl.indexOf("#");
@@ -67,10 +72,12 @@
67
72
  }
68
73
  }
69
74
 
75
+ //$inspect(isSupported, "isSupported");
76
+
70
77
  // Handle keyboard navigation
71
78
  function handleKeydown(event: KeyboardEvent, currentIndex: number): void {
72
79
  // Skip navigation on mobile or if component isn't ready
73
- if (isMobile || !isSupported || !isInitialized) return;
80
+ if (useMobileBehavior || !isSupported || !isInitialized) return;
74
81
 
75
82
  // Initialize to null, indicating no valid navigation key pressed yet.
76
83
  // Will be updated to a valid index (0+) if ArrowLeft/Right is pressed.
@@ -107,7 +114,7 @@
107
114
  // Handle tab click
108
115
  function handleTabClick(event: MouseEvent, tabId: string): void {
109
116
  // On mobile or without JS support, let default browser behavior happen
110
- if (isMobile || !isSupported) return;
117
+ if (useMobileBehavior || !isSupported) return;
111
118
  event.preventDefault();
112
119
  selectTab(tabId);
113
120
  }
@@ -115,7 +122,7 @@
115
122
  // Handle hash change
116
123
  function handleHashChange(): void {
117
124
  // Skip on mobile or when not properly initialized
118
- if (isMobile || !isSupported || !isInitialized) return;
125
+ if (useMobileBehavior || !isSupported || !isInitialized) return;
119
126
 
120
127
  const hash = window.location.hash.substring(1);
121
128
  if (hash && tabs.some((tab) => tab.id === hash)) {
@@ -225,32 +232,45 @@
225
232
  });
226
233
  </script>
227
234
 
228
- <div class="govuk-tabs" data-module="govuk-tabs">
235
+ <div
236
+ class="govuk-tabs"
237
+ data-module="govuk-tabs"
238
+ data-force-desktop={forceTabBehavior || null}
239
+ >
229
240
  <h2 class="govuk-tabs__title">
230
241
  {title}
231
242
  </h2>
232
243
 
233
244
  <ul
234
245
  class="govuk-tabs__list"
235
- role={isSupported && !isMobile ? "tablist" : null}
246
+ role={isSupported && !useMobileBehavior ? "tablist" : null}
236
247
  >
237
248
  {#each tabs as tab, index}
238
249
  {@const isSelected = selectedTabId === tab.id}
239
250
  {#key tab.id}
240
251
  <li
241
252
  class="govuk-tabs__list-item"
242
- class:govuk-tabs__list-item--selected={isSelected && !isMobile}
243
- role={isSupported && !isMobile ? "presentation" : null}
253
+ class:govuk-tabs__list-item--selected={isSelected &&
254
+ !useMobileBehavior}
255
+ role={isSupported && !useMobileBehavior ? "presentation" : null}
244
256
  >
245
257
  <!-- svelte-ignore binding_property_non_reactive -->
246
258
  <a
247
259
  class="govuk-tabs__tab"
248
260
  href={"#" + tab.id}
249
- id={isSupported && !isMobile ? `${idPrefix}_${tab.id}` : null}
250
- role={isSupported && !isMobile ? "tab" : null}
251
- aria-controls={isSupported && !isMobile ? tab.id : null}
252
- aria-selected={isSupported && !isMobile ? isSelected : null}
253
- tabindex={isSupported && !isMobile ? (isSelected ? 0 : -1) : null}
261
+ id={isSupported && !useMobileBehavior
262
+ ? `${idPrefix}_${tab.id}`
263
+ : null}
264
+ role={isSupported && !useMobileBehavior ? "tab" : null}
265
+ aria-controls={isSupported && !useMobileBehavior ? tab.id : null}
266
+ aria-selected={isSupported && !useMobileBehavior
267
+ ? isSelected
268
+ : null}
269
+ tabindex={isSupported && !useMobileBehavior
270
+ ? isSelected
271
+ ? 0
272
+ : -1
273
+ : null}
254
274
  onclick={(e) => handleTabClick(e, tab.id)}
255
275
  onkeydown={(e) => handleKeydown(e, index)}
256
276
  bind:this={tabElements[tab.id]}
@@ -266,13 +286,15 @@
266
286
  {@const isSelected = selectedTabId === tab.id}
267
287
  <div
268
288
  class="govuk-tabs__panel"
269
- class:govuk-tabs__panel--hidden={!isSelected && isSupported && !isMobile}
289
+ class:govuk-tabs__panel--hidden={!isSelected &&
290
+ isSupported &&
291
+ !useMobileBehavior}
270
292
  id={tab.id}
271
- role={isSupported && !isMobile ? "tabpanel" : null}
272
- aria-labelledby={isSupported && !isMobile
293
+ role={isSupported && !useMobileBehavior ? "tabpanel" : null}
294
+ aria-labelledby={isSupported && !useMobileBehavior
273
295
  ? `${idPrefix}_${tab.id}`
274
296
  : null}
275
- hidden={!isSelected && isSupported && !isMobile}
297
+ hidden={!isSelected && isSupported && !useMobileBehavior}
276
298
  >
277
299
  {#if autoAddHeadings}
278
300
  <h2 class="govuk-heading-l">{tab.label}</h2>
@@ -287,7 +309,8 @@
287
309
  {:else if tab.content satisfies Snippet}
288
310
  {@render tab.content()}
289
311
  {:else if tab.content}
290
- <svelte:component this={tab.content} />
312
+ {@const Component = tab.content}
313
+ <Component />
291
314
  {/if}
292
315
  </div>
293
316
  {/each}
@@ -303,4 +326,155 @@
303
326
  .govuk-tabs__panel--hidden {
304
327
  display: none;
305
328
  }
329
+
330
+ /*
331
+ * Force desktop tab appearance when forceTabBehavior is enabled
332
+ * These styles are copied verbatim from GOV.UK Frontend's desktop (40.0625em+) styles
333
+ * but applied at mobile breakpoints when data-force-desktop attribute is present
334
+ */
335
+ @media (max-width: 40.0624em) {
336
+ :global(.govuk-frontend-supported)
337
+ .govuk-tabs[data-force-desktop]
338
+ .govuk-tabs__list {
339
+ margin-bottom: 0;
340
+ border-bottom: 1px solid #b1b4b6;
341
+ }
342
+
343
+ :global(.govuk-frontend-supported)
344
+ .govuk-tabs[data-force-desktop]
345
+ .govuk-tabs__list:after {
346
+ content: "";
347
+ display: block;
348
+ clear: both;
349
+ }
350
+
351
+ :global(.govuk-frontend-supported)
352
+ .govuk-tabs[data-force-desktop]
353
+ .govuk-tabs__title {
354
+ display: none;
355
+ }
356
+
357
+ :global(.govuk-frontend-supported)
358
+ .govuk-tabs[data-force-desktop]
359
+ .govuk-tabs__list-item {
360
+ position: relative;
361
+ margin-right: 5px;
362
+ margin-bottom: 0;
363
+ margin-left: 0;
364
+ padding: 10px 20px;
365
+ float: left;
366
+ background-color: #f3f2f1;
367
+ text-align: center;
368
+ }
369
+
370
+ :global(.govuk-frontend-supported)
371
+ .govuk-tabs[data-force-desktop]
372
+ .govuk-tabs__list-item:before {
373
+ content: none;
374
+ }
375
+
376
+ :global(.govuk-frontend-supported)
377
+ .govuk-tabs[data-force-desktop]
378
+ .govuk-tabs__list-item--selected {
379
+ position: relative;
380
+ margin-top: -5px;
381
+ margin-bottom: -1px;
382
+ padding: 14px 19px 16px;
383
+ border: 1px solid #b1b4b6;
384
+ border-bottom: 0;
385
+ background-color: #fff;
386
+ }
387
+
388
+ :global(.govuk-frontend-supported)
389
+ .govuk-tabs[data-force-desktop]
390
+ .govuk-tabs__list-item--selected
391
+ .govuk-tabs__tab {
392
+ text-decoration: none;
393
+ }
394
+
395
+ :global(.govuk-frontend-supported)
396
+ .govuk-tabs[data-force-desktop]
397
+ .govuk-tabs__tab {
398
+ margin-bottom: 0;
399
+ }
400
+
401
+ :global(.govuk-frontend-supported)
402
+ .govuk-tabs[data-force-desktop]
403
+ .govuk-tabs__tab:link,
404
+ :global(.govuk-frontend-supported)
405
+ .govuk-tabs[data-force-desktop]
406
+ .govuk-tabs__tab:visited {
407
+ color: #0b0c0c;
408
+ }
409
+
410
+ @media print {
411
+ :global(.govuk-frontend-supported)
412
+ .govuk-tabs[data-force-desktop]
413
+ .govuk-tabs__tab:link,
414
+ :global(.govuk-frontend-supported)
415
+ .govuk-tabs[data-force-desktop]
416
+ .govuk-tabs__tab:visited {
417
+ color: #000;
418
+ }
419
+ }
420
+
421
+ :global(.govuk-frontend-supported)
422
+ .govuk-tabs[data-force-desktop]
423
+ .govuk-tabs__tab:hover {
424
+ color: rgba(11, 12, 12, 0.99);
425
+ }
426
+
427
+ :global(.govuk-frontend-supported)
428
+ .govuk-tabs[data-force-desktop]
429
+ .govuk-tabs__tab:active,
430
+ :global(.govuk-frontend-supported)
431
+ .govuk-tabs[data-force-desktop]
432
+ .govuk-tabs__tab:focus {
433
+ color: #0b0c0c;
434
+ }
435
+
436
+ @media print {
437
+ :global(.govuk-frontend-supported)
438
+ .govuk-tabs[data-force-desktop]
439
+ .govuk-tabs__tab:active,
440
+ :global(.govuk-frontend-supported)
441
+ .govuk-tabs[data-force-desktop]
442
+ .govuk-tabs__tab:focus {
443
+ color: #000;
444
+ }
445
+ }
446
+
447
+ :global(.govuk-frontend-supported)
448
+ .govuk-tabs[data-force-desktop]
449
+ .govuk-tabs__tab:after {
450
+ content: "";
451
+ position: absolute;
452
+ top: 0;
453
+ right: 0;
454
+ bottom: 0;
455
+ left: 0;
456
+ }
457
+
458
+ :global(.govuk-frontend-supported)
459
+ .govuk-tabs[data-force-desktop]
460
+ .govuk-tabs__panel {
461
+ margin-bottom: 0;
462
+ padding: 30px 20px;
463
+ border: 1px solid #b1b4b6;
464
+ border-top: 0;
465
+ }
466
+
467
+ :global(.govuk-frontend-supported)
468
+ .govuk-tabs[data-force-desktop]
469
+ .govuk-tabs__panel
470
+ > :last-child {
471
+ margin-bottom: 0;
472
+ }
473
+
474
+ :global(.govuk-frontend-supported)
475
+ .govuk-tabs[data-force-desktop]
476
+ .govuk-tabs__panel--hidden {
477
+ display: none;
478
+ }
479
+ }
306
480
  </style>
@@ -12,6 +12,7 @@ type $$ComponentProps = {
12
12
  idPrefix?: string;
13
13
  selectedTabId?: string | null;
14
14
  autoAddHeadings?: boolean;
15
+ forceTabBehavior?: boolean;
15
16
  };
16
17
  declare const Tabs: import("svelte").Component<$$ComponentProps, {}, "selectedTabId">;
17
18
  type Tabs = ReturnType<typeof Tabs>;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import "./main.css";
2
2
  export { default as InsetText } from './components/content/InsetText.svelte';
3
+ export { default as Tag } from './components/content/Tag.svelte';
3
4
  export { default as WarningText } from './components/content/WarningText.svelte';
5
+ export { default as Histogram } from './components/data-vis/Histogram.svelte';
4
6
  export { default as Axis } from './components/data-vis/axis/Axis.svelte';
5
7
  export { default as Ticks } from './components/data-vis/axis/Ticks.svelte';
6
8
  export { default as Line } from './components/data-vis/line-chart/Line.svelte';
@@ -28,8 +30,11 @@ export { default as MobileNav } from './components/layout/service-navigation-nes
28
30
  export { default as ServiceNavigationNestedMobile } from './components/layout/service-navigation-nested-mobile/ServiceNavigationNestedMobile.svelte';
29
31
  export { default as SideNav } from './components/layout/service-navigation-nested-mobile/SideNav.svelte';
30
32
  export { default as Accordion } from './components/ui/Accordion.svelte';
33
+ export { default as BasicMultiSelect } from './components/ui/BasicMultiSelect.svelte';
31
34
  export { default as Button } from './components/ui/Button.svelte';
32
35
  export { default as Card } from './components/ui/Card.svelte';
36
+ export { default as CardHeader } from './components/ui/CardHeader.svelte';
37
+ export { default as ChartExporter } from './components/ui/ChartExporter.svelte';
33
38
  export { default as CheckBox } from './components/ui/CheckBox.svelte';
34
39
  export { default as ContentsList } from './components/ui/ContentsList.svelte';
35
40
  export { default as CookieBanner } from './components/ui/CookieBanner.svelte';
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // this file is auto-generated — do not edit by hand
2
2
  import "./main.css";
3
3
  export { default as InsetText } from './components/content/InsetText.svelte';
4
+ export { default as Tag } from './components/content/Tag.svelte';
4
5
  export { default as WarningText } from './components/content/WarningText.svelte';
6
+ export { default as Histogram } from './components/data-vis/Histogram.svelte';
5
7
  export { default as Axis } from './components/data-vis/axis/Axis.svelte';
6
8
  export { default as Ticks } from './components/data-vis/axis/Ticks.svelte';
7
9
  export { default as Line } from './components/data-vis/line-chart/Line.svelte';
@@ -29,8 +31,11 @@ export { default as MobileNav } from './components/layout/service-navigation-nes
29
31
  export { default as ServiceNavigationNestedMobile } from './components/layout/service-navigation-nested-mobile/ServiceNavigationNestedMobile.svelte';
30
32
  export { default as SideNav } from './components/layout/service-navigation-nested-mobile/SideNav.svelte';
31
33
  export { default as Accordion } from './components/ui/Accordion.svelte';
34
+ export { default as BasicMultiSelect } from './components/ui/BasicMultiSelect.svelte';
32
35
  export { default as Button } from './components/ui/Button.svelte';
33
36
  export { default as Card } from './components/ui/Card.svelte';
37
+ export { default as CardHeader } from './components/ui/CardHeader.svelte';
38
+ export { default as ChartExporter } from './components/ui/ChartExporter.svelte';
34
39
  export { default as CheckBox } from './components/ui/CheckBox.svelte';
35
40
  export { default as ContentsList } from './components/ui/ContentsList.svelte';
36
41
  export { default as CookieBanner } from './components/ui/CookieBanner.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@communitiesuk/svelte-component-library",
3
- "version": "0.1.19-beta.3",
3
+ "version": "0.1.19-beta.33",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/communitiesuk/mhclg_svelte_component_library.git"
@@ -101,13 +101,16 @@
101
101
  "@types/dompurify": "^3.0.5",
102
102
  "accessible-autocomplete": "^3.0.1",
103
103
  "choices.js": "^11.1.0",
104
+ "chroma-js": "^3.2.0",
104
105
  "csv-parser": "^3.0.0",
105
106
  "d3": "^7.9.0",
107
+ "d3-array": "^3.2.4",
106
108
  "decimal.js": "^10.5.0",
107
109
  "dompurify": "^3.2.5",
108
110
  "flowbite-svelte-icons": "^2.0.3",
109
111
  "gh-pages": "^6.3.0",
110
112
  "govuk-frontend": "^5.11.1",
113
+ "html-to-image": "^1.11.13",
111
114
  "labelplacer": "^0.0.0",
112
115
  "leaflet": "^1.9.4",
113
116
  "mapbox-gl": "^1.13.3",