@lavalogic/scoria 0.40.14 → 0.40.16

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 (141) hide show
  1. package/README.md +58 -58
  2. package/dist/Components/AccordionGroup.svelte +35 -46
  3. package/dist/Components/AccordionGroupButton.svelte +68 -76
  4. package/dist/Components/Action.svelte +103 -135
  5. package/dist/Components/AlertModal.svelte +171 -190
  6. package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +614 -697
  7. package/dist/Components/Base/BaseModal.svelte +90 -116
  8. package/dist/Components/Base/ContextWrapper.svelte +67 -72
  9. package/dist/Components/Base/Pagination.svelte +173 -196
  10. package/dist/Components/Base/Snippets.svelte +34 -36
  11. package/dist/Components/BigRadioSet.svelte +36 -38
  12. package/dist/Components/Bubble.svelte +78 -101
  13. package/dist/Components/Button.svelte +175 -208
  14. package/dist/Components/Checkbox.svelte +75 -86
  15. package/dist/Components/CollapsibleCard.svelte +72 -86
  16. package/dist/Components/CollapsibleMenuGroup.svelte +52 -56
  17. package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +39 -64
  18. package/dist/Components/Contexts/ContextMenu.svelte +141 -156
  19. package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
  20. package/dist/Components/Contexts/ContextMenuOption.svelte +53 -60
  21. package/dist/Components/Contexts/Toast.svelte +81 -86
  22. package/dist/Components/Contexts/ToastContainer.svelte +58 -62
  23. package/dist/Components/Contexts/Tooltip.svelte +36 -37
  24. package/dist/Components/DataMatrixIcon.svelte +95 -108
  25. package/dist/Components/DateInput.svelte +118 -146
  26. package/dist/Components/DatePicker.svelte +255 -294
  27. package/dist/Components/DesktopModal.svelte +70 -90
  28. package/dist/Components/Dial.svelte +167 -197
  29. package/dist/Components/DimensionInput.svelte +124 -169
  30. package/dist/Components/DragMenu/DragMenuHolder.svelte +98 -114
  31. package/dist/Components/DragMenu/DraggableCard.svelte +64 -76
  32. package/dist/Components/FileCard.svelte +21 -24
  33. package/dist/Components/FileUpload.svelte +190 -225
  34. package/dist/Components/GridInput.svelte +159 -196
  35. package/dist/Components/GridInputSet.svelte +24 -29
  36. package/dist/Components/HorizontalTabGroup.svelte +73 -89
  37. package/dist/Components/HorizontalTabGroupButton.svelte +40 -44
  38. package/dist/Components/Icon.svelte +99 -128
  39. package/dist/Components/Icons.js +357 -357
  40. package/dist/Components/InfoAlert.svelte +35 -38
  41. package/dist/Components/LoadingAnimation.svelte +691 -755
  42. package/dist/Components/LoadingModal.svelte +36 -44
  43. package/dist/Components/LoadingOverlay.svelte +22 -26
  44. package/dist/Components/Modal.svelte +204 -254
  45. package/dist/Components/MultiSelect.svelte +186 -216
  46. package/dist/Components/Nav/Nav.svelte +94 -110
  47. package/dist/Components/Nav/NavServiceMenuList.svelte +57 -61
  48. package/dist/Components/Nav/NavTab.svelte +58 -62
  49. package/dist/Components/Nav/ServiceMenuItem.svelte +103 -111
  50. package/dist/Components/Nav/ServicesNav.svelte +72 -79
  51. package/dist/Components/NumberInput.svelte +121 -155
  52. package/dist/Components/OptionCards.svelte +62 -73
  53. package/dist/Components/PageHeading.svelte +23 -25
  54. package/dist/Components/PasswordInput.svelte +69 -88
  55. package/dist/Components/PopoverButton.svelte +69 -82
  56. package/dist/Components/Portal.svelte +29 -35
  57. package/dist/Components/ProgressBubble.svelte +91 -106
  58. package/dist/Components/QuerySelect.svelte +260 -346
  59. package/dist/Components/SidebarPanel.svelte +34 -36
  60. package/dist/Components/SingleSelect.svelte +196 -244
  61. package/dist/Components/StepButton.svelte +65 -70
  62. package/dist/Components/StepForm.svelte +115 -135
  63. package/dist/Components/Switch.svelte +57 -69
  64. package/dist/Components/Table/ARCHITECTURE.md +298 -298
  65. package/dist/Components/Table/Body/QuickSearchCell.svelte +578 -655
  66. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +42 -51
  67. package/dist/Components/Table/Body/Rows/ColumnList.svelte +42 -58
  68. package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +403 -442
  69. package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +51 -78
  70. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +165 -184
  71. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +110 -123
  72. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +134 -160
  73. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +190 -231
  74. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +82 -104
  75. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +52 -87
  76. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +122 -150
  77. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +132 -159
  78. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +190 -236
  79. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +173 -211
  80. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +204 -244
  81. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +140 -177
  82. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +188 -217
  83. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +173 -193
  84. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +166 -187
  85. package/dist/Components/Table/Body/Rows/TableRow.svelte +245 -288
  86. package/dist/Components/Table/Body/TableBody.svelte +141 -154
  87. package/dist/Components/Table/ColumnFactory.svelte.js +1 -0
  88. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +35 -41
  89. package/dist/Components/Table/Headers/SelectAllHeader.svelte +24 -30
  90. package/dist/Components/Table/Headers/TableHead.svelte +348 -402
  91. package/dist/Components/Table/Misc/ColumnPanel.svelte +37 -39
  92. package/dist/Components/Table/Misc/ColumnPanelModal.svelte +35 -39
  93. package/dist/Components/Table/Misc/FilterInput.svelte +556 -619
  94. package/dist/Components/Table/Misc/FilterPanel.svelte +170 -183
  95. package/dist/Components/Table/Misc/FilterPanelModal.svelte +25 -31
  96. package/dist/Components/Table/Misc/ShareViewModal.svelte +252 -281
  97. package/dist/Components/Table/Misc/SidePanel.svelte +32 -35
  98. package/dist/Components/Table/Misc/TableConfigurationModal.svelte +574 -629
  99. package/dist/Components/Table/Misc/TableFooter.svelte +326 -332
  100. package/dist/Components/Table/Misc/TableHorizontalBar.svelte +134 -140
  101. package/dist/Components/Table/Misc/TableSidebar.svelte +183 -198
  102. package/dist/Components/Table/Misc/TableViewDropdown.svelte +83 -103
  103. package/dist/Components/Table/Misc/ToolboxPanel.svelte +83 -100
  104. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +88 -107
  105. package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +163 -190
  106. package/dist/Components/Table/NestedTable.svelte +102 -128
  107. package/dist/Components/Table/Table.svelte +531 -663
  108. package/dist/Components/Table/Types/Columns/Definitions/Actions/ActionsDef.svelte.d.ts +8 -6
  109. package/dist/Components/Table/Types/Columns/Definitions/Actions/ActionsDef.svelte.js +3 -3
  110. package/dist/Components/Test/TestContextConsumer.svelte +11 -13
  111. package/dist/Components/TextArea.svelte +95 -130
  112. package/dist/Components/TextInput.svelte +125 -176
  113. package/dist/Components/ThreeStateRadio.svelte +111 -130
  114. package/dist/Components/Touch/BoolCard.svelte +33 -45
  115. package/dist/Components/Touch/DateModal.svelte +164 -204
  116. package/dist/Components/Touch/EditCard.svelte +48 -59
  117. package/dist/Components/Touch/InfoCard.svelte +28 -31
  118. package/dist/Components/Touch/InfoTextCard.svelte +26 -28
  119. package/dist/Components/Touch/ModalExplanation.svelte +15 -17
  120. package/dist/Components/Touch/NumberKeyboard.svelte +181 -218
  121. package/dist/Components/Touch/NumberModal.svelte +59 -79
  122. package/dist/Components/Touch/PlusMinusCard.svelte +43 -46
  123. package/dist/Components/Touch/SelectModal.svelte +111 -126
  124. package/dist/Components/Touch/SummaryCard.svelte +80 -93
  125. package/dist/Components/Touch/TextAreaModal.svelte +72 -94
  126. package/dist/Components/Touch/TextModal.svelte +77 -105
  127. package/dist/Components/Touch/TouchCard.svelte +31 -33
  128. package/dist/Components/Touch/TouchModal.svelte +214 -270
  129. package/dist/Components/Touch/UtilityButton.svelte +88 -109
  130. package/dist/Components/VerticalTabGroup.svelte +60 -78
  131. package/dist/Components/VerticalTabGroupButton.svelte +54 -58
  132. package/dist/Helpers/Datamatrix.d.ts +19 -19
  133. package/dist/Helpers/Datamatrix.js +291 -291
  134. package/dist/Types/Examples/ExampleModal.svelte +31 -35
  135. package/dist/scss/_basics.scss +12 -12
  136. package/dist/scss/_colours.scss +134 -134
  137. package/dist/scss/_mixins.scss +3392 -3392
  138. package/dist/scss/_motion.scss +57 -57
  139. package/dist/scss/_sizing.scss +85 -85
  140. package/dist/scss/_transitions.scss +8 -8
  141. package/package.json +1 -1
