@onsvisual/svelte-components 1.0.25 → 1.0.28
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/dist/css/main.css +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/inputs/ButtonGroup/ButtonGroup.stories.svelte +40 -0
- package/dist/inputs/ButtonGroup/ButtonGroup.stories.svelte.d.ts +23 -0
- package/dist/inputs/ButtonGroup/ButtonGroup.svelte +57 -0
- package/dist/inputs/ButtonGroup/ButtonGroup.svelte.d.ts +27 -0
- package/dist/inputs/ButtonGroup/ButtonGroupItem.svelte +101 -0
- package/dist/inputs/ButtonGroup/ButtonGroupItem.svelte.d.ts +23 -0
- package/dist/inputs/ButtonGroup/docs/component.md +21 -0
- package/dist/inputs/Radios/Radio.svelte +8 -1
- package/dist/inputs/Toolbar/HelpModal.svelte +234 -0
- package/dist/inputs/Toolbar/HelpModal.svelte.d.ts +16 -0
- package/dist/inputs/Toolbar/ToolControl.svelte +23 -0
- package/dist/inputs/Toolbar/ToolControl.svelte.d.ts +27 -0
- package/dist/inputs/Toolbar/ToolControls.svelte +9 -0
- package/dist/inputs/Toolbar/ToolControls.svelte.d.ts +27 -0
- package/dist/inputs/Toolbar/Toolbar.stories.svelte +148 -0
- package/dist/inputs/Toolbar/Toolbar.stories.svelte.d.ts +23 -0
- package/dist/inputs/Toolbar/Toolbar.svelte +70 -0
- package/dist/inputs/Toolbar/Toolbar.svelte.d.ts +29 -0
- package/dist/inputs/Toolbar/ToolbarButton.svelte +184 -0
- package/dist/inputs/Toolbar/ToolbarButton.svelte.d.ts +19 -0
- package/dist/inputs/Toolbar/ToolbarDivider.svelte +29 -0
- package/dist/inputs/Toolbar/ToolbarDivider.svelte.d.ts +14 -0
- package/dist/inputs/Toolbar/ToolbarIcon.svelte +106 -0
- package/dist/inputs/Toolbar/ToolbarIcon.svelte.d.ts +23 -0
- package/dist/inputs/Toolbar/ToolbarsContainer.svelte +69 -0
- package/dist/inputs/Toolbar/ToolbarsContainer.svelte.d.ts +19 -0
- package/dist/inputs/Toolbar/docs/component.md +99 -0
- package/dist/inputs/Toolbar/img/movepan.png +0 -0
- package/package.json +1 -1
package/dist/css/main.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import url("https://cdn.ons.gov.uk/sdc/design-system/72.10.4
|
|
1
|
+
@import url("https://cdn.ons.gov.uk/sdc/design-system/72.10.4/css/main.css");
|
|
2
2
|
@import url("https://cdn.ons.gov.uk/vendor/accessible-autocomplete/3.0.1/accessible-autocomplete.min.css");
|
|
3
3
|
|
|
4
4
|
/* CSS rules missing from design system */
|
package/dist/index.d.ts
CHANGED
|
@@ -46,6 +46,16 @@ export { default as Input } from "./inputs/Input/Input.svelte";
|
|
|
46
46
|
export { default as Radio } from "./inputs/Radios/Radio.svelte";
|
|
47
47
|
export { default as Radios } from "./inputs/Radios/Radios.svelte";
|
|
48
48
|
export { default as Textarea } from "./inputs/Textarea/Textarea.svelte";
|
|
49
|
+
export { default as HelpModal } from "./inputs/Toolbar/HelpModal.svelte";
|
|
50
|
+
export { default as ToolbarIcon } from "./inputs/Toolbar/ToolbarIcon.svelte";
|
|
51
|
+
export { default as Toolbar } from "./inputs/Toolbar/Toolbar.svelte";
|
|
52
|
+
export { default as ToolbarButton } from "./inputs/Toolbar/ToolbarButton.svelte";
|
|
53
|
+
export { default as ToolbarDivider } from "./inputs/Toolbar/ToolbarDivider.svelte";
|
|
54
|
+
export { default as ToolbarsContainer } from "./inputs/Toolbar/ToolbarsContainer.svelte";
|
|
55
|
+
export { default as ToolControl } from "./inputs/Toolbar/ToolControl.svelte";
|
|
56
|
+
export { default as ToolControls } from "./inputs/Toolbar/ToolControls.svelte";
|
|
57
|
+
export { default as ButtonGroup } from "./inputs/ButtonGroup/ButtonGroup.svelte";
|
|
58
|
+
export { default as ButtonGroupItem } from "./inputs/ButtonGroup/ButtonGroupItem.svelte";
|
|
49
59
|
export { default as Blockquote } from "./decorators/Blockquote/Blockquote.svelte";
|
|
50
60
|
export { default as Divider } from "./decorators/Divider/Divider.svelte";
|
|
51
61
|
export { default as Em } from "./decorators/Em/Em.svelte";
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,16 @@ export { default as Radios } from "./inputs/Radios/Radios.svelte";
|
|
|
63
63
|
export { default as Select } from "./inputs/Select/Select.svelte";
|
|
64
64
|
export { default as AccessibleSelect } from "./inputs/Select/Select.svelte"; // Alias for Select
|
|
65
65
|
export { default as Textarea } from "./inputs/Textarea/Textarea.svelte";
|
|
66
|
+
export { default as HelpModal } from "./inputs/Toolbar/HelpModal.svelte";
|
|
67
|
+
export { default as ToolbarIcon } from "./inputs/Toolbar/ToolbarIcon.svelte";
|
|
68
|
+
export { default as Toolbar } from "./inputs/Toolbar/Toolbar.svelte";
|
|
69
|
+
export { default as ToolbarButton } from "./inputs/Toolbar/ToolbarButton.svelte";
|
|
70
|
+
export { default as ToolbarDivider } from "./inputs/Toolbar/ToolbarDivider.svelte";
|
|
71
|
+
export { default as ToolbarsContainer } from "./inputs/Toolbar/ToolbarsContainer.svelte";
|
|
72
|
+
export { default as ToolControl } from "./inputs/Toolbar/ToolControl.svelte";
|
|
73
|
+
export { default as ToolControls } from "./inputs/Toolbar/ToolControls.svelte";
|
|
74
|
+
export { default as ButtonGroup } from "./inputs/ButtonGroup/ButtonGroup.svelte";
|
|
75
|
+
export { default as ButtonGroupItem } from "./inputs/ButtonGroup/ButtonGroupItem.svelte";
|
|
66
76
|
|
|
67
77
|
// Decorators
|
|
68
78
|
export { default as Blockquote } from "./decorators/Blockquote/Blockquote.svelte";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import componentDocs from "./docs/component.md?raw";
|
|
4
|
+
import ButtonGroup from "./ButtonGroup.svelte";
|
|
5
|
+
import ButtonGroupItem from "./ButtonGroupItem.svelte";
|
|
6
|
+
import { withComponentDocs } from "../../js/withParams.js";
|
|
7
|
+
|
|
8
|
+
const { Story } = defineMeta({
|
|
9
|
+
title: "Inputs/ButtonGroup",
|
|
10
|
+
component: ButtonGroup,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
argTypes: {
|
|
13
|
+
legend: { control: "text" },
|
|
14
|
+
visuallyHideLegend: { control: "boolean" }
|
|
15
|
+
},
|
|
16
|
+
parameters: withComponentDocs(componentDocs)
|
|
17
|
+
});
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
{#snippet template(args)}
|
|
21
|
+
<ButtonGroup {...args}>
|
|
22
|
+
<ButtonGroupItem value="1" label="Option 1" />
|
|
23
|
+
<ButtonGroupItem value="2" label="Option 2" />
|
|
24
|
+
<ButtonGroupItem value="3" label="Option 3" />
|
|
25
|
+
</ButtonGroup>
|
|
26
|
+
{/snippet}
|
|
27
|
+
|
|
28
|
+
<Story name="Default" args={{ name: "primary", legend: "Choose an option" }} {template} />
|
|
29
|
+
|
|
30
|
+
<Story
|
|
31
|
+
name="With initial value"
|
|
32
|
+
args={{ name: "primary", legend: "Choose an option", value: "2" }}
|
|
33
|
+
{template}
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
<Story
|
|
37
|
+
name="Visually hide legend"
|
|
38
|
+
args={{ name: "primary", legend: "Choose an option", visuallyHideLegend: true }}
|
|
39
|
+
{template}
|
|
40
|
+
/>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ButtonGroupProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ButtonGroupEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ButtonGroupSlots */
|
|
4
|
+
export default class ButtonGroup extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: never;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type ButtonGroupProps = typeof __propDef.props;
|
|
11
|
+
export type ButtonGroupEvents = typeof __propDef.events;
|
|
12
|
+
export type ButtonGroupSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponentTyped } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
[x: string]: never;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { setContext } from "svelte";
|
|
3
|
+
import { writable } from "svelte/store";
|
|
4
|
+
|
|
5
|
+
let { name = "", legend = "", value, visuallyHideLegend = false } = $props();
|
|
6
|
+
|
|
7
|
+
// create the store
|
|
8
|
+
const selectedValue = writable(value);
|
|
9
|
+
|
|
10
|
+
// When store changes and update prop
|
|
11
|
+
$effect(() => {
|
|
12
|
+
selectedValue.set(value);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const currentValue = $derived(selectedValue);
|
|
16
|
+
|
|
17
|
+
$effect(() => {
|
|
18
|
+
if ($currentValue !== value) {
|
|
19
|
+
value = $currentValue;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Create a context to share with child Button components
|
|
24
|
+
setContext("buttonGroup", {
|
|
25
|
+
groupName: name,
|
|
26
|
+
selectedValue
|
|
27
|
+
});
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<fieldset class="button-group">
|
|
31
|
+
{#if legend}
|
|
32
|
+
<legend class:ons-u-vh={visuallyHideLegend}>{legend}</legend>
|
|
33
|
+
{/if}
|
|
34
|
+
<div class="buttons">
|
|
35
|
+
<slot />
|
|
36
|
+
</div>
|
|
37
|
+
</fieldset>
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
.button-group {
|
|
41
|
+
display: inline-block;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
legend {
|
|
45
|
+
font-weight: bold;
|
|
46
|
+
margin-bottom: 0.5rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.buttons {
|
|
50
|
+
display: flex;
|
|
51
|
+
gap: 8px;
|
|
52
|
+
background: #f5f5f6;
|
|
53
|
+
padding: 4px;
|
|
54
|
+
border-radius: 8px;
|
|
55
|
+
justify-content: space-between;
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ButtonGroupProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ButtonGroupEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ButtonGroupSlots */
|
|
4
|
+
export default class ButtonGroup extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: never;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {
|
|
9
|
+
default: {};
|
|
10
|
+
}> {
|
|
11
|
+
}
|
|
12
|
+
export type ButtonGroupProps = typeof __propDef.props;
|
|
13
|
+
export type ButtonGroupEvents = typeof __propDef.events;
|
|
14
|
+
export type ButtonGroupSlots = typeof __propDef.slots;
|
|
15
|
+
import { SvelteComponentTyped } from "svelte";
|
|
16
|
+
declare const __propDef: {
|
|
17
|
+
props: {
|
|
18
|
+
[x: string]: never;
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots: {
|
|
24
|
+
default: {};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
|
|
4
|
+
let { value = "", label = "" } = $props();
|
|
5
|
+
|
|
6
|
+
// Get the parent ButtonGroup context
|
|
7
|
+
const buttonGroup = getContext("buttonGroup");
|
|
8
|
+
const { groupName, selectedValue } = buttonGroup;
|
|
9
|
+
|
|
10
|
+
// Subscribe to selectedValue store
|
|
11
|
+
const currentSelected = $derived(selectedValue);
|
|
12
|
+
const selected = $derived($currentSelected === value);
|
|
13
|
+
|
|
14
|
+
function handleClick() {
|
|
15
|
+
selectedValue.set(value); // Update the store
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let buttonRef;
|
|
19
|
+
|
|
20
|
+
function handleKeydown(event) {
|
|
21
|
+
const buttons = Array.from(document.querySelectorAll(`[name="${groupName}"]`));
|
|
22
|
+
const currentIndex = buttons.indexOf(buttonRef);
|
|
23
|
+
|
|
24
|
+
let newIndex = -1;
|
|
25
|
+
|
|
26
|
+
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
|
|
27
|
+
newIndex = (currentIndex + 1) % buttons.length;
|
|
28
|
+
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
|
|
29
|
+
newIndex = (currentIndex - 1 + buttons.length) % buttons.length;
|
|
30
|
+
} else if (event.key === "Enter" || event.key === " ") {
|
|
31
|
+
handleClick();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (newIndex !== -1) {
|
|
36
|
+
buttons[newIndex].focus();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<div class="button-container">
|
|
42
|
+
<input
|
|
43
|
+
type="radio"
|
|
44
|
+
id={value}
|
|
45
|
+
name={groupName}
|
|
46
|
+
{value}
|
|
47
|
+
checked={selected}
|
|
48
|
+
class="radio-input"
|
|
49
|
+
on:click={handleClick}
|
|
50
|
+
on:keydown={handleKeydown}
|
|
51
|
+
aria-checked={selected}
|
|
52
|
+
tabindex="0"
|
|
53
|
+
bind:this={buttonRef}
|
|
54
|
+
/>
|
|
55
|
+
<label for={value} class="button" class:selected on:click={handleClick}>
|
|
56
|
+
{label || value}
|
|
57
|
+
</label>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<style>
|
|
61
|
+
.button-container {
|
|
62
|
+
display: flex;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.radio-input {
|
|
66
|
+
position: absolute;
|
|
67
|
+
opacity: 0;
|
|
68
|
+
width: 0;
|
|
69
|
+
height: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.button {
|
|
73
|
+
flex-grow: 0;
|
|
74
|
+
padding: 4px 8px;
|
|
75
|
+
border: none;
|
|
76
|
+
background: transparent;
|
|
77
|
+
font-size: 14px;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
border-radius: 6px;
|
|
80
|
+
transition:
|
|
81
|
+
background 0.2s ease,
|
|
82
|
+
color 0.2s ease;
|
|
83
|
+
color: #707071;
|
|
84
|
+
text-align: center;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.button:hover {
|
|
88
|
+
background-color: #e8e8e8;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.button:focus {
|
|
92
|
+
box-shadow: orange 0 0 0 2px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.button.selected {
|
|
96
|
+
background: white;
|
|
97
|
+
font-weight: bold;
|
|
98
|
+
color: #206095;
|
|
99
|
+
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
|
|
100
|
+
}
|
|
101
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ButtonGroupItemProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ButtonGroupItemEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ButtonGroupItemSlots */
|
|
4
|
+
export default class ButtonGroupItem extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: never;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type ButtonGroupItemProps = typeof __propDef.props;
|
|
11
|
+
export type ButtonGroupItemEvents = typeof __propDef.events;
|
|
12
|
+
export type ButtonGroupItemSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponentTyped } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
[x: string]: never;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Radio inputs dressed up as a button group.
|
|
2
|
+
|
|
3
|
+
<!-- prettier-ignore -->
|
|
4
|
+
```html
|
|
5
|
+
<ButtonGroup name="primary" legend="Choose an option">
|
|
6
|
+
<ButtonGroupItem value="1" label="Option 1" />
|
|
7
|
+
<ButtonGroupItem value="2" label="Option 2" />
|
|
8
|
+
<ButtonGroupItem value="3" label="Option 3" />
|
|
9
|
+
</ButtonGroup>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
To see what is selected, bind `value` to a variable e.g.
|
|
13
|
+
|
|
14
|
+
<!-- prettier-ignore -->
|
|
15
|
+
```html
|
|
16
|
+
let selectedValue;
|
|
17
|
+
|
|
18
|
+
<ButtonGroup name="primary" legend="Choose an option" bind:value="{selectedValue}">
|
|
19
|
+
...
|
|
20
|
+
</ButtonGroup>
|
|
21
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { createEventDispatcher } from "svelte";
|
|
2
|
+
import { onMount, createEventDispatcher } from "svelte";
|
|
3
3
|
|
|
4
4
|
const dispatch = createEventDispatcher();
|
|
5
5
|
|
|
@@ -38,6 +38,12 @@
|
|
|
38
38
|
* @type {boolean}
|
|
39
39
|
*/
|
|
40
40
|
export let compact = false;
|
|
41
|
+
|
|
42
|
+
let el;
|
|
43
|
+
|
|
44
|
+
onMount(() => {
|
|
45
|
+
if (value?.id === item.id) el.checked = true;
|
|
46
|
+
});
|
|
41
47
|
</script>
|
|
42
48
|
|
|
43
49
|
<span class="ons-radios__item" class:ons-radios__item--no-border={compact}>
|
|
@@ -54,6 +60,7 @@
|
|
|
54
60
|
dispatch("change", { value, e });
|
|
55
61
|
}
|
|
56
62
|
}}
|
|
63
|
+
bind:this={el}
|
|
57
64
|
/>
|
|
58
65
|
<label
|
|
59
66
|
class="ons-radio__label"
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
// import { get, set } from "svelte/store";
|
|
4
|
+
import { fly } from "svelte/transition";
|
|
5
|
+
import Checkbox from "../Checkbox/Checkbox.svelte";
|
|
6
|
+
import Button from "../Button/Button.svelte";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
triggerElement = null,
|
|
10
|
+
onClose = () => {}
|
|
11
|
+
}: {
|
|
12
|
+
triggerElement?: HTMLElement | null;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
} = $props();
|
|
15
|
+
|
|
16
|
+
// --- Context ---
|
|
17
|
+
const activeModalId = getContext("activeModalId");
|
|
18
|
+
const showHelpModals = getContext("showHelpModals");
|
|
19
|
+
const { buttonIds } = getContext("buttonIds");
|
|
20
|
+
|
|
21
|
+
// --- Derived state from stores ---
|
|
22
|
+
const ids = $derived(buttonIds);
|
|
23
|
+
const currentActiveId = $derived(activeModalId);
|
|
24
|
+
const showHelp = $derived(showHelpModals);
|
|
25
|
+
|
|
26
|
+
// --- Local state ---
|
|
27
|
+
let modalPosition = $state({ top: 50, left: -5 });
|
|
28
|
+
let notchPosition = $state({ left: 17, right: "auto" });
|
|
29
|
+
let dontShowMeAgain = $state(false);
|
|
30
|
+
|
|
31
|
+
$effect(() => {
|
|
32
|
+
if (!triggerElement) return;
|
|
33
|
+
|
|
34
|
+
const rect = triggerElement.getBoundingClientRect();
|
|
35
|
+
|
|
36
|
+
// Calculate the modal's position
|
|
37
|
+
// const spaceBelow = window.innerHeight - rect.bottom;
|
|
38
|
+
// const spaceAbove = rect.top;
|
|
39
|
+
const spaceRight = window.innerWidth - rect.right;
|
|
40
|
+
|
|
41
|
+
let newLeft = window.scrollX - 10;
|
|
42
|
+
let newNotchLeft: number | "auto" = 17;
|
|
43
|
+
let newNotchRight: number | "auto" = "auto";
|
|
44
|
+
|
|
45
|
+
// if (spaceBelow < 200 && spaceAbove > 200) {
|
|
46
|
+
// newTop = rect.top + window.scrollY - 10;
|
|
47
|
+
// }
|
|
48
|
+
|
|
49
|
+
if (spaceRight < 300) {
|
|
50
|
+
newLeft = window.scrollX - 325;
|
|
51
|
+
newNotchLeft = "auto";
|
|
52
|
+
newNotchRight = -350;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// modalPosition.top = newTop;
|
|
56
|
+
modalPosition.left = newLeft;
|
|
57
|
+
notchPosition.left = newNotchLeft;
|
|
58
|
+
notchPosition.right = newNotchRight;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Update localStorage if "Don't show me again" is checked
|
|
62
|
+
function disableHelpModalsPermanently() {
|
|
63
|
+
localStorage.setItem("showHelpModals", "false");
|
|
64
|
+
sessionStorage.setItem("showHelpModals", "false");
|
|
65
|
+
showHelpModals.set(false);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Hide modals until refresh
|
|
69
|
+
function hideHelpModalsUntilRefresh() {
|
|
70
|
+
sessionStorage.setItem("showHelpModals", "false");
|
|
71
|
+
showHelpModals.set(false);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Navigate to the next modal
|
|
75
|
+
function nextModal() {
|
|
76
|
+
const currentIndex = $ids.indexOf($currentActiveId);
|
|
77
|
+
if (currentIndex !== -1 && currentIndex < $ids.length - 1) {
|
|
78
|
+
activeModalId.set($ids[currentIndex + 1]);
|
|
79
|
+
// console.log("Navigating to next modal:", ids[currentIndex + 1]);
|
|
80
|
+
}
|
|
81
|
+
if (dontShowMeAgain) {
|
|
82
|
+
disableHelpModalsPermanently(); // Disable help modals permanently
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function handleSkip() {
|
|
87
|
+
if (dontShowMeAgain) {
|
|
88
|
+
disableHelpModalsPermanently(); // Disable help modals permanently
|
|
89
|
+
} else {
|
|
90
|
+
hideHelpModalsUntilRefresh();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Navigate to the previous modal
|
|
95
|
+
function previousModal() {
|
|
96
|
+
const currentIndex = $ids.indexOf($currentActiveId);
|
|
97
|
+
if (currentIndex > 0) {
|
|
98
|
+
activeModalId.set($ids[currentIndex - 1]);
|
|
99
|
+
// console.log("Navigating to previous modal:", ids[currentIndex - 1]);
|
|
100
|
+
}
|
|
101
|
+
if (dontShowMeAgain) {
|
|
102
|
+
disableHelpModalsPermanently(); // Disable help modals permanently
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
107
|
+
if (event.key === "Escape") onClose();
|
|
108
|
+
}
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<svelte:window on:keydown={handleKeydown} />
|
|
112
|
+
{#if $showHelp}
|
|
113
|
+
<div class="help-modal-wrapper" style="top: {modalPosition.top}px; left: {modalPosition.left}px;">
|
|
114
|
+
<!-- Notch -->
|
|
115
|
+
<div
|
|
116
|
+
class="help-modal-notch"
|
|
117
|
+
style="left: {notchPosition.left}px;right: {notchPosition.right}px;"
|
|
118
|
+
></div>
|
|
119
|
+
|
|
120
|
+
<!-- Modal Content -->
|
|
121
|
+
<div class="help-modal" role="dialog" aria-modal="true">
|
|
122
|
+
<slot />
|
|
123
|
+
<!-- <button class="close-button" on:click="{onClose}" aria-label="Close help">×</button> -->
|
|
124
|
+
|
|
125
|
+
<div class="ons-padding-4">
|
|
126
|
+
<Checkbox
|
|
127
|
+
id="dontShowMeAgain"
|
|
128
|
+
label="Don't show me again"
|
|
129
|
+
bind:checked={dontShowMeAgain}
|
|
130
|
+
compact
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="ons-grid-flex ons-grid-flex--between ons-grid-flex-vertical-center">
|
|
134
|
+
<button class="btn-link" on:click={handleSkip} aria-label="Skip instructions">Skip</button>
|
|
135
|
+
{#if $ids.indexOf($currentActiveId) > 0}
|
|
136
|
+
<span style="margin-left:auto; margin-right:10px">
|
|
137
|
+
<Button variant="secondary" on:click={previousModal}>Back</Button>
|
|
138
|
+
</span>
|
|
139
|
+
{/if}
|
|
140
|
+
|
|
141
|
+
{#if $ids.indexOf($currentActiveId) != $ids.length - 1}
|
|
142
|
+
<Button on:click={nextModal}>Next</Button>
|
|
143
|
+
{/if}
|
|
144
|
+
{#if $ids.indexOf($currentActiveId) == $ids.length - 1}
|
|
145
|
+
<Button on:click={hideHelpModalsUntilRefresh}>Get started</Button>
|
|
146
|
+
{/if}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
{/if}
|
|
151
|
+
|
|
152
|
+
<style>
|
|
153
|
+
.help-modal-wrapper {
|
|
154
|
+
position: absolute;
|
|
155
|
+
z-index: 10;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.help-modal-notch {
|
|
159
|
+
position: absolute;
|
|
160
|
+
top: -10px;
|
|
161
|
+
width: 0;
|
|
162
|
+
height: 0;
|
|
163
|
+
border-left: 10px solid transparent;
|
|
164
|
+
border-right: 10px solid transparent;
|
|
165
|
+
border-bottom: 10px solid white;
|
|
166
|
+
z-index: 1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.help-modal {
|
|
170
|
+
position: absolute;
|
|
171
|
+
flex-direction: column;
|
|
172
|
+
justify-content: center;
|
|
173
|
+
align-items: flex-start;
|
|
174
|
+
padding: 16px;
|
|
175
|
+
isolation: isolate;
|
|
176
|
+
|
|
177
|
+
width: 360px;
|
|
178
|
+
|
|
179
|
+
background: #ffffff;
|
|
180
|
+
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
|
|
181
|
+
border-radius: 16px;
|
|
182
|
+
|
|
183
|
+
/* Inside auto layout */
|
|
184
|
+
flex: none;
|
|
185
|
+
order: 2;
|
|
186
|
+
flex-grow: 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.close-button {
|
|
190
|
+
position: absolute;
|
|
191
|
+
top: 0.5rem;
|
|
192
|
+
right: 0.5rem;
|
|
193
|
+
background: none;
|
|
194
|
+
border: none;
|
|
195
|
+
font-size: 1.25rem;
|
|
196
|
+
color: #666;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.close-button:hover {
|
|
201
|
+
color: #333;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.ons-padding-4 {
|
|
205
|
+
padding-top: var(--4-units, 16px);
|
|
206
|
+
padding-bottom: var(--4-units, 16px);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
button.btn-link {
|
|
210
|
+
line-height: 1.3;
|
|
211
|
+
color: var(--link, #206095);
|
|
212
|
+
background: none;
|
|
213
|
+
margin: 0;
|
|
214
|
+
padding: 0;
|
|
215
|
+
border: none;
|
|
216
|
+
text-decoration: underline;
|
|
217
|
+
text-decoration-thickness: 1px;
|
|
218
|
+
text-underline-position: under;
|
|
219
|
+
}
|
|
220
|
+
button.btn-link:hover {
|
|
221
|
+
color: var(--link-hover, #003c57) !important;
|
|
222
|
+
text-decoration-thickness: 2px;
|
|
223
|
+
}
|
|
224
|
+
button.btn-link:focus {
|
|
225
|
+
background-color: #fbc900 !important;
|
|
226
|
+
box-shadow:
|
|
227
|
+
0 -2px #fbc900,
|
|
228
|
+
0 4px #222;
|
|
229
|
+
color: #222 !important;
|
|
230
|
+
outline: 3px solid transparent;
|
|
231
|
+
outline-offset: 1px;
|
|
232
|
+
text-decoration: none;
|
|
233
|
+
}
|
|
234
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: Record<string, never>;
|
|
4
|
+
events: {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
};
|
|
7
|
+
slots: {
|
|
8
|
+
default: {};
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export type HelpModalProps = typeof __propDef.props;
|
|
12
|
+
export type HelpModalEvents = typeof __propDef.events;
|
|
13
|
+
export type HelpModalSlots = typeof __propDef.slots;
|
|
14
|
+
export default class HelpModal extends SvelteComponentTyped<HelpModalProps, HelpModalEvents, HelpModalSlots> {
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
const activeModalId = getContext("activeModalId");
|
|
4
|
+
const showHelpModals = getContext("showHelpModals");
|
|
5
|
+
|
|
6
|
+
const currentModalId = $derived(activeModalId);
|
|
7
|
+
const showHelp = $derived(showHelpModals);
|
|
8
|
+
|
|
9
|
+
let { id = "" } = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
{#if currentModalId === id && !showHelp}
|
|
13
|
+
<div class="tool-control" role="tabpanel" aria-labelledby={`button-${id}`} id={`panel-${id}`}>
|
|
14
|
+
<slot />
|
|
15
|
+
</div>
|
|
16
|
+
{/if}
|
|
17
|
+
|
|
18
|
+
<style>
|
|
19
|
+
.tool-control {
|
|
20
|
+
max-width: 371px;
|
|
21
|
+
padding: 8px;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ToolControlProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ToolControlEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ToolControlSlots */
|
|
4
|
+
export default class ToolControl extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: never;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {
|
|
9
|
+
default: {};
|
|
10
|
+
}> {
|
|
11
|
+
}
|
|
12
|
+
export type ToolControlProps = typeof __propDef.props;
|
|
13
|
+
export type ToolControlEvents = typeof __propDef.events;
|
|
14
|
+
export type ToolControlSlots = typeof __propDef.slots;
|
|
15
|
+
import { SvelteComponentTyped } from "svelte";
|
|
16
|
+
declare const __propDef: {
|
|
17
|
+
props: {
|
|
18
|
+
[x: string]: never;
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots: {
|
|
24
|
+
default: {};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export {};
|