@lavalogic/scoria 0.40.13 → 0.40.15
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 +58 -58
- package/dist/Components/AccordionGroup.svelte +35 -46
- package/dist/Components/AccordionGroupButton.svelte +68 -76
- package/dist/Components/Action.svelte +103 -135
- package/dist/Components/AlertModal.svelte +171 -190
- package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +614 -697
- package/dist/Components/Base/BaseModal.svelte +90 -116
- package/dist/Components/Base/ContextWrapper.svelte +67 -72
- package/dist/Components/Base/Pagination.svelte +173 -196
- package/dist/Components/Base/Snippets.svelte +34 -36
- package/dist/Components/BigRadioSet.svelte +36 -38
- package/dist/Components/Bubble.svelte +78 -101
- package/dist/Components/Button.svelte +175 -208
- package/dist/Components/Checkbox.svelte +75 -86
- package/dist/Components/CollapsibleCard.svelte +72 -87
- package/dist/Components/CollapsibleMenuGroup.svelte +53 -57
- package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +39 -64
- package/dist/Components/Contexts/ContextMenu.svelte +141 -156
- package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
- package/dist/Components/Contexts/ContextMenuOption.svelte +53 -60
- package/dist/Components/Contexts/Toast.svelte +81 -86
- package/dist/Components/Contexts/ToastContainer.svelte +58 -62
- package/dist/Components/Contexts/Tooltip.svelte +36 -37
- package/dist/Components/DataMatrixIcon.svelte +95 -108
- package/dist/Components/DateInput.svelte +118 -146
- package/dist/Components/DatePicker.svelte +255 -294
- package/dist/Components/DesktopModal.svelte +70 -90
- package/dist/Components/Dial.svelte +167 -197
- package/dist/Components/DimensionInput.svelte +124 -169
- package/dist/Components/DragMenu/DragMenuHolder.svelte +98 -114
- package/dist/Components/DragMenu/DraggableCard.svelte +64 -76
- package/dist/Components/FileCard.svelte +21 -24
- package/dist/Components/FileUpload.svelte +190 -225
- package/dist/Components/GridInput.svelte +159 -196
- package/dist/Components/GridInputSet.svelte +24 -29
- package/dist/Components/HorizontalTabGroup.svelte +73 -89
- package/dist/Components/HorizontalTabGroupButton.svelte +40 -44
- package/dist/Components/Icon.svelte +99 -128
- package/dist/Components/Icons.js +357 -357
- package/dist/Components/InfoAlert.svelte +35 -38
- package/dist/Components/LoadingAnimation.svelte +691 -755
- package/dist/Components/LoadingModal.svelte +36 -44
- package/dist/Components/LoadingOverlay.svelte +22 -26
- package/dist/Components/Modal.svelte +204 -254
- package/dist/Components/MultiSelect.svelte +186 -216
- package/dist/Components/Nav/Nav.svelte +94 -110
- package/dist/Components/Nav/NavServiceMenuList.svelte +57 -61
- package/dist/Components/Nav/NavTab.svelte +58 -62
- package/dist/Components/Nav/ServiceMenuItem.svelte +103 -111
- package/dist/Components/Nav/ServicesNav.svelte +72 -79
- package/dist/Components/NumberInput.svelte +121 -155
- package/dist/Components/OptionCards.svelte +62 -73
- package/dist/Components/PageHeading.svelte +23 -25
- package/dist/Components/PasswordInput.svelte +69 -88
- package/dist/Components/PopoverButton.svelte +151 -0
- package/dist/Components/PopoverButton.svelte.d.ts +9 -0
- package/dist/Components/PopoverButtonProps.d.ts +21 -0
- package/dist/Components/PopoverButtonProps.js +1 -0
- package/dist/Components/Portal.svelte +29 -35
- package/dist/Components/ProgressBubble.svelte +91 -106
- package/dist/Components/QuerySelect.svelte +260 -346
- package/dist/Components/SidebarPanel.svelte +34 -36
- package/dist/Components/SingleSelect.svelte +196 -244
- package/dist/Components/StepButton.svelte +65 -70
- package/dist/Components/StepForm.svelte +115 -135
- package/dist/Components/Switch.svelte +57 -69
- package/dist/Components/Table/ARCHITECTURE.md +298 -298
- package/dist/Components/Table/Body/QuickSearchCell.svelte +578 -655
- package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +42 -51
- package/dist/Components/Table/Body/Rows/ColumnList.svelte +42 -58
- package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +403 -442
- package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +51 -78
- package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +165 -184
- package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +110 -123
- package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +134 -160
- package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +190 -231
- package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +82 -104
- package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +52 -87
- package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +122 -150
- package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +132 -159
- package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +190 -236
- package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +173 -211
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +204 -244
- package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +140 -177
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +188 -217
- package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +173 -193
- package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +166 -187
- package/dist/Components/Table/Body/Rows/TableRow.svelte +245 -288
- package/dist/Components/Table/Body/TableBody.svelte +141 -154
- package/dist/Components/Table/Headers/HighlightAllHeader.svelte +35 -41
- package/dist/Components/Table/Headers/SelectAllHeader.svelte +24 -30
- package/dist/Components/Table/Headers/TableHead.svelte +348 -402
- package/dist/Components/Table/Misc/ColumnPanel.svelte +37 -39
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +35 -39
- package/dist/Components/Table/Misc/FilterInput.svelte +556 -619
- package/dist/Components/Table/Misc/FilterPanel.svelte +170 -183
- package/dist/Components/Table/Misc/FilterPanelModal.svelte +25 -31
- package/dist/Components/Table/Misc/ShareViewModal.svelte +252 -281
- package/dist/Components/Table/Misc/SidePanel.svelte +32 -35
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +574 -629
- package/dist/Components/Table/Misc/TableFooter.svelte +326 -332
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +134 -140
- package/dist/Components/Table/Misc/TableSidebar.svelte +183 -198
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +83 -103
- package/dist/Components/Table/Misc/ToolboxPanel.svelte +83 -100
- package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +88 -107
- package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +163 -190
- package/dist/Components/Table/NestedTable.svelte +102 -128
- package/dist/Components/Table/Table.svelte +531 -663
- package/dist/Components/Test/TestContextConsumer.svelte +11 -13
- package/dist/Components/TextArea.svelte +95 -130
- package/dist/Components/TextInput.svelte +125 -176
- package/dist/Components/ThreeStateRadio.svelte +111 -130
- package/dist/Components/Touch/BoolCard.svelte +33 -45
- package/dist/Components/Touch/DateModal.svelte +164 -204
- package/dist/Components/Touch/EditCard.svelte +48 -59
- package/dist/Components/Touch/InfoCard.svelte +28 -31
- package/dist/Components/Touch/InfoTextCard.svelte +26 -28
- package/dist/Components/Touch/ModalExplanation.svelte +15 -17
- package/dist/Components/Touch/NumberKeyboard.svelte +181 -218
- package/dist/Components/Touch/NumberModal.svelte +59 -79
- package/dist/Components/Touch/PlusMinusCard.svelte +43 -46
- package/dist/Components/Touch/SelectModal.svelte +111 -126
- package/dist/Components/Touch/SummaryCard.svelte +80 -93
- package/dist/Components/Touch/TextAreaModal.svelte +72 -94
- package/dist/Components/Touch/TextModal.svelte +77 -105
- package/dist/Components/Touch/TouchCard.svelte +31 -33
- package/dist/Components/Touch/TouchModal.svelte +214 -270
- package/dist/Components/Touch/UtilityButton.svelte +88 -109
- package/dist/Components/VerticalTabGroup.svelte +60 -78
- package/dist/Components/VerticalTabGroupButton.svelte +54 -58
- package/dist/Helpers/Datamatrix.d.ts +19 -19
- package/dist/Helpers/Datamatrix.js +291 -291
- package/dist/Types/Examples/ExampleModal.svelte +31 -35
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/scss/_basics.scss +12 -12
- package/dist/scss/_colours.scss +134 -134
- package/dist/scss/_mixins.scss +3392 -3392
- package/dist/scss/_motion.scss +57 -57
- package/dist/scss/_sizing.scss +85 -85
- package/dist/scss/_transitions.scss +8 -8
- package/package.json +1 -1
|
@@ -0,0 +1,151 @@
|
|
|
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;
|
|
17
|
+
}
|
|
18
|
+
if (wrapper && e.target instanceof Node && !wrapper.contains(e.target)) {
|
|
19
|
+
open = false;
|
|
20
|
+
}
|
|
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
|
+
|
|
71
|
+
<style>.popover-button {
|
|
72
|
+
position: relative;
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.trigger {
|
|
77
|
+
display: inline-flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
padding: 0.75rem;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
background-color: #ffffff;
|
|
83
|
+
border: solid 1px #cbd4da;
|
|
84
|
+
border-radius: 4px;
|
|
85
|
+
}
|
|
86
|
+
.trigger:hover {
|
|
87
|
+
background-color: #f4f7f9;
|
|
88
|
+
}
|
|
89
|
+
.trigger.open:not(.borderless) {
|
|
90
|
+
border-color: #259fc7;
|
|
91
|
+
}
|
|
92
|
+
.trigger.borderless {
|
|
93
|
+
border: none;
|
|
94
|
+
border-radius: 0;
|
|
95
|
+
background-color: transparent;
|
|
96
|
+
width: 100%;
|
|
97
|
+
height: 100%;
|
|
98
|
+
}
|
|
99
|
+
.trigger.borderless:hover {
|
|
100
|
+
background-color: #f4f7f9;
|
|
101
|
+
}
|
|
102
|
+
.trigger.borderless.open {
|
|
103
|
+
background-color: #f4fbfd;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.popover {
|
|
107
|
+
position: absolute;
|
|
108
|
+
top: calc(100% + 0.6rem);
|
|
109
|
+
z-index: 100;
|
|
110
|
+
background-color: #ffffff;
|
|
111
|
+
border: solid 1px #cbd4da;
|
|
112
|
+
border-radius: 4px;
|
|
113
|
+
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1333333333);
|
|
114
|
+
padding: 1.25rem;
|
|
115
|
+
width: max-content;
|
|
116
|
+
max-width: 80vw;
|
|
117
|
+
}
|
|
118
|
+
.popover.align-center {
|
|
119
|
+
left: 50%;
|
|
120
|
+
transform: translateX(-50%);
|
|
121
|
+
}
|
|
122
|
+
.popover.align-start {
|
|
123
|
+
left: 0;
|
|
124
|
+
}
|
|
125
|
+
.popover.align-end {
|
|
126
|
+
right: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.caret {
|
|
130
|
+
position: absolute;
|
|
131
|
+
top: -6px;
|
|
132
|
+
width: 12px;
|
|
133
|
+
height: 12px;
|
|
134
|
+
background-color: #ffffff;
|
|
135
|
+
border-left: solid 1px #cbd4da;
|
|
136
|
+
border-top: solid 1px #cbd4da;
|
|
137
|
+
transform: rotate(45deg);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.align-center .caret {
|
|
141
|
+
left: 50%;
|
|
142
|
+
margin-left: -6px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.align-start .caret {
|
|
146
|
+
left: 1.5rem;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.align-end .caret {
|
|
150
|
+
right: 1.5rem;
|
|
151
|
+
}</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PopoverButtonProps } from './PopoverButtonProps.js';
|
|
2
|
+
/**
|
|
3
|
+
* An icon button that toggles a floating popover anchored beneath it, with a
|
|
4
|
+
* caret pointing back at the button. The popover holds arbitrary content (the
|
|
5
|
+
* default snippet) and closes on click-outside or Escape.
|
|
6
|
+
*/
|
|
7
|
+
declare const PopoverButton: import("svelte").Component<PopoverButtonProps, {}, "open">;
|
|
8
|
+
type PopoverButton = ReturnType<typeof PopoverButton>;
|
|
9
|
+
export default PopoverButton;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { icons } from './Icons.js';
|
|
3
|
+
/**
|
|
4
|
+
* Props for {@link PopoverButton} — an icon button that toggles a floating
|
|
5
|
+
* popover (with a caret pointing back at the button) holding arbitrary
|
|
6
|
+
* content. Closes on click-outside or Escape.
|
|
7
|
+
*/
|
|
8
|
+
export interface PopoverButtonProps {
|
|
9
|
+
/** Icon shown in the trigger button. */
|
|
10
|
+
icon: keyof typeof icons;
|
|
11
|
+
/** Accessible label for the trigger button. */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Popover contents. */
|
|
14
|
+
children: Snippet;
|
|
15
|
+
/** Horizontal alignment of the popover relative to the button. Defaults to `'center'`. */
|
|
16
|
+
align?: 'center' | 'start' | 'end';
|
|
17
|
+
/** Drop the trigger's border so it can sit flush inside a grouped bar. */
|
|
18
|
+
borderless?: boolean;
|
|
19
|
+
/** Two-way bindable open state. */
|
|
20
|
+
open?: boolean;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,36 +1,30 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
aria-
|
|
89
|
-
aria-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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>
|