@geoffcox/sterling-svelte 0.0.25 → 0.0.27
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/Button.svelte +79 -24
- package/Button.svelte.d.ts +1 -0
- package/Checkbox.svelte +44 -19
- package/Checkbox.svelte.d.ts +1 -0
- package/ColorPicker.constants.d.ts +1 -0
- package/ColorPicker.constants.js +1 -0
- package/ColorPicker.svelte +226 -0
- package/ColorPicker.svelte.d.ts +22 -0
- package/ColorPicker.types.d.ts +4 -0
- package/ColorPicker.types.js +1 -0
- package/Dialog.svelte +10 -10
- package/Dropdown.svelte +88 -47
- package/Dropdown.svelte.d.ts +4 -0
- package/Field.svelte +34 -46
- package/HexColorSliders.svelte +150 -0
- package/HexColorSliders.svelte.d.ts +22 -0
- package/HslColorSliders.svelte +187 -0
- package/HslColorSliders.svelte.d.ts +22 -0
- package/Input.svelte +49 -21
- package/Input.svelte.d.ts +2 -1
- package/Label.svelte +3 -3
- package/Link.svelte +63 -17
- package/Link.svelte.d.ts +1 -0
- package/List.svelte +31 -30
- package/List.svelte.d.ts +1 -0
- package/List.types.d.ts +4 -3
- package/ListItem.svelte +29 -10
- package/ListItem.svelte.d.ts +1 -1
- package/Menu.svelte +92 -121
- package/Menu.svelte.d.ts +8 -2
- package/MenuBar.svelte +77 -32
- package/MenuBar.types.d.ts +2 -2
- package/MenuButton.svelte +48 -28
- package/MenuItem.constants.d.ts +1 -0
- package/MenuItem.constants.js +1 -0
- package/MenuItem.svelte +202 -139
- package/MenuItem.svelte.d.ts +7 -3
- package/MenuItem.types.d.ts +14 -5
- package/MenuItem.utils.d.ts +2 -0
- package/MenuItem.utils.js +16 -0
- package/MenuItemDisplay.svelte +9 -2
- package/MenuItemDisplay.svelte.d.ts +1 -0
- package/MenuSeparator.svelte +3 -3
- package/Popover.svelte +68 -64
- package/Popover.svelte.d.ts +4 -2
- package/Progress.svelte +14 -14
- package/Radio.svelte +42 -16
- package/Radio.svelte.d.ts +1 -0
- package/RgbColorSliders.svelte +161 -0
- package/RgbColorSliders.svelte.d.ts +22 -0
- package/Select.svelte +50 -32
- package/Slider.svelte +108 -118
- package/Slider.svelte.d.ts +1 -0
- package/Switch.svelte +97 -34
- package/Switch.svelte.d.ts +1 -0
- package/Tab.svelte +53 -30
- package/TabList.svelte +23 -28
- package/TabList.svelte.d.ts +1 -0
- package/TabList.types.d.ts +1 -1
- package/TextArea.svelte +45 -20
- package/TextArea.svelte.d.ts +3 -2
- package/Tooltip.svelte +12 -11
- package/Tree.svelte +37 -35
- package/Tree.svelte.d.ts +2 -0
- package/Tree.types.d.ts +1 -0
- package/TreeChevron.svelte +1 -1
- package/TreeItem.svelte +47 -10
- package/TreeItem.svelte.d.ts +2 -0
- package/TreeItemDisplay.svelte +26 -8
- package/TreeItemDisplay.svelte.d.ts +2 -0
- package/actions/clickOutside.js +1 -1
- package/actions/trapKeyboardFocus.d.ts +3 -0
- package/actions/trapKeyboardFocus.js +52 -0
- package/floating-ui.types.d.ts +2 -0
- package/index.d.ts +10 -5
- package/index.js +8 -3
- package/package.json +12 -1
- package/stores/prefersReducedMotion.d.ts +1 -0
- package/stores/prefersReducedMotion.js +10 -0
- package/stores/usingKeyboard.d.ts +1 -0
- package/stores/usingKeyboard.js +13 -0
- package/theme/applyTheme.js +3 -2
- package/theme/colors.d.ts +1 -0
- package/theme/colors.js +28 -13
- package/theme/darkTheme.js +130 -87
- package/theme/lightTheme.js +107 -87
package/ListItem.svelte
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
<script>import { getContext } from "svelte";
|
|
2
2
|
import { LIST_CONTEXT_KEY } from "./List.constants";
|
|
3
|
-
import { readable } from "svelte/store";
|
|
3
|
+
import { readable, writable } from "svelte/store";
|
|
4
4
|
export let disabled = false;
|
|
5
5
|
export let value;
|
|
6
6
|
const {
|
|
7
|
+
colorful,
|
|
7
8
|
disabled: listDisabled,
|
|
8
9
|
selectedValue,
|
|
9
10
|
horizontal
|
|
10
11
|
} = getContext(LIST_CONTEXT_KEY) || {
|
|
12
|
+
colorful: readable(false),
|
|
11
13
|
disabled: readable(false),
|
|
12
|
-
selectedValue: void 0,
|
|
13
|
-
horizontal: false
|
|
14
|
+
selectedValue: writable(void 0),
|
|
15
|
+
horizontal: readable(false)
|
|
14
16
|
};
|
|
15
17
|
let itemRef;
|
|
16
18
|
$:
|
|
@@ -30,6 +32,7 @@ export const focus = (options) => {
|
|
|
30
32
|
aria-selected={selected}
|
|
31
33
|
bind:this={itemRef}
|
|
32
34
|
class="sterling-list-item"
|
|
35
|
+
class:colorful={$colorful}
|
|
33
36
|
class:disabled={disabled || $listDisabled}
|
|
34
37
|
class:item-disabled={disabled && !$listDisabled}
|
|
35
38
|
class:selected
|
|
@@ -65,7 +68,7 @@ export const focus = (options) => {
|
|
|
65
68
|
on:pointerover
|
|
66
69
|
on:pointerout
|
|
67
70
|
on:pointerup
|
|
68
|
-
on:wheel
|
|
71
|
+
on:wheel|passive
|
|
69
72
|
{...$$restProps}
|
|
70
73
|
>
|
|
71
74
|
<slot {disabled} {horizontal} {selected} {value}>{value}</slot>
|
|
@@ -75,7 +78,7 @@ export const focus = (options) => {
|
|
|
75
78
|
.sterling-list-item {
|
|
76
79
|
background-color: transparent;
|
|
77
80
|
box-sizing: border-box;
|
|
78
|
-
color: var(--stsv-
|
|
81
|
+
color: var(--stsv-common__color);
|
|
79
82
|
cursor: pointer;
|
|
80
83
|
margin: 0;
|
|
81
84
|
padding: 0.5em;
|
|
@@ -87,13 +90,23 @@ export const focus = (options) => {
|
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
.sterling-list-item:not(.disabled):not(.selected):hover {
|
|
90
|
-
background-color: var(--stsv-
|
|
91
|
-
color: var(--stsv-
|
|
93
|
+
background-color: var(--stsv-button__background-color--hover);
|
|
94
|
+
color: var(--stsv-button__color--hover);
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
.sterling-list-item.selected {
|
|
95
|
-
background-color: var(--stsv-
|
|
96
|
-
color: var(--stsv-
|
|
98
|
+
background-color: var(--stsv-button__background-color--active);
|
|
99
|
+
color: var(--stsv-button__color--active);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.sterling-list-item.colorful:not(.disabled):not(.selected):hover {
|
|
103
|
+
background-color: var(--stsv-button--colorful__background-color--hover);
|
|
104
|
+
color: var(--stsv-button--colorful__color--hover);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.sterling-list-item.colorful.selected {
|
|
108
|
+
background-color: var(--stsv-button--colorful__background-color--active);
|
|
109
|
+
color: var(--stsv-button--colorful__color--active);
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
.sterling-list-item.disabled {
|
|
@@ -102,7 +115,13 @@ export const focus = (options) => {
|
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
.sterling-list-item::after {
|
|
105
|
-
background:
|
|
118
|
+
background: repeating-linear-gradient(
|
|
119
|
+
45deg,
|
|
120
|
+
var(--stsv-common__background-color1--disabled),
|
|
121
|
+
var(--stsv-common__background-color1--disabled) 3px,
|
|
122
|
+
var(--stsv-common__background-color2--disabled) 3px,
|
|
123
|
+
var(--stsv-common__background-color2--disabled) 6px
|
|
124
|
+
);
|
|
106
125
|
bottom: 0;
|
|
107
126
|
content: '';
|
|
108
127
|
left: 0;
|
package/ListItem.svelte.d.ts
CHANGED
package/Menu.svelte
CHANGED
|
@@ -1,155 +1,126 @@
|
|
|
1
|
-
<script>import { getContext
|
|
2
|
-
import {
|
|
3
|
-
import { portal } from "./actions/portal";
|
|
1
|
+
<script>import { getContext } from "svelte";
|
|
2
|
+
import { slide } from "svelte/transition";
|
|
4
3
|
import { MENU_ITEM_CONTEXT_KEY } from "./MenuItem.constants";
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { isElementEnabledMenuItem, isElementMenuItem } from "./MenuItem.utils";
|
|
5
|
+
import { prefersReducedMotion } from "./stores/prefersReducedMotion";
|
|
7
6
|
let menuRef;
|
|
8
|
-
let
|
|
9
|
-
const
|
|
7
|
+
let menuItemsRef;
|
|
8
|
+
const slidNoOp = (node, params) => {
|
|
9
|
+
return { delay: 0, duration: 0 };
|
|
10
|
+
};
|
|
11
|
+
$:
|
|
12
|
+
slideMotion = !$prefersReducedMotion ? slide : slidNoOp;
|
|
13
|
+
const { rootValue } = getContext(MENU_ITEM_CONTEXT_KEY) || {};
|
|
10
14
|
export const blur = () => {
|
|
11
15
|
menuRef?.blur();
|
|
12
16
|
};
|
|
13
17
|
export const focus = (options) => {
|
|
14
18
|
menuRef?.focus(options);
|
|
15
19
|
};
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const isElementInThisMenu = (candidate) => {
|
|
21
|
+
return candidate && candidate.closest('[role="menu"]') === menuRef;
|
|
22
|
+
};
|
|
23
|
+
export const focusFirstMenuItem = () => {
|
|
24
|
+
let candidate = menuItemsRef?.firstElementChild;
|
|
25
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
26
|
+
candidate = candidate.nextElementSibling;
|
|
23
27
|
}
|
|
24
|
-
|
|
28
|
+
candidate?.focus({ preventScroll: true });
|
|
29
|
+
return !!candidate;
|
|
25
30
|
};
|
|
26
|
-
const
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
flip(),
|
|
35
|
-
shift({ padding: 0, mainAxis: true, crossAxis: true })
|
|
36
|
-
];
|
|
37
|
-
const computeMenuPosition = async () => {
|
|
38
|
-
if (reference && menuRef) {
|
|
39
|
-
menuPosition = await computePosition(reference, menuRef, {
|
|
40
|
-
placement: menuPlacement,
|
|
41
|
-
middleware
|
|
42
|
-
});
|
|
43
|
-
} else {
|
|
44
|
-
menuPosition = { x: 0, y: 0 };
|
|
31
|
+
export const focusPreviousMenuItem = () => {
|
|
32
|
+
let candidate = document.activeElement;
|
|
33
|
+
if (candidate && isElementMenuItem(candidate) && isElementInThisMenu(candidate)) {
|
|
34
|
+
candidate = menuItemsRef?.previousElementSibling;
|
|
35
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
36
|
+
candidate = candidate.previousElementSibling;
|
|
37
|
+
}
|
|
38
|
+
candidate?.focus();
|
|
45
39
|
}
|
|
40
|
+
return !!candidate;
|
|
46
41
|
};
|
|
47
|
-
|
|
42
|
+
export const focusNextMenuItem = () => {
|
|
43
|
+
let candidate = document.activeElement;
|
|
44
|
+
if (candidate && isElementMenuItem(candidate) && isElementInThisMenu(candidate)) {
|
|
45
|
+
candidate = menuItemsRef?.nextElementSibling;
|
|
46
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
47
|
+
candidate = candidate.nextElementSibling;
|
|
48
|
+
}
|
|
49
|
+
candidate?.focus();
|
|
50
|
+
}
|
|
51
|
+
return !!candidate;
|
|
48
52
|
};
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
export const focusLastMenuItem = () => {
|
|
54
|
+
let candidate = menuItemsRef?.lastElementChild;
|
|
55
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
56
|
+
candidate = candidate.previousElementSibling;
|
|
53
57
|
}
|
|
58
|
+
candidate?.focus({ preventScroll: true });
|
|
59
|
+
return !!candidate;
|
|
54
60
|
};
|
|
55
|
-
$:
|
|
56
|
-
menuRef, reference, autoUpdateMenuPosition();
|
|
57
|
-
$:
|
|
58
|
-
open, bodyHeight, computeMenuPosition();
|
|
59
|
-
onMount(() => {
|
|
60
|
-
resizeObserver.observe(document.body);
|
|
61
|
-
return () => {
|
|
62
|
-
resizeObserver.unobserve(document.body);
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
61
|
</script>
|
|
66
62
|
|
|
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
|
-
style="left:{menuPosition.x}px; top:{menuPosition.y}px"
|
|
107
|
-
>
|
|
108
|
-
<div class="sterling-menu-content">
|
|
109
|
-
<slot />
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
63
|
+
<div
|
|
64
|
+
bind:this={menuRef}
|
|
65
|
+
class="sterling-menu"
|
|
66
|
+
role="menu"
|
|
67
|
+
class:open
|
|
68
|
+
data-root-value={rootValue}
|
|
69
|
+
in:slideMotion={{ duration: 300 }}
|
|
70
|
+
out:slideMotion={{ duration: 100 }}
|
|
71
|
+
on:blur
|
|
72
|
+
on:click
|
|
73
|
+
on:copy
|
|
74
|
+
on:cut
|
|
75
|
+
on:dblclick
|
|
76
|
+
on:dragend
|
|
77
|
+
on:dragenter
|
|
78
|
+
on:dragleave
|
|
79
|
+
on:dragover
|
|
80
|
+
on:dragstart
|
|
81
|
+
on:drop
|
|
82
|
+
on:focus
|
|
83
|
+
on:focusin
|
|
84
|
+
on:focusout
|
|
85
|
+
on:keydown
|
|
86
|
+
on:keypress
|
|
87
|
+
on:keyup
|
|
88
|
+
on:mousedown
|
|
89
|
+
on:mouseenter
|
|
90
|
+
on:mouseleave
|
|
91
|
+
on:mousemove
|
|
92
|
+
on:mouseover
|
|
93
|
+
on:mouseout
|
|
94
|
+
on:mouseup
|
|
95
|
+
on:scroll
|
|
96
|
+
on:wheel|passive
|
|
97
|
+
on:paste
|
|
98
|
+
{...$$restProps}
|
|
99
|
+
>
|
|
100
|
+
<div bind:this={menuItemsRef} class="menu-items">
|
|
101
|
+
<slot />
|
|
112
102
|
</div>
|
|
113
|
-
|
|
103
|
+
</div>
|
|
114
104
|
|
|
115
105
|
<style>
|
|
116
|
-
.sterling-menu-portal {
|
|
117
|
-
position: relative;
|
|
118
|
-
overflow: visible;
|
|
119
|
-
background: rgba(255, 0, 0, 0.1);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
106
|
.sterling-menu {
|
|
123
|
-
background-color: var(--stsv-
|
|
124
|
-
border-color: var(--stsv-
|
|
125
|
-
border-radius: var(--stsv-
|
|
126
|
-
border-style: var(--stsv-
|
|
127
|
-
border-width: var(--stsv-
|
|
128
|
-
box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px -1px;
|
|
107
|
+
background-color: var(--stsv-common__background-color);
|
|
108
|
+
border-color: var(--stsv-common__border-color);
|
|
109
|
+
border-radius: var(--stsv-common__border-radius);
|
|
110
|
+
border-style: var(--stsv-common__border-style);
|
|
111
|
+
border-width: var(--stsv-common__border-width);
|
|
129
112
|
box-sizing: border-box;
|
|
130
113
|
display: grid;
|
|
131
114
|
grid-template-columns: 1fr;
|
|
132
115
|
grid-template-rows: 1fr;
|
|
133
116
|
height: fit-content;
|
|
134
|
-
left: 0;
|
|
135
|
-
max-height: calc(50vh);
|
|
136
|
-
overflow: auto;
|
|
137
|
-
overscroll-behavior: contain;
|
|
138
117
|
padding: 0.25em;
|
|
139
|
-
position: absolute;
|
|
140
|
-
top: 0;
|
|
141
|
-
width: max-content;
|
|
142
|
-
z-index: 1;
|
|
143
118
|
}
|
|
144
119
|
|
|
145
|
-
.
|
|
120
|
+
.menu-items {
|
|
146
121
|
display: grid;
|
|
147
122
|
grid-template-columns: 1fr;
|
|
148
123
|
grid-template-rows: auto;
|
|
149
|
-
row-gap: calc(2 * var(--stsv-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.sterling-menu.open {
|
|
153
|
-
display: grid;
|
|
124
|
+
row-gap: calc(2 * var(--stsv-common__outline-width));
|
|
154
125
|
}
|
|
155
126
|
</style>
|
package/Menu.svelte.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ import { SvelteComponentTyped } from "svelte";
|
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
4
|
[x: string]: any;
|
|
5
|
-
reference: HTMLElement;
|
|
6
|
-
open?: boolean | undefined;
|
|
7
5
|
blur?: (() => void) | undefined;
|
|
8
6
|
focus?: ((options?: FocusOptions) => void) | undefined;
|
|
7
|
+
focusFirstMenuItem?: (() => boolean) | undefined;
|
|
8
|
+
focusPreviousMenuItem?: (() => boolean) | undefined;
|
|
9
|
+
focusNextMenuItem?: (() => boolean) | undefined;
|
|
10
|
+
focusLastMenuItem?: (() => boolean) | undefined;
|
|
9
11
|
};
|
|
10
12
|
events: {
|
|
11
13
|
blur: FocusEvent;
|
|
@@ -48,5 +50,9 @@ export type MenuSlots = typeof __propDef.slots;
|
|
|
48
50
|
export default class Menu extends SvelteComponentTyped<MenuProps, MenuEvents, MenuSlots> {
|
|
49
51
|
get blur(): () => void;
|
|
50
52
|
get focus(): (options?: FocusOptions | undefined) => void;
|
|
53
|
+
get focusFirstMenuItem(): () => boolean;
|
|
54
|
+
get focusPreviousMenuItem(): () => boolean;
|
|
55
|
+
get focusNextMenuItem(): () => boolean;
|
|
56
|
+
get focusLastMenuItem(): () => boolean;
|
|
51
57
|
}
|
|
52
58
|
export {};
|
package/MenuBar.svelte
CHANGED
|
@@ -2,7 +2,25 @@
|
|
|
2
2
|
import { MENU_BAR_CONTEXT_KEY } from "./MenuBar.constants";
|
|
3
3
|
import { MENU_ITEM_CONTEXT_KEY } from "./MenuItem.constants";
|
|
4
4
|
import { writable } from "svelte/store";
|
|
5
|
+
import { isElementEnabledMenuItem } from "./MenuItem.utils";
|
|
6
|
+
import { idGenerator } from "./idGenerator";
|
|
7
|
+
import { clickOutside } from "./actions/clickOutside";
|
|
8
|
+
const openValues = writable([]);
|
|
9
|
+
const rootValue = idGenerator.nextId("MenuBar");
|
|
5
10
|
let menuBarRef;
|
|
11
|
+
let prevOpenValue = void 0;
|
|
12
|
+
$: {
|
|
13
|
+
if ($openValues.length > 0) {
|
|
14
|
+
prevOpenValue = $openValues[0];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
$: {
|
|
18
|
+
if ($openValues.length === 0 && prevOpenValue !== void 0) {
|
|
19
|
+
const candidate = menuBarRef.querySelector(`[data-value="${prevOpenValue}"]`);
|
|
20
|
+
candidate?.focus();
|
|
21
|
+
prevOpenValue = void 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
6
24
|
const dispatch = createEventDispatcher();
|
|
7
25
|
const raiseClose = (value) => {
|
|
8
26
|
dispatch("close", { value });
|
|
@@ -19,48 +37,73 @@ export const blur = () => {
|
|
|
19
37
|
export const focus = (options) => {
|
|
20
38
|
menuBarRef?.focus(options);
|
|
21
39
|
};
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const focusIndex = index === 0 ? $children.length - 1 : index - 1;
|
|
27
|
-
$children[focusIndex].focus();
|
|
28
|
-
$children[focusIndex].open();
|
|
40
|
+
const getOpenMenuBarItem = () => {
|
|
41
|
+
const value = $openValues[0];
|
|
42
|
+
if (value) {
|
|
43
|
+
return menuBarRef.querySelector(`[data-value="${value}"]`);
|
|
29
44
|
}
|
|
45
|
+
return null;
|
|
30
46
|
};
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
const openPreviousMenuBarItem = () => {
|
|
48
|
+
const openItem = getOpenMenuBarItem() || menuBarRef.firstElementChild;
|
|
49
|
+
let candidate = openItem?.previousElementSibling || menuBarRef.lastElementChild;
|
|
50
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
51
|
+
candidate = candidate.previousElementSibling || menuBarRef.lastElementChild;
|
|
52
|
+
if (candidate === openItem) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!candidate) {
|
|
57
|
+
candidate = menuBarRef.lastElementChild;
|
|
58
|
+
candidate = candidate && isElementEnabledMenuItem(candidate) ? candidate : null;
|
|
37
59
|
}
|
|
60
|
+
candidate?.click();
|
|
61
|
+
return !!candidate;
|
|
38
62
|
};
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
63
|
+
const openNextMenuBarItem = () => {
|
|
64
|
+
const openItem = getOpenMenuBarItem() || menuBarRef.lastElementChild;
|
|
65
|
+
let candidate = openItem?.nextElementSibling || menuBarRef.firstElementChild;
|
|
66
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
67
|
+
candidate = candidate.nextElementSibling || menuBarRef.firstElementChild;
|
|
68
|
+
if (candidate === openItem) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
43
71
|
}
|
|
72
|
+
if (!candidate) {
|
|
73
|
+
candidate = menuBarRef.firstElementChild;
|
|
74
|
+
candidate = candidate && isElementEnabledMenuItem(candidate) ? candidate : null;
|
|
75
|
+
}
|
|
76
|
+
candidate?.click();
|
|
77
|
+
return !!candidate;
|
|
78
|
+
};
|
|
79
|
+
const closeAllMenus = () => {
|
|
80
|
+
openValues.set([]);
|
|
44
81
|
};
|
|
82
|
+
const onClickOutside = (event) => {
|
|
83
|
+
const {
|
|
84
|
+
detail: { mouseEvent }
|
|
85
|
+
} = event;
|
|
86
|
+
let element = mouseEvent.target;
|
|
87
|
+
while (element) {
|
|
88
|
+
if (element.getAttribute("data-root-value") === rootValue) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
element = element.parentElement;
|
|
92
|
+
}
|
|
93
|
+
closeAllMenus?.();
|
|
94
|
+
};
|
|
95
|
+
setContext(MENU_BAR_CONTEXT_KEY, {
|
|
96
|
+
openPreviousMenuBarItem,
|
|
97
|
+
openNextMenuBarItem
|
|
98
|
+
});
|
|
45
99
|
setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
unregister: (menuItem) => {
|
|
50
|
-
children.set($children.filter((x) => x.value !== menuItem.value));
|
|
51
|
-
},
|
|
52
|
-
closeMenu: (recursive) => {
|
|
53
|
-
},
|
|
54
|
-
focusPrevious: openPreviousChild,
|
|
55
|
-
focusNext: openNextChild,
|
|
100
|
+
isMenuBarItem: true,
|
|
101
|
+
openValues,
|
|
102
|
+
rootValue,
|
|
56
103
|
onClose: raiseClose,
|
|
57
104
|
onOpen: raiseOpen,
|
|
58
105
|
onSelect: raiseSelect
|
|
59
106
|
});
|
|
60
|
-
setContext(MENU_BAR_CONTEXT_KEY, {
|
|
61
|
-
openPreviousMenu: openPreviousChild,
|
|
62
|
-
openNextMenu: openNextChild
|
|
63
|
-
});
|
|
64
107
|
</script>
|
|
65
108
|
|
|
66
109
|
<div
|
|
@@ -92,9 +135,11 @@ setContext(MENU_BAR_CONTEXT_KEY, {
|
|
|
92
135
|
on:mouseout
|
|
93
136
|
on:mouseup
|
|
94
137
|
on:scroll
|
|
95
|
-
on:wheel
|
|
138
|
+
on:wheel|passive
|
|
96
139
|
on:paste
|
|
97
140
|
{...$$restProps}
|
|
141
|
+
use:clickOutside
|
|
142
|
+
on:click_outside={onClickOutside}
|
|
98
143
|
>
|
|
99
144
|
<slot />
|
|
100
145
|
</div>
|
package/MenuBar.types.d.ts
CHANGED
package/MenuButton.svelte
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
<script>import { createEventDispatcher,
|
|
1
|
+
<script>import { createEventDispatcher, setContext, tick } from "svelte";
|
|
2
2
|
import { writable } from "svelte/store";
|
|
3
3
|
import Button from "./Button.svelte";
|
|
4
4
|
import Menu from "./Menu.svelte";
|
|
5
5
|
import { MENU_ITEM_CONTEXT_KEY } from "./MenuItem.constants";
|
|
6
|
-
import { focusFirstChild, focusNextChild, focusPreviousChild } from "./MenuItem.utils";
|
|
7
6
|
import { idGenerator } from "./idGenerator";
|
|
7
|
+
import Popover from "./Popover.svelte";
|
|
8
|
+
import { clickOutside } from "./actions/clickOutside";
|
|
8
9
|
export let open = false;
|
|
9
10
|
export let shape = "rounded";
|
|
10
11
|
export let value;
|
|
@@ -12,12 +13,16 @@ export let variant = "regular";
|
|
|
12
13
|
const instanceId = idGenerator.nextId("MenuButton");
|
|
13
14
|
let buttonRef;
|
|
14
15
|
let reference;
|
|
16
|
+
let menuRef;
|
|
15
17
|
let prevOpen = open;
|
|
16
18
|
$:
|
|
17
19
|
menuId = `${value}-menu-${instanceId}`;
|
|
18
20
|
$:
|
|
19
21
|
hasChildren = $$slots.items;
|
|
20
|
-
const
|
|
22
|
+
const openValues = writable([]);
|
|
23
|
+
$: {
|
|
24
|
+
open = $openValues.length > 0;
|
|
25
|
+
}
|
|
21
26
|
const dispatch = createEventDispatcher();
|
|
22
27
|
const raiseClose = (value2) => {
|
|
23
28
|
dispatch("close", { value: value2 });
|
|
@@ -28,10 +33,23 @@ const raiseOpen = (value2) => {
|
|
|
28
33
|
const raiseSelect = (value2) => {
|
|
29
34
|
dispatch("select", { value: value2 });
|
|
30
35
|
};
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
export const click = () => {
|
|
37
|
+
buttonRef?.click();
|
|
38
|
+
};
|
|
39
|
+
export const blur = () => {
|
|
40
|
+
buttonRef?.blur();
|
|
41
|
+
};
|
|
42
|
+
export const focus = (options) => {
|
|
43
|
+
buttonRef?.focus(options);
|
|
44
|
+
};
|
|
45
|
+
const onClick = async () => {
|
|
46
|
+
if (!open) {
|
|
47
|
+
openValues.set(["menu-button"]);
|
|
48
|
+
await tick();
|
|
49
|
+
menuRef?.focusFirstMenuItem();
|
|
50
|
+
} else {
|
|
51
|
+
open = false;
|
|
52
|
+
openValues.set([]);
|
|
35
53
|
}
|
|
36
54
|
};
|
|
37
55
|
$: {
|
|
@@ -40,29 +58,29 @@ $: {
|
|
|
40
58
|
}
|
|
41
59
|
prevOpen = open;
|
|
42
60
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
46
|
-
export const blur = () => {
|
|
47
|
-
buttonRef?.blur();
|
|
61
|
+
const closeAllMenus = () => {
|
|
62
|
+
openValues.set([]);
|
|
48
63
|
};
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
const onClickOutside = (event) => {
|
|
65
|
+
const {
|
|
66
|
+
detail: { mouseEvent }
|
|
67
|
+
} = event;
|
|
68
|
+
let element = mouseEvent.target;
|
|
69
|
+
while (element) {
|
|
70
|
+
if (element.getAttribute("data-root-value") === value) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
element = element.parentElement;
|
|
74
|
+
}
|
|
75
|
+
closeAllMenus?.();
|
|
51
76
|
};
|
|
52
77
|
setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
53
|
-
rootValue: value,
|
|
54
78
|
depth: 1,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
unregister: (menuItem) => {
|
|
59
|
-
children.set($children.filter((x) => x.value !== menuItem.value));
|
|
60
|
-
},
|
|
61
|
-
closeMenu: (recursive) => {
|
|
79
|
+
openValues,
|
|
80
|
+
rootValue: value,
|
|
81
|
+
closeContainingMenu: () => {
|
|
62
82
|
open = false;
|
|
63
83
|
},
|
|
64
|
-
focusPrevious: (currentValue) => focusPreviousChild($children, currentValue),
|
|
65
|
-
focusNext: (currentValue) => focusNextChild($children, currentValue),
|
|
66
84
|
onOpen: raiseOpen,
|
|
67
85
|
onClose: raiseClose,
|
|
68
86
|
onSelect: raiseSelect
|
|
@@ -117,12 +135,14 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
|
117
135
|
on:wheel
|
|
118
136
|
{...$$restProps}
|
|
119
137
|
>
|
|
120
|
-
<div class="reference" bind:this={reference}>
|
|
138
|
+
<div class="reference" bind:this={reference} use:clickOutside on:click_outside={onClickOutside}>
|
|
121
139
|
<slot {shape} {variant} />
|
|
122
140
|
</div>
|
|
123
|
-
<
|
|
124
|
-
<
|
|
125
|
-
|
|
141
|
+
<Popover {reference} placement="bottom-start" {open}>
|
|
142
|
+
<Menu bind:this={menuRef} id={menuId} {reference} {open}>
|
|
143
|
+
<slot name="items" />
|
|
144
|
+
</Menu>
|
|
145
|
+
</Popover>
|
|
126
146
|
</Button>
|
|
127
147
|
|
|
128
148
|
<style>
|
package/MenuItem.constants.d.ts
CHANGED
package/MenuItem.constants.js
CHANGED