@@ -1,86 +1,73 @@
1
- <svelte:options runes />
2
-
3
- <!--
4
- @component
5
- An icon button that toggles a floating popover anchored beneath it, with a
6
- caret pointing back at the button. The popover holds arbitrary content (the
7
- default snippet) and closes on click-outside or Escape.
8
- -->
9
- <script lang="ts">
10
- import { Colour } from '../scss/colours.js';
11
- import { Size } from '../Types/Internal/Size.js';
12
- import Icon from './Icon.svelte';
13
- import type { PopoverButtonProps } from './PopoverButtonProps.js';
14
-
15
- let {
16
- icon,
17
- label,
18
- children,
19
- align = 'center',
20
- borderless = false,
21
- open = $bindable(false),
22
- }: PopoverButtonProps = $props();
23
-
24
- let wrapper: HTMLDivElement | undefined = $state();
25
-
26
- function onWindowPointerDown(e: MouseEvent) {
27
- if (!open) {
28
- return;
29
- }
30
- if (wrapper && e.target instanceof Node && !wrapper.contains(e.target)) {
31
- open = false;
32
- }
1
+ <svelte:options runes />
2
+
3
+ <!--
4
+ @component
5
+ An icon button that toggles a floating popover anchored beneath it, with a
6
+ caret pointing back at the button. The popover holds arbitrary content (the
7
+ default snippet) and closes on click-outside or Escape.
8
+ -->
9
+ <script lang="ts">import { Colour } from "../scss/colours.js";
10
+ import { Size } from "../Types/Internal/Size.js";
11
+ import Icon from "./Icon.svelte";
12
+ let { icon, label, children, align = "center", borderless = false, open = $bindable(false) } = $props();
13
+ let wrapper = $state();
14
+ function onWindowPointerDown(e) {
15
+ if (!open) {
16
+ return;
33
17
  }
34
-
35
- function onWindowKeydown(e: KeyboardEvent) {
36
- if (open && e.key === 'Escape') {
37
- open = false;
38
- }
18
+ if (wrapper && e.target instanceof Node && !wrapper.contains(e.target)) {
19
+ open = false;
39
20
  }
40
- </script>
41
-
42
- <svelte:window
43
- onpointerdown={onWindowPointerDown}
44
- onkeydown={onWindowKeydown}
45
- />
46
-
47
- <div
48
- class="popover-button"
49
- bind:this={wrapper}
50
- >
51
- <button
52
- type="button"
53
- class="trigger"
54
- class:open
55
- class:borderless
56
- aria-label={label}
57
- aria-expanded={open}
58
- aria-haspopup="dialog"
59
- onclick={() => {
60
- open = !open;
61
- }}
62
- >
63
- <Icon
64
- name={icon}
65
- size={Size.Large}
66
- colour={open ? Colour['$brand-primary'] : Colour['$font-secondary']}
67
- />
68
- </button>
69
-
70
- {#if open}
71
- <div
72
- class="popover align-{align}"
73
- role="dialog"
74
- aria-label={label}
75
- >
76
- <span class="caret"></span>
77
- <div class="popover-inner">
78
- {@render children()}
79
- </div>
80
- </div>
81
- {/if}
82
- </div>
83
-
21
+ }
22
+ function onWindowKeydown(e) {
23
+ if (open && e.key === "Escape") {
24
+ open = false;
25
+ }
26
+ }
27
+ </script>
28
+
29
+ <svelte:window
30
+ onpointerdown={onWindowPointerDown}
31
+ onkeydown={onWindowKeydown}
32
+ />
33
+
34
+ <div
35
+ class="popover-button"
36
+ bind:this={wrapper}
37
+ >
38
+ <button
39
+ type="button"
40
+ class="trigger"
41
+ class:open
42
+ class:borderless
43
+ aria-label={label}
44
+ aria-expanded={open}
45
+ aria-haspopup="dialog"
46
+ onclick={() => {
47
+ open = !open;
48
+ }}
49
+ >
50
+ <Icon
51
+ name={icon}
52
+ size={Size.Large}
53
+ colour={open ? Colour['$brand-primary'] : Colour['$font-secondary']}
54
+ />
55
+ </button>
56
+
57
+ {#if open}
58
+ <div
59
+ class="popover align-{align}"
60
+ role="dialog"
61
+ aria-label={label}
62
+ >
63
+ <span class="caret"></span>
64
+ <div class="popover-inner">
65
+ {@render children()}
66
+ </div>
67
+ </div>
68
+ {/if}
69
+ </div>
70
+
84
71
  <style>.popover-button {
85
72
  position: relative;
86
73
  display: inline-flex;
@@ -161,4 +148,4 @@ default snippet) and closes on click-outside or Escape.
161
148
 
162
149
  .align-end .caret {
163
150
  right: 1.5rem;
164
- }</style>
151
+ }</style>
@@ -1,36 +1,30 @@
1
- <svelte:options runes />
2
-
3
- <script lang="ts">
4
- import { browser } from '$app/environment';
5
- import type { PortalProps } from './PortalProps.js';
6
-
7
- let { target = browser ? globalThis.document.body : undefined, children }: PortalProps = $props();
8
-
9
- let ref: HTMLElement | undefined = $state();
10
- let lastTarget: HTMLElement | undefined;
11
-
12
- $effect(() => {
13
- // Identity guard: only re-parent when `target` actually changes.
14
- // `appendChild` already moves the node when called, so this avoids
15
- // unnecessary detach/attach when an upstream `$state` target
16
- // re-fires the effect without changing identity.
17
- if (target && ref && target !== lastTarget) {
18
- if (target.ownerDocument === globalThis.document) {
19
- target.appendChild(ref);
20
- lastTarget = target;
21
- }
1
+ <svelte:options runes />
2
+
3
+ <script lang="ts">import { browser } from "$app/environment";
4
+ let { target = browser ? globalThis.document.body : undefined, children } = $props();
5
+ let ref = $state();
6
+ let lastTarget;
7
+ $effect(() => {
8
+ // Identity guard: only re-parent when `target` actually changes.
9
+ // `appendChild` already moves the node when called, so this avoids
10
+ // unnecessary detach/attach when an upstream `$state` target
11
+ // re-fires the effect without changing identity.
12
+ if (target && ref && target !== lastTarget) {
13
+ if (target.ownerDocument === globalThis.document) {
14
+ target.appendChild(ref);
15
+ lastTarget = target;
22
16
  }
23
-
24
- // Cleanup is necessary, not redundant: without it, the appended
25
- // node would remain inside `target` after the Portal unmounts,
26
- // because `target` outlives the component.
27
- return () => {
28
- ref?.parentNode?.removeChild(ref);
29
- lastTarget = undefined;
30
- };
31
- });
32
- </script>
33
-
34
- <div bind:this={ref}>
35
- {@render children()}
36
- </div>
17
+ }
18
+ // Cleanup is necessary, not redundant: without it, the appended
19
+ // node would remain inside `target` after the Portal unmounts,
20
+ // because `target` outlives the component.
21
+ return () => {
22
+ ref?.parentNode?.removeChild(ref);
23
+ lastTarget = undefined;
24
+ };
25
+ });
26
+ </script>
27
+
28
+ <div bind:this={ref}>
29
+ {@render children()}
30
+ </div>
@@ -1,109 +1,94 @@
1
- <svelte:options runes />
2
-
3
- <script lang="ts">
4
- import { useAsyncFlag } from '../Helpers/AsyncFlag.svelte.js';
5
- import { getCanvasContext } from '../Helpers/Helpers.svelte.js';
6
- import type { BubbleColour } from './BubbleColour.js';
7
- import type { ProgressBubbleProps } from './ProgressBubbleProps.js';
8
-
9
- const { value, colours }: ProgressBubbleProps = $props();
10
-
11
- const current = $derived(value[0]);
12
- const total = $derived(value[1]);
13
- const progress = $derived(`${current}/${total}`);
14
-
15
- // Clamp the percentage so callers passing `current > total` do not
16
- // blow past the bar's edge.
17
- const percent = $derived(Math.min((current / total) * 100, 100));
18
-
19
- let progressBarRef: HTMLDivElement | undefined = $state();
20
-
21
- // Observed inline-size of the filled bar. A `ResizeObserver` is used
22
- // instead of `getBoundingClientRect()` inside an `$effect`: the latter
23
- // forces a synchronous layout flush on every `progress` change, which
24
- // is expensive inside a table with many `ProgressBubble` cells. The
25
- // observer notifies us only when the bar's actual rendered size
26
- // changes, and does so via a microtask scheduled by the browser so we
27
- // never force layout ourselves.
28
- let barWidth = $state(0);
29
- $effect(() => {
30
- if (!progressBarRef) {
31
- return;
32
- }
33
- const ro = new ResizeObserver((entries) => {
34
- const entry = entries[0];
35
- barWidth = entry.borderBoxSize[0]?.inlineSize ?? entry.contentRect.width;
36
- });
37
- ro.observe(progressBarRef);
38
- return () => {
39
- ro.disconnect();
40
- };
1
+ <svelte:options runes />
2
+
3
+ <script lang="ts">import { useAsyncFlag } from "../Helpers/AsyncFlag.svelte.js";
4
+ import { getCanvasContext } from "../Helpers/Helpers.svelte.js";
5
+ const { value, colours } = $props();
6
+ const current = $derived(value[0]);
7
+ const total = $derived(value[1]);
8
+ const progress = $derived(`${current}/${total}`);
9
+ // Clamp the percentage so callers passing `current > total` do not
10
+ // blow past the bar's edge.
11
+ const percent = $derived(Math.min(current / total * 100, 100));
12
+ let progressBarRef = $state();
13
+ // Observed inline-size of the filled bar. A `ResizeObserver` is used
14
+ // instead of `getBoundingClientRect()` inside an `$effect`: the latter
15
+ // forces a synchronous layout flush on every `progress` change, which
16
+ // is expensive inside a table with many `ProgressBubble` cells. The
17
+ // observer notifies us only when the bar's actual rendered size
18
+ // changes, and does so via a microtask scheduled by the browser so we
19
+ // never force layout ourselves.
20
+ let barWidth = $state(0);
21
+ $effect(() => {
22
+ if (!progressBarRef) {
23
+ return;
24
+ }
25
+ const ro = new ResizeObserver((entries) => {
26
+ const entry = entries[0];
27
+ barWidth = entry.borderBoxSize[0]?.inlineSize ?? entry.contentRect.width;
41
28
  });
42
-
43
- // Whether the `current/total` label fits inside the filled bar.
44
- // Measured via a memoised offscreen canvas so we do not trigger
45
- // layout.
46
- const fitsInProgressBar = $derived.by(() => {
47
- const textWidth = getCanvasContext()?.measureText(`__${progress}__`).width ?? 0;
48
- return barWidth > textWidth;
49
- });
50
-
51
- // `colours` may be a bare `BubbleColour`, a Promise resolving to one,
52
- // or undefined. Routed through `useAsyncFlag` which (a) cancels stale
53
- // Promises via a sequence ticket so the freshest value always wins,
54
- // (b) reports errors through `ToastContext` when one is mounted, and
55
- // (c) falls back to `undefined` while no resolution is available.
56
- const awaitedColoursFlag = useAsyncFlag<BubbleColour | undefined>(() => colours, undefined);
57
- const awaitedColours = $derived(awaitedColoursFlag.value);
58
-
59
- // Precompute the wrapper and bar style strings. Each colour comes
60
- // from the trusted `Colour` registry (see `Bubble.svelte` security
61
- // note) so interpolation into `style="..."` is safe.
62
- const wrapperStyle = $derived(
63
- awaitedColours
64
- ? `--bar-background-colour: ${awaitedColours.backgroundColour}; --text-colour: ${awaitedColours.colour};`
65
- : ''
66
- );
67
- const barStyle = $derived(`width: ${percent}%;`);
68
- </script>
69
-
70
- <div
71
- class="progress-wrapper"
72
- style={wrapperStyle}
73
- >
74
- <!--
75
- Native `<progress>` is kept as a fallback for assistive tech that
76
- ignores ARIA progressbar roles. Visually hidden rather than
77
- `display: none` so the element stays in the accessibility tree.
78
- -->
79
- <progress
80
- class="visually-hidden"
81
- value={current}
82
- max={total}>{progress}</progress
83
- >
84
-
85
- <div
86
- class="progress-background"
87
- role="progressbar"
88
- aria-valuenow={current}
89
- aria-valuemin={0}
90
- aria-valuemax={total}
91
- aria-valuetext={progress}
92
- >
93
- <div
94
- class:fits={fitsInProgressBar}
95
- class="progress-value"
96
- bind:this={progressBarRef}
97
- style={barStyle}
98
- >
99
- <span
100
- class:fits={fitsInProgressBar}
101
- class="progress-text">{progress}</span
102
- >
103
- </div>
104
- </div>
105
- </div>
106
-
29
+ ro.observe(progressBarRef);
30
+ return () => {
31
+ ro.disconnect();
32
+ };
33
+ });
34
+ // Whether the `current/total` label fits inside the filled bar.
35
+ // Measured via a memoised offscreen canvas so we do not trigger
36
+ // layout.
37
+ const fitsInProgressBar = $derived.by(() => {
38
+ const textWidth = getCanvasContext()?.measureText(`__${progress}__`).width ?? 0;
39
+ return barWidth > textWidth;
40
+ });
41
+ // `colours` may be a bare `BubbleColour`, a Promise resolving to one,
42
+ // or undefined. Routed through `useAsyncFlag` which (a) cancels stale
43
+ // Promises via a sequence ticket so the freshest value always wins,
44
+ // (b) reports errors through `ToastContext` when one is mounted, and
45
+ // (c) falls back to `undefined` while no resolution is available.
46
+ const awaitedColoursFlag = useAsyncFlag(() => colours, undefined);
47
+ const awaitedColours = $derived(awaitedColoursFlag.value);
48
+ // Precompute the wrapper and bar style strings. Each colour comes
49
+ // from the trusted `Colour` registry (see `Bubble.svelte` security
50
+ // note) so interpolation into `style="..."` is safe.
51
+ const wrapperStyle = $derived(awaitedColours ? `--bar-background-colour: ${awaitedColours.backgroundColour}; --text-colour: ${awaitedColours.colour};` : "");
52
+ const barStyle = $derived(`width: ${percent}%;`);
53
+ </script>
54
+
55
+ <div
56
+ class="progress-wrapper"
57
+ style={wrapperStyle}
58
+ >
59
+ <!--
60
+ Native `<progress>` is kept as a fallback for assistive tech that
61
+ ignores ARIA progressbar roles. Visually hidden rather than
62
+ `display: none` so the element stays in the accessibility tree.
63
+ -->
64
+ <progress
65
+ class="visually-hidden"
66
+ value={current}
67
+ max={total}>{progress}</progress
68
+ >
69
+
70
+ <div
71
+ class="progress-background"
72
+ role="progressbar"
73
+ aria-valuenow={current}
74
+ aria-valuemin={0}
75
+ aria-valuemax={total}
76
+ aria-valuetext={progress}
77
+ >
78
+ <div
79
+ class:fits={fitsInProgressBar}
80
+ class="progress-value"
81
+ bind:this={progressBarRef}
82
+ style={barStyle}
83
+ >
84
+ <span
85
+ class:fits={fitsInProgressBar}
86
+ class="progress-text">{progress}</span
87
+ >
88
+ </div>
89
+ </div>
90
+ </div>
91
+
107
92
  <style>.progress-wrapper {
108
93
  width: 100%;
109
94
  height: 100%;
@@ -172,4 +157,4 @@
172
157
  }
173
158
  .progress-text.fits {
174
159
  color: var(--text-colour, #3a4952);
175
- }</style>
160
+ }</style>