@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,64 +1,60 @@
|
|
|
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
|
-
for (const { item } of items) {
|
|
21
|
-
const path = item.path;
|
|
22
|
-
if (path && pathname.includes(path) && (best === null || path.length > best.length)) {
|
|
23
|
-
best = path;
|
|
24
|
-
}
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script lang="ts">import { page } from "$app/state";
|
|
4
|
+
import { Colour } from "../../scss/colours.js";
|
|
5
|
+
import { Size } from "../../Types/Internal/Size.js";
|
|
6
|
+
import Icon from "../Icon.svelte";
|
|
7
|
+
import { Dimensions } from "./Dimensions.js";
|
|
8
|
+
import ServiceMenuItem from "./ServiceMenuItem.svelte";
|
|
9
|
+
const { title, items, icon } = $props();
|
|
10
|
+
// Only the single most-specific item is active: the longest item path that
|
|
11
|
+
// the current URL matches. Without this a nested route (e.g.
|
|
12
|
+
// /reports/manage-reports) would also light up its parent item (/reports).
|
|
13
|
+
const activePath = $derived.by(() => {
|
|
14
|
+
const pathname = page.url.pathname;
|
|
15
|
+
let best = null;
|
|
16
|
+
for (const { item } of items) {
|
|
17
|
+
const path = item.path;
|
|
18
|
+
if (path && pathname.includes(path) && (best === null || path.length > best.length)) {
|
|
19
|
+
best = path;
|
|
25
20
|
}
|
|
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
|
-
</div>
|
|
61
|
-
|
|
21
|
+
}
|
|
22
|
+
return best;
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
class="wrapper"
|
|
28
|
+
style="--icon-column-width: {Dimensions.smallPanelWidth}rem"
|
|
29
|
+
role="group"
|
|
30
|
+
aria-label={title}
|
|
31
|
+
>
|
|
32
|
+
<h3>
|
|
33
|
+
<div class="icon">
|
|
34
|
+
{#if icon}
|
|
35
|
+
<Icon
|
|
36
|
+
size={Size.Large}
|
|
37
|
+
colour={Colour['$font-primary']}
|
|
38
|
+
{...icon}
|
|
39
|
+
/>
|
|
40
|
+
{/if}
|
|
41
|
+
</div>
|
|
42
|
+
{title}
|
|
43
|
+
</h3>
|
|
44
|
+
|
|
45
|
+
<div
|
|
46
|
+
class="items"
|
|
47
|
+
role="list"
|
|
48
|
+
>
|
|
49
|
+
{#each items as { item } (item.label)}
|
|
50
|
+
<ServiceMenuItem
|
|
51
|
+
{item}
|
|
52
|
+
selected={item.path != null && item.path === activePath}
|
|
53
|
+
/>
|
|
54
|
+
{/each}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
62
58
|
<style>h3 {
|
|
63
59
|
font-size: 1.5rem;
|
|
64
60
|
display: flex;
|
|
@@ -82,4 +78,4 @@ h3 .icon {
|
|
|
82
78
|
.wrapper .items {
|
|
83
79
|
flex-shrink: 1;
|
|
84
80
|
overflow: auto;
|
|
85
|
-
}</style>
|
|
81
|
+
}</style>
|
|
@@ -1,64 +1,60 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<script
|
|
4
|
-
lang="ts"
|
|
5
|
-
generics="Args"
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/>
|
|
59
|
-
{/if}
|
|
60
|
-
</button>
|
|
61
|
-
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
generics="Args"
|
|
6
|
+
>import { useAsyncFlag } from "../../Helpers/AsyncFlag.svelte.js";
|
|
7
|
+
import { Colour } from "../../scss/colours.js";
|
|
8
|
+
import { Size } from "../../Types/Internal/Size.js";
|
|
9
|
+
import Icon from "../Icon.svelte";
|
|
10
|
+
// `Args` defaults to `unknown` on the props interface, but we still
|
|
11
|
+
// pass the generic explicitly so consumers using the component as
|
|
12
|
+
// `<NavTab>` inside a typed snippet receive the same `Args` rune.
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-arguments
|
|
14
|
+
let { option, selected } = $props();
|
|
15
|
+
const isValid = useAsyncFlag(() => option.isValid, true);
|
|
16
|
+
const disabled = useAsyncFlag(() => option.disabled, false);
|
|
17
|
+
const visible = useAsyncFlag(() => option.visible, true);
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<button
|
|
21
|
+
class:selected
|
|
22
|
+
onclick={() => {
|
|
23
|
+
option.onclick();
|
|
24
|
+
}}
|
|
25
|
+
type="button"
|
|
26
|
+
class="tab"
|
|
27
|
+
role="tab"
|
|
28
|
+
aria-selected={selected}
|
|
29
|
+
aria-label={option.label}
|
|
30
|
+
disabled={disabled.value}
|
|
31
|
+
class:invalid={!isValid.value}
|
|
32
|
+
class:hidden={!visible.value}
|
|
33
|
+
>
|
|
34
|
+
<Icon
|
|
35
|
+
name="nothing"
|
|
36
|
+
colour={Colour['$brand-primary']}
|
|
37
|
+
size={Size.MediumLarge}
|
|
38
|
+
{...option.iconLeft}
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
{option.label}
|
|
42
|
+
{#if option.isValid === false}
|
|
43
|
+
<Icon
|
|
44
|
+
name="error"
|
|
45
|
+
colour={Colour['$error-border']}
|
|
46
|
+
size={Size.MediumLarge}
|
|
47
|
+
/>
|
|
48
|
+
{:else}
|
|
49
|
+
<Icon
|
|
50
|
+
name="nothing"
|
|
51
|
+
colour={Colour['$brand-primary']}
|
|
52
|
+
size={Size.MediumLarge}
|
|
53
|
+
{...option.iconRight}
|
|
54
|
+
/>
|
|
55
|
+
{/if}
|
|
56
|
+
</button>
|
|
57
|
+
|
|
62
58
|
<style>button.tab.hidden {
|
|
63
59
|
display: none !important;
|
|
64
60
|
}
|
|
@@ -91,4 +87,4 @@
|
|
|
91
87
|
}
|
|
92
88
|
.tab.invalid {
|
|
93
89
|
color: #aa1414;
|
|
94
|
-
}</style>
|
|
90
|
+
}</style>
|
|
@@ -1,114 +1,106 @@
|
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
* The validated path is run through `resolve` so the rendered `href`
|
|
37
|
-
* honours a configured base path (e.g. a `URI_PREFIX` build arg).
|
|
38
|
-
* `item.path` is the bare app-relative route; without the prefix the
|
|
39
|
-
* `<a href>` would point outside the deployed sub-path.
|
|
40
|
-
*/
|
|
41
|
-
function safeHref(path: string): string {
|
|
42
|
-
if (typeof path !== 'string' || path.length === 0) {
|
|
43
|
-
return '#';
|
|
44
|
-
}
|
|
45
|
-
if (!path.startsWith('/')) {
|
|
46
|
-
return '#';
|
|
47
|
-
}
|
|
48
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(path)) {
|
|
49
|
-
return '#';
|
|
50
|
-
}
|
|
51
|
-
return resolve(path as '/');
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script lang="ts">import { dev } from "$app/environment";
|
|
4
|
+
import { resolve } from "$app/paths";
|
|
5
|
+
import { page } from "$app/state";
|
|
6
|
+
import { useAsyncFlag } from "../../Helpers/AsyncFlag.svelte.js";
|
|
7
|
+
import { Size } from "../../Types/Internal/Size.js";
|
|
8
|
+
import Icon from "../Icon.svelte";
|
|
9
|
+
import { Dimensions } from "./Dimensions.js";
|
|
10
|
+
const { item, selected: maybeSelected } = $props();
|
|
11
|
+
// `page.url.pathname` carries the configured base path; `item.path`
|
|
12
|
+
// does not. Match with `includes` so the comparison holds whether or
|
|
13
|
+
// not a base path (e.g. a `URI_PREFIX` build arg) is set.
|
|
14
|
+
const selected = $derived(maybeSelected ?? (item.path ? page.url.pathname.includes(item.path) : false));
|
|
15
|
+
const visible = useAsyncFlag(() => item.visible, true);
|
|
16
|
+
/**
|
|
17
|
+
* Constrain the rendered `href` to safe, relative paths only, then
|
|
18
|
+
* prefix the SvelteKit `base` path.
|
|
19
|
+
*
|
|
20
|
+
* `item.path` is typed as the SvelteKit `Pathname` brand at the
|
|
21
|
+
* boundary, but the property is still a `string` at runtime. To
|
|
22
|
+
* keep the trust boundary tight we reject anything that contains
|
|
23
|
+
* a URL scheme (anything matching `^[a-z][a-z0-9+.-]*:`) and any
|
|
24
|
+
* input that does not start with `/`. Disallowed values resolve
|
|
25
|
+
* to `#` so the link is harmless if a future consumer supplies an
|
|
26
|
+
* unsafe value.
|
|
27
|
+
*
|
|
28
|
+
* The validated path is run through `resolve` so the rendered `href`
|
|
29
|
+
* honours a configured base path (e.g. a `URI_PREFIX` build arg).
|
|
30
|
+
* `item.path` is the bare app-relative route; without the prefix the
|
|
31
|
+
* `<a href>` would point outside the deployed sub-path.
|
|
32
|
+
*/
|
|
33
|
+
function safeHref(path) {
|
|
34
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
35
|
+
return "#";
|
|
52
36
|
}
|
|
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
|
-
|
|
89
|
-
>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
{
|
|
111
|
-
|
|
37
|
+
if (!path.startsWith("/")) {
|
|
38
|
+
return "#";
|
|
39
|
+
}
|
|
40
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(path)) {
|
|
41
|
+
return "#";
|
|
42
|
+
}
|
|
43
|
+
return resolve(path);
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
{#if item.callback}
|
|
48
|
+
<button
|
|
49
|
+
onclick={() => {
|
|
50
|
+
item.callback();
|
|
51
|
+
}}
|
|
52
|
+
style="--iconWidth: {Dimensions.smallPanelWidth}rem"
|
|
53
|
+
class:selected
|
|
54
|
+
class:hidden={!visible.value}
|
|
55
|
+
>
|
|
56
|
+
<!-- <div class="selected-marker"></div> -->
|
|
57
|
+
<div class="icon-wrapper">
|
|
58
|
+
{#if item.iconName}
|
|
59
|
+
<Icon
|
|
60
|
+
name={item.iconName}
|
|
61
|
+
size={Size.Medium}
|
|
62
|
+
label={item.label}
|
|
63
|
+
/>
|
|
64
|
+
{/if}
|
|
65
|
+
</div>
|
|
66
|
+
<div class="spacer"></div>
|
|
67
|
+
<div class="text">
|
|
68
|
+
<div class="label">{item.label}</div>
|
|
69
|
+
{#if item.subtitle}
|
|
70
|
+
<div class="subtitle">{item.subtitle}</div>
|
|
71
|
+
{/if}
|
|
72
|
+
</div></button
|
|
73
|
+
>
|
|
74
|
+
{:else if item.path}
|
|
75
|
+
<a
|
|
76
|
+
href={safeHref(item.path)}
|
|
77
|
+
style="--iconWidth: {Dimensions.smallPanelWidth}rem"
|
|
78
|
+
aria-current={selected ? 'page' : undefined}
|
|
79
|
+
class:selected
|
|
80
|
+
class:hidden={!visible.value}
|
|
81
|
+
>
|
|
82
|
+
<!-- <div class="selected-marker"></div> -->
|
|
83
|
+
<div class="icon-wrapper">
|
|
84
|
+
{#if item.iconName}
|
|
85
|
+
<Icon
|
|
86
|
+
name={item.iconName}
|
|
87
|
+
size={Size.Medium}
|
|
88
|
+
label={item.label}
|
|
89
|
+
/>
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
92
|
+
<div class="spacer"></div>
|
|
93
|
+
<div class="text">
|
|
94
|
+
<div class="label">{item.label}</div>
|
|
95
|
+
{#if item.subtitle}
|
|
96
|
+
<div class="subtitle">{item.subtitle}</div>
|
|
97
|
+
{/if}
|
|
98
|
+
</div></a
|
|
99
|
+
>
|
|
100
|
+
{:else if dev}
|
|
101
|
+
Error: Callback had neither callback nor path
|
|
102
|
+
{/if}
|
|
103
|
+
|
|
112
104
|
<style>button.hidden,
|
|
113
105
|
a.hidden {
|
|
114
106
|
display: none !important;
|
|
@@ -174,4 +166,4 @@ a:hover {
|
|
|
174
166
|
button .spacer,
|
|
175
167
|
a .spacer {
|
|
176
168
|
width: 0.5rem;
|
|
177
|
-
}</style>
|
|
169
|
+
}</style>
|
|
@@ -1,82 +1,75 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<script
|
|
4
|
-
lang="ts"
|
|
5
|
-
generics="Args"
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
function fireClose(): void {
|
|
19
|
-
const result = onclose();
|
|
20
|
-
if (result instanceof Promise) {
|
|
21
|
-
result.catch((e: unknown) => {
|
|
22
|
-
devCatch(e);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
generics="Args"
|
|
6
|
+
>import { devCatch } from "../../Helpers/Helpers.svelte.js";
|
|
7
|
+
import HorizontalTabGroup from "../HorizontalTabGroup.svelte";
|
|
8
|
+
import NavTab from "./NavTab.svelte";
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-arguments
|
|
10
|
+
const { onclose, serviceTabs, selectedServiceTab } = $props();
|
|
11
|
+
let dialogRef = $state.raw();
|
|
12
|
+
function fireClose() {
|
|
13
|
+
const result = onclose();
|
|
14
|
+
if (result instanceof Promise) {
|
|
15
|
+
result.catch((e) => {
|
|
16
|
+
devCatch(e);
|
|
17
|
+
});
|
|
25
18
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<dialog
|
|
39
|
-
bind:this={dialogRef}
|
|
40
|
-
aria-label="Services"
|
|
41
|
-
class="overlay"
|
|
42
|
-
oncancel={(e) => {
|
|
43
|
-
// Escape fires `cancel` first; prevent the native close so we
|
|
44
|
-
// fully delegate to the parent (it owns the visibility flag).
|
|
45
|
-
e.preventDefault();
|
|
46
|
-
fireClose();
|
|
47
|
-
}}
|
|
48
|
-
onclick={(e) => {
|
|
49
|
-
// Native <dialog> click target is the dialog element itself when
|
|
50
|
-
// the user clicks the backdrop; clicks on inner content bubble
|
|
51
|
-
// up with a different target.
|
|
52
|
-
if (dialogRef === e.target) {
|
|
53
|
-
fireClose();
|
|
54
|
-
}
|
|
55
|
-
}}
|
|
56
|
-
>
|
|
57
|
-
<div
|
|
58
|
-
role="navigation"
|
|
59
|
-
aria-label="Services tabs"
|
|
60
|
-
class="services"
|
|
61
|
-
>
|
|
62
|
-
<HorizontalTabGroup
|
|
63
|
-
name="nav-services"
|
|
64
|
-
tabs={serviceTabs}
|
|
65
|
-
selected={selectedServiceTab}
|
|
66
|
-
tabComponent={navTab}
|
|
67
|
-
noRadius
|
|
68
|
-
grow
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
71
|
-
</dialog>
|
|
72
|
-
|
|
73
|
-
{#snippet navTab(option: TabOption<Args>, selected: boolean)}
|
|
74
|
-
<NavTab
|
|
75
|
-
{option}
|
|
76
|
-
{selected}
|
|
77
|
-
/>
|
|
78
|
-
{/snippet}
|
|
79
|
-
|
|
19
|
+
}
|
|
20
|
+
// Open the dialog as soon as we mount; native showModal() gives us a
|
|
21
|
+
// real focus trap, Escape-to-close, and inert background without any
|
|
22
|
+
// manual aria-modal / tabindex bookkeeping.
|
|
23
|
+
$effect(() => {
|
|
24
|
+
const dialog = dialogRef;
|
|
25
|
+
if (dialog && !dialog.open) {
|
|
26
|
+
dialog.showModal();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<dialog
|
|
32
|
+
bind:this={dialogRef}
|
|
33
|
+
aria-label="Services"
|
|
34
|
+
class="overlay"
|
|
35
|
+
oncancel={(e) => {
|
|
36
|
+
// Escape fires `cancel` first; prevent the native close so we
|
|
37
|
+
// fully delegate to the parent (it owns the visibility flag).
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
fireClose();
|
|
40
|
+
}}
|
|
41
|
+
onclick={(e) => {
|
|
42
|
+
// Native <dialog> click target is the dialog element itself when
|
|
43
|
+
// the user clicks the backdrop; clicks on inner content bubble
|
|
44
|
+
// up with a different target.
|
|
45
|
+
if (dialogRef === e.target) {
|
|
46
|
+
fireClose();
|
|
47
|
+
}
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
<div
|
|
51
|
+
role="navigation"
|
|
52
|
+
aria-label="Services tabs"
|
|
53
|
+
class="services"
|
|
54
|
+
>
|
|
55
|
+
<HorizontalTabGroup
|
|
56
|
+
name="nav-services"
|
|
57
|
+
tabs={serviceTabs}
|
|
58
|
+
selected={selectedServiceTab}
|
|
59
|
+
tabComponent={navTab}
|
|
60
|
+
noRadius
|
|
61
|
+
grow
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
</dialog>
|
|
65
|
+
|
|
66
|
+
{#snippet navTab(option: TabOption<Args>, selected: boolean)}
|
|
67
|
+
<NavTab
|
|
68
|
+
{option}
|
|
69
|
+
{selected}
|
|
70
|
+
/>
|
|
71
|
+
{/snippet}
|
|
72
|
+
|
|
80
73
|
<style>dialog.overlay {
|
|
81
74
|
position: fixed;
|
|
82
75
|
top: calc(3.25rem + var(--env-border-height, 0));
|
|
@@ -115,4 +108,4 @@ div.services {
|
|
|
115
108
|
justify-content: stretch;
|
|
116
109
|
height: var(--services-nav-height, min(710px, 80%));
|
|
117
110
|
width: var(--services-nav-width, 800px);
|
|
118
|
-
}</style>
|
|
111
|
+
}</style>
|