@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.
- package/README.md +7 -0
- package/dist/components/content/Tag.svelte +32 -0
- package/dist/components/content/Tag.svelte.d.ts +13 -0
- package/dist/components/data-vis/Histogram.svelte +302 -0
- package/dist/components/data-vis/Histogram.svelte.d.ts +75 -0
- package/dist/components/data-vis/axis/Axis.svelte +217 -34
- package/dist/components/data-vis/axis/Axis.svelte.d.ts +38 -30
- package/dist/components/data-vis/axis/Ticks.svelte +142 -78
- package/dist/components/data-vis/axis/Ticks.svelte.d.ts +28 -31
- package/dist/components/data-vis/line-chart/LineChart.svelte +51 -21
- package/dist/components/data-vis/line-chart/LineChart.svelte.d.ts +14 -6
- package/dist/components/data-vis/line-chart/ValueLabel.svelte +2 -1
- package/dist/components/data-vis/line-chart/ValueLabel.svelte.d.ts +2 -0
- package/dist/components/data-vis/position-chart/PositionChart.svelte +278 -122
- package/dist/components/data-vis/position-chart/PositionChart.svelte.d.ts +37 -5
- package/dist/components/data-vis/position-chart/PositionChartAxis.svelte +59 -48
- package/dist/components/data-vis/position-chart/PositionChartAxis.svelte.d.ts +4 -4
- package/dist/components/layout/Footer.svelte +9 -0
- package/dist/components/layout/Footer.svelte.d.ts +1 -0
- package/dist/components/layout/PhaseBanner.svelte +10 -1
- package/dist/components/layout/PhaseBanner.svelte.d.ts +1 -0
- package/dist/components/layout/ServiceNavigation.svelte +19 -1
- package/dist/components/layout/ServiceNavigation.svelte.d.ts +2 -0
- package/dist/components/ui/BasicMultiSelect.svelte +716 -0
- package/dist/components/ui/BasicMultiSelect.svelte.d.ts +18 -0
- package/dist/components/ui/Button.svelte +1 -0
- package/dist/components/ui/Card.svelte +48 -60
- package/dist/components/ui/Card.svelte.d.ts +26 -12
- package/dist/components/ui/CardHeader.svelte +46 -0
- package/dist/components/ui/CardHeader.svelte.d.ts +21 -0
- package/dist/components/ui/ChartExporter.svelte +142 -0
- package/dist/components/ui/ChartExporter.svelte.d.ts +16 -0
- package/dist/components/ui/CheckBox.svelte +1 -0
- package/dist/components/ui/Details.svelte +47 -8
- package/dist/components/ui/Details.svelte.d.ts +8 -10
- package/dist/components/ui/Masthead.svelte +44 -6
- package/dist/components/ui/Masthead.svelte.d.ts +6 -0
- package/dist/components/ui/RelatedContent.svelte +4 -1
- package/dist/components/ui/RelatedContent.svelte.d.ts +1 -0
- package/dist/components/ui/SearchAutocomplete.svelte +69 -44
- package/dist/components/ui/SearchAutocomplete.svelte.d.ts +1 -0
- package/dist/components/ui/Select.svelte +18 -7
- package/dist/components/ui/Tabs.svelte +192 -18
- package/dist/components/ui/Tabs.svelte.d.ts +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- 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
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
422
|
+
// Mark as accepted to prevent form submit handler from processing again
|
|
426
423
|
const inputElement =
|
|
427
424
|
autocompleteInstance?.inputElement as HTMLInputElement;
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
//
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
|
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(
|
|
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
|
|
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:
|
|
229
|
-
|
|
230
|
-
align-items:
|
|
231
|
-
|
|
232
|
-
|
|
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;
|
|
242
|
-
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
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 && !
|
|
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 &&
|
|
243
|
-
|
|
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 && !
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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 &&
|
|
289
|
+
class:govuk-tabs__panel--hidden={!isSelected &&
|
|
290
|
+
isSupported &&
|
|
291
|
+
!useMobileBehavior}
|
|
270
292
|
id={tab.id}
|
|
271
|
-
role={isSupported && !
|
|
272
|
-
aria-labelledby={isSupported && !
|
|
293
|
+
role={isSupported && !useMobileBehavior ? "tabpanel" : null}
|
|
294
|
+
aria-labelledby={isSupported && !useMobileBehavior
|
|
273
295
|
? `${idPrefix}_${tab.id}`
|
|
274
296
|
: null}
|
|
275
|
-
hidden={!isSelected && isSupported && !
|
|
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
|
-
|
|
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
|
+
"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",
|