@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
|
@@ -1,166 +1,151 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<!--
|
|
4
|
-
@component
|
|
5
|
-
Visual host for `ContextMenuContext`. Renders the fixed-positioned
|
|
6
|
-
`<ul role="menu">` near the `(x, y)` coordinates the context exposes,
|
|
7
|
-
and clamps the position so the menu never spills off the viewport.
|
|
8
|
-
|
|
9
|
-
Mounted exactly once at the app root by `ContextWrapper`; consumers do
|
|
10
|
-
not render `ContextMenu` directly. Open a menu through the context:
|
|
11
|
-
|
|
12
|
-
```svelte
|
|
13
|
-
<script lang="ts">
|
|
14
|
-
import { ContextMenuContext } from '@lavalogic/scoria';
|
|
15
|
-
import { getContext } from 'svelte';
|
|
16
|
-
|
|
17
|
-
const ctx = getContext<ContextMenuContext>(ContextMenuContext.identifier);
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<button oncontextmenu={(e) => ctx.openContextMenu(e, items)}>
|
|
21
|
-
Right-click me
|
|
22
|
-
</button>
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Keyboard
|
|
26
|
-
|
|
27
|
-
`Escape` closes the menu and returns focus to the previously focused
|
|
28
|
-
element; `ArrowUp` / `ArrowDown` cycle focus through the items.
|
|
29
|
-
-->
|
|
30
|
-
<script lang="ts">
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let _y: number = $state(0);
|
|
45
|
-
|
|
46
|
-
$effect(() => {
|
|
47
|
-
if (contextMenuContext.showMenu) {
|
|
48
|
-
recalculateCoordinates();
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
function recalculateCoordinates() {
|
|
53
|
-
_x = contextMenuContext.x;
|
|
54
|
-
_y = contextMenuContext.y;
|
|
55
|
-
|
|
56
|
-
tick()
|
|
57
|
-
.then(() => {
|
|
58
|
-
const rect = menuEl?.getBoundingClientRect();
|
|
59
|
-
if (!rect) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
_x = Math.min(window.innerWidth - rect.width, _x);
|
|
63
|
-
if (_y > window.innerHeight - rect.height) {
|
|
64
|
-
_y -= rect.height;
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
.catch(devCatch);
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
@component
|
|
5
|
+
Visual host for `ContextMenuContext`. Renders the fixed-positioned
|
|
6
|
+
`<ul role="menu">` near the `(x, y)` coordinates the context exposes,
|
|
7
|
+
and clamps the position so the menu never spills off the viewport.
|
|
8
|
+
|
|
9
|
+
Mounted exactly once at the app root by `ContextWrapper`; consumers do
|
|
10
|
+
not render `ContextMenu` directly. Open a menu through the context:
|
|
11
|
+
|
|
12
|
+
```svelte
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import { ContextMenuContext } from '@lavalogic/scoria';
|
|
15
|
+
import { getContext } from 'svelte';
|
|
16
|
+
|
|
17
|
+
const ctx = getContext<ContextMenuContext>(ContextMenuContext.identifier);
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<button oncontextmenu={(e) => ctx.openContextMenu(e, items)}>
|
|
21
|
+
Right-click me
|
|
22
|
+
</button>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Keyboard
|
|
26
|
+
|
|
27
|
+
`Escape` closes the menu and returns focus to the previously focused
|
|
28
|
+
element; `ArrowUp` / `ArrowDown` cycle focus through the items.
|
|
29
|
+
-->
|
|
30
|
+
<script lang="ts">import { ContextMenuContext } from "../../Contexts/ContextMenuContext.svelte.js";
|
|
31
|
+
import { devCatch } from "../../Helpers/Helpers.svelte.js";
|
|
32
|
+
import { getContext, tick, untrack } from "svelte";
|
|
33
|
+
import { fade } from "svelte/transition";
|
|
34
|
+
import { usePrefersReducedMotion } from "../../Helpers/prefersReducedMotion.svelte.js";
|
|
35
|
+
import ContextMenuOption from "./ContextMenuOption.svelte";
|
|
36
|
+
const contextMenuContext = getContext(ContextMenuContext.identifier);
|
|
37
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
38
|
+
const fadeDuration = $derived(reducedMotion.matches ? 0 : 50);
|
|
39
|
+
let _x = $state(0);
|
|
40
|
+
let _y = $state(0);
|
|
41
|
+
$effect(() => {
|
|
42
|
+
if (contextMenuContext.showMenu) {
|
|
43
|
+
recalculateCoordinates();
|
|
68
44
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
45
|
+
});
|
|
46
|
+
function recalculateCoordinates() {
|
|
47
|
+
_x = contextMenuContext.x;
|
|
48
|
+
_y = contextMenuContext.y;
|
|
49
|
+
tick().then(() => {
|
|
50
|
+
const rect = menuEl?.getBoundingClientRect();
|
|
51
|
+
if (!rect) {
|
|
73
52
|
return;
|
|
74
53
|
}
|
|
75
|
-
|
|
76
|
-
|
|
54
|
+
_x = Math.min(window.innerWidth - rect.width, _x);
|
|
55
|
+
if (_y > window.innerHeight - rect.height) {
|
|
56
|
+
_y -= rect.height;
|
|
77
57
|
}
|
|
78
|
-
|
|
58
|
+
}).catch(devCatch);
|
|
59
|
+
}
|
|
60
|
+
let menuEl = $state();
|
|
61
|
+
function closeOnClickOutside(e) {
|
|
62
|
+
if (!menuEl) {
|
|
63
|
+
return;
|
|
79
64
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
$effect.pre(() => {
|
|
84
|
-
if (contextMenuContext.showMenu) {
|
|
85
|
-
untrack(() => {
|
|
86
|
-
previousElement = document.activeElement as MaybeFocusable;
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
function refocusPrevious() {
|
|
92
|
-
previousElement?.focus?.();
|
|
65
|
+
if (e.target === menuEl || menuEl.contains(e.target)) {
|
|
66
|
+
return;
|
|
93
67
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
const index = items.indexOf(document.activeElement as HTMLElement);
|
|
104
|
-
items.at((index + 1) % items.length)?.focus();
|
|
68
|
+
contextMenuContext.closeMenu();
|
|
69
|
+
}
|
|
70
|
+
let previousElement = $state();
|
|
71
|
+
$effect.pre(() => {
|
|
72
|
+
if (contextMenuContext.showMenu) {
|
|
73
|
+
untrack(() => {
|
|
74
|
+
previousElement = document.activeElement;
|
|
75
|
+
});
|
|
105
76
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
const index = items.indexOf(document.activeElement as HTMLElement);
|
|
116
|
-
items.at((index - 1 + items.length) % items.length)?.focus();
|
|
77
|
+
});
|
|
78
|
+
function refocusPrevious() {
|
|
79
|
+
previousElement?.focus?.();
|
|
80
|
+
}
|
|
81
|
+
function focusNext() {
|
|
82
|
+
if (!menuEl) {
|
|
83
|
+
return;
|
|
117
84
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
85
|
+
const items = [...menuEl.querySelectorAll("[role=\"menuitem\"]")];
|
|
86
|
+
if (items.length === 0) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const index = items.indexOf(document.activeElement);
|
|
90
|
+
items.at((index + 1) % items.length)?.focus();
|
|
91
|
+
}
|
|
92
|
+
function focusPrev() {
|
|
93
|
+
if (!menuEl) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const items = [...menuEl.querySelectorAll("[role=\"menuitem\"]")];
|
|
97
|
+
if (items.length === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const index = items.indexOf(document.activeElement);
|
|
101
|
+
items.at((index - 1 + items.length) % items.length)?.focus();
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<svelte:body onclick={closeOnClickOutside} />
|
|
106
|
+
|
|
107
|
+
{#if contextMenuContext.showMenu}
|
|
108
|
+
<ul
|
|
109
|
+
transition:fade={{ duration: fadeDuration }}
|
|
110
|
+
bind:this={menuEl}
|
|
111
|
+
style="top: {_y}px; left: {_x}px;"
|
|
112
|
+
role="menu"
|
|
113
|
+
aria-label="Context menu"
|
|
114
|
+
tabindex="-1"
|
|
115
|
+
onkeydown={(e) => {
|
|
116
|
+
if (e.key === 'Escape') {
|
|
117
|
+
e.stopImmediatePropagation();
|
|
118
|
+
e.stopPropagation();
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
contextMenuContext.closeMenu();
|
|
121
|
+
refocusPrevious();
|
|
122
|
+
} else if (e.key == 'ArrowUp') {
|
|
123
|
+
e.stopImmediatePropagation();
|
|
124
|
+
e.stopPropagation();
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
focusPrev();
|
|
127
|
+
} else if (e.key == 'ArrowDown') {
|
|
128
|
+
e.stopImmediatePropagation();
|
|
129
|
+
e.stopPropagation();
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
focusNext();
|
|
132
|
+
}
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{#each contextMenuContext.items as item, index (item)}
|
|
136
|
+
<ContextMenuOption
|
|
137
|
+
{index}
|
|
138
|
+
disabled={item.disabled}
|
|
139
|
+
onclick={() => {
|
|
140
|
+
void item.callback();
|
|
141
|
+
contextMenuContext.closeMenu();
|
|
142
|
+
}}
|
|
143
|
+
text={item.text}
|
|
144
|
+
/>
|
|
145
|
+
{/each}
|
|
146
|
+
</ul>
|
|
147
|
+
{/if}
|
|
148
|
+
|
|
164
149
|
<style>ul {
|
|
165
150
|
padding: 0.375rem;
|
|
166
151
|
position: fixed;
|
|
@@ -175,4 +160,4 @@ element; `ArrowUp` / `ArrowDown` cycle focus through the items.
|
|
|
175
160
|
|
|
176
161
|
ul:focus {
|
|
177
162
|
outline: none;
|
|
178
|
-
}</style>
|
|
163
|
+
}</style>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<!--
|
|
4
|
-
@component
|
|
5
|
-
Visual separator for {@link ContextMenu}. Renders a thin horizontal
|
|
6
|
-
rule. The native `<hr>` ARIA mapping is `role="separator"`, which is
|
|
7
|
-
the correct semantic inside a `role="menu"` group, so no explicit
|
|
8
|
-
role is set.
|
|
9
|
-
|
|
10
|
-
Intended for use between groups of `ContextMenuOption` entries inside
|
|
11
|
-
a context menu rendered via the visual host.
|
|
12
|
-
-->
|
|
13
|
-
<hr />
|
|
14
|
-
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
@component
|
|
5
|
+
Visual separator for {@link ContextMenu}. Renders a thin horizontal
|
|
6
|
+
rule. The native `<hr>` ARIA mapping is `role="separator"`, which is
|
|
7
|
+
the correct semantic inside a `role="menu"` group, so no explicit
|
|
8
|
+
role is set.
|
|
9
|
+
|
|
10
|
+
Intended for use between groups of `ContextMenuOption` entries inside
|
|
11
|
+
a context menu rendered via the visual host.
|
|
12
|
+
-->
|
|
13
|
+
<hr />
|
|
14
|
+
|
|
15
15
|
<style>hr {
|
|
16
16
|
border-top: solid 1px #cbd4da;
|
|
17
17
|
width: 100%;
|
|
18
18
|
margin: 2px 0;
|
|
19
|
-
}</style>
|
|
19
|
+
}</style>
|
|
@@ -1,62 +1,55 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<!--
|
|
4
|
-
@component
|
|
5
|
-
A single row inside the {@link ContextMenu} host. Renders a
|
|
6
|
-
`<button role="menuitem">` and assigns a roving `tabindex`: the
|
|
7
|
-
first option (index `0`) receives focus on mount and is the only
|
|
8
|
-
tab stop, all subsequent options carry `tabindex="-1"` so arrow-key
|
|
9
|
-
navigation owns focus traversal within the menu.
|
|
10
|
-
|
|
11
|
-
Consumers do not usually mount `ContextMenuOption` directly; the
|
|
12
|
-
visual host iterates over `ContextMenuContext.items` and renders one
|
|
13
|
-
option per entry.
|
|
14
|
-
-->
|
|
15
|
-
<script lang="ts">
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{#if text}
|
|
54
|
-
{text}
|
|
55
|
-
{:else if children}
|
|
56
|
-
{@render children()}
|
|
57
|
-
{/if}
|
|
58
|
-
</button>
|
|
59
|
-
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
@component
|
|
5
|
+
A single row inside the {@link ContextMenu} host. Renders a
|
|
6
|
+
`<button role="menuitem">` and assigns a roving `tabindex`: the
|
|
7
|
+
first option (index `0`) receives focus on mount and is the only
|
|
8
|
+
tab stop, all subsequent options carry `tabindex="-1"` so arrow-key
|
|
9
|
+
navigation owns focus traversal within the menu.
|
|
10
|
+
|
|
11
|
+
Consumers do not usually mount `ContextMenuOption` directly; the
|
|
12
|
+
visual host iterates over `ContextMenuContext.items` and renders one
|
|
13
|
+
option per entry.
|
|
14
|
+
-->
|
|
15
|
+
<script lang="ts">import { devCatch } from "../../Helpers/Helpers.svelte.js";
|
|
16
|
+
import { tick } from "svelte";
|
|
17
|
+
let { text = "", index, disabled = false, onclick, children } = $props();
|
|
18
|
+
let element = $state();
|
|
19
|
+
$effect(() => {
|
|
20
|
+
void element;
|
|
21
|
+
// Only the first option seeds focus. The check stays inside the
|
|
22
|
+
// effect (rather than gating registration) so Svelte's reactive
|
|
23
|
+
// dependency on `index` is recorded.
|
|
24
|
+
if (index === 0) {
|
|
25
|
+
tick().then(() => {
|
|
26
|
+
element?.focus();
|
|
27
|
+
}).catch(devCatch);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<button
|
|
33
|
+
class="context-menu-item"
|
|
34
|
+
role="menuitem"
|
|
35
|
+
class:disabled
|
|
36
|
+
tabindex={index === 0 ? 0 : -1}
|
|
37
|
+
aria-disabled={disabled ? 'true' : undefined}
|
|
38
|
+
bind:this={element}
|
|
39
|
+
onclick={(e) => {
|
|
40
|
+
e.stopImmediatePropagation();
|
|
41
|
+
e.stopPropagation();
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
void onclick?.(e);
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
{#if text}
|
|
47
|
+
{text}
|
|
48
|
+
{:else if children}
|
|
49
|
+
{@render children()}
|
|
50
|
+
{/if}
|
|
51
|
+
</button>
|
|
52
|
+
|
|
60
53
|
<style>button {
|
|
61
54
|
background-color: #ffffff;
|
|
62
55
|
border: none;
|
|
@@ -85,4 +78,4 @@ button.disabled {
|
|
|
85
78
|
|
|
86
79
|
button.disabled:hover {
|
|
87
80
|
background: #ffffff;
|
|
88
|
-
}</style>
|
|
81
|
+
}</style>
|
|
@@ -1,88 +1,83 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<!--
|
|
4
|
-
@component
|
|
5
|
-
Single toast rendering. Renders a pill near the bottom-right of the
|
|
6
|
-
viewport via `ToastContainer`, sliding in vertically. The severity of
|
|
7
|
-
the underlying toast drives both the colouring and the live-region
|
|
8
|
-
semantics:
|
|
9
|
-
|
|
10
|
-
- `Validity.Invalid` -> `role="alert"`, `aria-live="assertive"`.
|
|
11
|
-
- All other severities -> `role="status"`, `aria-live="polite"`.
|
|
12
|
-
|
|
13
|
-
The slide transition animates the pill's height (the `y` axis) so the
|
|
14
|
-
message keeps its final width for the whole animation — animating the
|
|
15
|
-
`x` axis instead reflows the text from stacked-and-wrapped to a single
|
|
16
|
-
line as the pill widens. It honours `prefers-reduced-motion` through
|
|
17
|
-
the shared `usePrefersReducedMotion` helper; when the user has opted in
|
|
18
|
-
the duration collapses to zero. The copy action is only shown when
|
|
19
|
-
`navigator.clipboard` is present (HTTPS or `localhost`).
|
|
20
|
-
-->
|
|
21
|
-
<script
|
|
22
|
-
lang="ts"
|
|
23
|
-
module
|
|
24
|
-
>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
</div>
|
|
82
|
-
{/if}
|
|
83
|
-
</div>
|
|
84
|
-
</output>
|
|
85
|
-
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
@component
|
|
5
|
+
Single toast rendering. Renders a pill near the bottom-right of the
|
|
6
|
+
viewport via `ToastContainer`, sliding in vertically. The severity of
|
|
7
|
+
the underlying toast drives both the colouring and the live-region
|
|
8
|
+
semantics:
|
|
9
|
+
|
|
10
|
+
- `Validity.Invalid` -> `role="alert"`, `aria-live="assertive"`.
|
|
11
|
+
- All other severities -> `role="status"`, `aria-live="polite"`.
|
|
12
|
+
|
|
13
|
+
The slide transition animates the pill's height (the `y` axis) so the
|
|
14
|
+
message keeps its final width for the whole animation — animating the
|
|
15
|
+
`x` axis instead reflows the text from stacked-and-wrapped to a single
|
|
16
|
+
line as the pill widens. It honours `prefers-reduced-motion` through
|
|
17
|
+
the shared `usePrefersReducedMotion` helper; when the user has opted in
|
|
18
|
+
the duration collapses to zero. The copy action is only shown when
|
|
19
|
+
`navigator.clipboard` is present (HTTPS or `localhost`).
|
|
20
|
+
-->
|
|
21
|
+
<script
|
|
22
|
+
lang="ts"
|
|
23
|
+
module
|
|
24
|
+
>import { ColourSet } from "../../scss/colours.js";
|
|
25
|
+
import { Size } from "../../Types/Internal/Size.js";
|
|
26
|
+
import { Validity } from "../../Types/Internal/Validity.js";
|
|
27
|
+
import { slide } from "svelte/transition";
|
|
28
|
+
import Action from "../Action.svelte";
|
|
29
|
+
import Icon from "../Icon.svelte";
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script lang="ts">import { usePrefersReducedMotion } from "../../Helpers/prefersReducedMotion.svelte.js";
|
|
33
|
+
let { toast, copy } = $props();
|
|
34
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
35
|
+
const slideDuration = $derived(reducedMotion.matches ? 0 : 500);
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<output
|
|
39
|
+
role={toast.result == Validity.Invalid ? 'alert' : 'status'}
|
|
40
|
+
aria-live={toast.result == Validity.Invalid ? 'assertive' : 'polite'}
|
|
41
|
+
class:info={toast.result == Validity.Info}
|
|
42
|
+
class:success={toast.result == Validity.Valid}
|
|
43
|
+
class:warning={toast.result == Validity.Warning}
|
|
44
|
+
class:error={toast.result == Validity.Invalid}
|
|
45
|
+
transition:slide={{ axis: 'y', duration: slideDuration }}
|
|
46
|
+
>
|
|
47
|
+
<div>
|
|
48
|
+
<div class="noshrink">
|
|
49
|
+
{#if toast.copyable != false && navigator.clipboard}
|
|
50
|
+
<Action
|
|
51
|
+
onclick={copy}
|
|
52
|
+
icon={{ name: 'copy' }}
|
|
53
|
+
label="Copy to clipboard"
|
|
54
|
+
size={Size.MediumLarge}
|
|
55
|
+
colourSet={ColourSet.Auxiliary}
|
|
56
|
+
/>
|
|
57
|
+
{:else}
|
|
58
|
+
<Icon
|
|
59
|
+
name="info"
|
|
60
|
+
size={Size.MediumLarge}
|
|
61
|
+
/>
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
<span>{toast.message}</span>
|
|
65
|
+
{#if toast.closeable}
|
|
66
|
+
<div class="noshrink">
|
|
67
|
+
<Action
|
|
68
|
+
size={Size.MediumLarge}
|
|
69
|
+
icon={{ name: 'cross' }}
|
|
70
|
+
label="Dismiss"
|
|
71
|
+
onclick={() => {
|
|
72
|
+
toast.close?.();
|
|
73
|
+
}}
|
|
74
|
+
colourSet={ColourSet.Auxiliary}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
{/if}
|
|
78
|
+
</div>
|
|
79
|
+
</output>
|
|
80
|
+
|
|
86
81
|
<style>output {
|
|
87
82
|
font-weight: 700;
|
|
88
83
|
font-size: 1.125rem;
|
|
@@ -116,4 +111,4 @@ output span {
|
|
|
116
111
|
overflow-wrap: anywhere;
|
|
117
112
|
min-width: 0;
|
|
118
113
|
flex: 1 1 auto;
|
|
119
|
-
}</style>
|
|
114
|
+
}</style>
|