@geoffcox/sterling-svelte 1.0.12 → 2.0.1
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/Button.svelte +8 -46
- package/dist/Button.svelte.d.ts +9 -65
- package/dist/Callout.svelte +47 -72
- package/dist/Callout.svelte.d.ts +14 -55
- package/dist/Callout.types.d.ts +11 -0
- package/dist/Checkbox.svelte +12 -48
- package/dist/Checkbox.svelte.d.ts +9 -62
- package/dist/Dialog.svelte +30 -38
- package/dist/Dialog.svelte.d.ts +13 -36
- package/dist/Dropdown.svelte +39 -71
- package/dist/Dropdown.svelte.d.ts +17 -76
- package/dist/Input.svelte +16 -50
- package/dist/Input.svelte.d.ts +12 -74
- package/dist/Label.svelte +55 -161
- package/dist/Label.svelte.d.ts +16 -81
- package/dist/Link.svelte +9 -41
- package/dist/Link.svelte.d.ts +11 -64
- package/dist/List.svelte +35 -85
- package/dist/List.svelte.d.ts +19 -74
- package/dist/List.types.d.ts +3 -11
- package/dist/ListItem.svelte +27 -56
- package/dist/ListItem.svelte.d.ts +12 -66
- package/dist/Menu.svelte +18 -45
- package/dist/Menu.svelte.d.ts +13 -63
- package/dist/MenuBar.svelte +36 -78
- package/dist/MenuBar.svelte.d.ts +12 -57
- package/dist/MenuButton.svelte +56 -85
- package/dist/MenuButton.svelte.d.ts +19 -70
- package/dist/MenuItem.svelte +107 -151
- package/dist/MenuItem.svelte.d.ts +21 -82
- package/dist/MenuItem.types.d.ts +1 -9
- package/dist/MenuSeparator.svelte +9 -7
- package/dist/MenuSeparator.svelte.d.ts +6 -20
- package/dist/Popover.svelte +45 -64
- package/dist/Popover.svelte.d.ts +14 -58
- package/dist/Progress.constants.d.ts +1 -1
- package/dist/Progress.constants.js +1 -1
- package/dist/Progress.svelte +24 -71
- package/dist/Progress.svelte.d.ts +11 -60
- package/dist/Progress.types.d.ts +3 -3
- package/dist/Radio.svelte +19 -92
- package/dist/Radio.svelte.d.ts +11 -63
- package/dist/Select.svelte +55 -94
- package/dist/Select.svelte.d.ts +19 -82
- package/dist/Slider.svelte +41 -98
- package/dist/Slider.svelte.d.ts +18 -65
- package/dist/Switch.svelte +29 -78
- package/dist/Switch.svelte.d.ts +20 -73
- package/dist/Tab.svelte +23 -66
- package/dist/Tab.svelte.d.ts +11 -70
- package/dist/TabList.svelte +50 -76
- package/dist/TabList.svelte.d.ts +17 -69
- package/dist/TabList.types.d.ts +3 -11
- package/dist/TextArea.svelte +17 -59
- package/dist/TextArea.svelte.d.ts +18 -68
- package/dist/Tooltip.svelte +23 -66
- package/dist/Tooltip.svelte.d.ts +9 -69
- package/dist/Tree.svelte +32 -83
- package/dist/Tree.svelte.d.ts +14 -66
- package/dist/Tree.types.d.ts +3 -11
- package/dist/TreeChevron.svelte +10 -49
- package/dist/TreeChevron.svelte.d.ts +8 -52
- package/dist/TreeItem.svelte +105 -159
- package/dist/TreeItem.svelte.d.ts +21 -100
- package/dist/TreeItem.types.d.ts +2 -12
- package/dist/actions/clickOutside.d.ts +1 -0
- package/dist/actions/clickOutside.js +1 -0
- package/dist/actions/extraClass.d.ts +8 -0
- package/dist/actions/extraClass.js +14 -0
- package/dist/index.d.ts +4 -12
- package/dist/index.js +3 -9
- package/package.json +20 -22
- package/dist/Button.constants.d.ts +0 -2
- package/dist/Button.constants.js +0 -2
- package/dist/Button.types.d.ts +0 -6
- package/dist/ColorPicker.constants.d.ts +0 -1
- package/dist/ColorPicker.constants.js +0 -1
- package/dist/ColorPicker.svelte +0 -287
- package/dist/ColorPicker.svelte.d.ts +0 -52
- package/dist/ColorPicker.types.d.ts +0 -4
- package/dist/ColorPicker.types.js +0 -1
- package/dist/HexColorSliders.svelte +0 -103
- package/dist/HexColorSliders.svelte.d.ts +0 -51
- package/dist/HslColorSliders.svelte +0 -128
- package/dist/HslColorSliders.svelte.d.ts +0 -51
- package/dist/Label.types.d.ts +0 -6
- package/dist/Label.types.js +0 -1
- package/dist/MenuItemDisplay.svelte +0 -32
- package/dist/MenuItemDisplay.svelte.d.ts +0 -39
- package/dist/RgbColorSliders.svelte +0 -93
- package/dist/RgbColorSliders.svelte.d.ts +0 -24
- package/dist/TreeItemDisplay.svelte +0 -74
- package/dist/TreeItemDisplay.svelte.d.ts +0 -73
- package/dist/css/Button.base.css +0 -54
- package/dist/css/Button.colorful.css +0 -17
- package/dist/css/Button.css +0 -8
- package/dist/css/Button.disabled.css +0 -22
- package/dist/css/Button.secondary.colorful.css +0 -15
- package/dist/css/Button.secondary.css +0 -11
- package/dist/css/Button.shapes.css +0 -14
- package/dist/css/Button.tool.colorful.css +0 -13
- package/dist/css/Button.tool.css +0 -18
- package/dist/css/Callout.base.css +0 -55
- package/dist/css/Callout.colorful.css +0 -5
- package/dist/css/Callout.css +0 -2
- package/dist/css/Checkbox.base.css +0 -121
- package/dist/css/Checkbox.colorful.css +0 -17
- package/dist/css/Checkbox.css +0 -3
- package/dist/css/Checkbox.disabled.css +0 -28
- package/dist/css/ColorPicker.base.css +0 -23
- package/dist/css/ColorPicker.css +0 -1
- package/dist/css/Dialog.base.css +0 -114
- package/dist/css/Dialog.css +0 -1
- package/dist/css/Dropdown.base.css +0 -105
- package/dist/css/Dropdown.colorful.css +0 -23
- package/dist/css/Dropdown.composed.css +0 -11
- package/dist/css/Dropdown.css +0 -4
- package/dist/css/Dropdown.disabled.css +0 -32
- package/dist/css/HexColorSliders.base.css +0 -87
- package/dist/css/HexColorSliders.css +0 -1
- package/dist/css/HslColorSliders.base.css +0 -105
- package/dist/css/HslColorSliders.css +0 -1
- package/dist/css/Input.base.css +0 -72
- package/dist/css/Input.colorful.css +0 -22
- package/dist/css/Input.composed.css +0 -12
- package/dist/css/Input.css +0 -4
- package/dist/css/Input.disabled.css +0 -24
- package/dist/css/Label.base.css +0 -114
- package/dist/css/Label.boxed.colorful.css +0 -21
- package/dist/css/Label.boxed.css +0 -31
- package/dist/css/Label.colorful.css +0 -3
- package/dist/css/Label.css +0 -5
- package/dist/css/Label.disabled.css +0 -9
- package/dist/css/Link.base.css +0 -43
- package/dist/css/Link.colorful.css +0 -15
- package/dist/css/Link.css +0 -11
- package/dist/css/Link.disabled.css +0 -10
- package/dist/css/Link.ghost.colorful.css +0 -7
- package/dist/css/Link.ghost.css +0 -11
- package/dist/css/Link.text-underline.css +0 -8
- package/dist/css/Link.text-underline.ghost.css +0 -13
- package/dist/css/Link.undecorated.colorful.css +0 -8
- package/dist/css/Link.undecorated.css +0 -8
- package/dist/css/Link.undecorated.ghost.css +0 -8
- package/dist/css/Link.undecorated.underline.css +0 -8
- package/dist/css/List.base.css +0 -84
- package/dist/css/List.composed.css +0 -8
- package/dist/css/List.css +0 -3
- package/dist/css/List.disabled.css +0 -7
- package/dist/css/ListItem.base.css +0 -33
- package/dist/css/ListItem.css +0 -2
- package/dist/css/ListItem.disabled.css +0 -28
- package/dist/css/Menu.base.css +0 -21
- package/dist/css/Menu.css +0 -1
- package/dist/css/MenuBar.base.css +0 -9
- package/dist/css/MenuBar.css +0 -1
- package/dist/css/MenuButton.base.css +0 -13
- package/dist/css/MenuButton.css +0 -1
- package/dist/css/MenuItem.base.css +0 -48
- package/dist/css/MenuItem.css +0 -1
- package/dist/css/MenuItemDisplay.base.css +0 -79
- package/dist/css/MenuItemDisplay.css +0 -2
- package/dist/css/MenuItemDisplay.disabled.css +0 -28
- package/dist/css/MenuSeparator.base.css +0 -5
- package/dist/css/MenuSeparator.css +0 -1
- package/dist/css/Popover.css +0 -21
- package/dist/css/Progress.base.css +0 -85
- package/dist/css/Progress.css +0 -2
- package/dist/css/Progress.disabled.css +0 -17
- package/dist/css/Radio.base.css +0 -109
- package/dist/css/Radio.colorful.css +0 -18
- package/dist/css/Radio.css +0 -3
- package/dist/css/Radio.disabled.css +0 -28
- package/dist/css/RgbColorSliders.base.css +0 -94
- package/dist/css/RgbColorSliders.css +0 -1
- package/dist/css/Select.base.css +0 -101
- package/dist/css/Select.colorful.css +0 -24
- package/dist/css/Select.composed.css +0 -12
- package/dist/css/Select.css +0 -4
- package/dist/css/Select.disabled.css +0 -28
- package/dist/css/Slider.base.css +0 -152
- package/dist/css/Slider.colorful.css +0 -11
- package/dist/css/Slider.composed.css +0 -8
- package/dist/css/Slider.css +0 -4
- package/dist/css/Slider.disabled.css +0 -30
- package/dist/css/Switch.base.css +0 -175
- package/dist/css/Switch.colorful.css +0 -45
- package/dist/css/Switch.css +0 -3
- package/dist/css/Switch.disabled.css +0 -30
- package/dist/css/Tab.base.css +0 -96
- package/dist/css/Tab.colorful.css +0 -13
- package/dist/css/Tab.css +0 -3
- package/dist/css/Tab.disabled.css +0 -36
- package/dist/css/TabList.base.css +0 -34
- package/dist/css/TabList.css +0 -1
- package/dist/css/TextArea.base.css +0 -62
- package/dist/css/TextArea.colorful.css +0 -17
- package/dist/css/TextArea.composed.css +0 -8
- package/dist/css/TextArea.css +0 -4
- package/dist/css/TextArea.disabled.css +0 -28
- package/dist/css/Tooltip.base.css +0 -6
- package/dist/css/Tooltip.css +0 -1
- package/dist/css/Tree.base.css +0 -49
- package/dist/css/Tree.composed.css +0 -8
- package/dist/css/Tree.css +0 -3
- package/dist/css/Tree.disabled.css +0 -27
- package/dist/css/TreeChevron.base.css +0 -86
- package/dist/css/TreeChevron.css +0 -1
- package/dist/css/TreeItem.base.css +0 -3
- package/dist/css/TreeItem.css +0 -1
- package/dist/css/TreeItemDisplay.base.css +0 -48
- package/dist/css/TreeItemDisplay.colorful.css +0 -9
- package/dist/css/TreeItemDisplay.css +0 -3
- package/dist/css/TreeItemDisplay.disabled.css +0 -28
- package/dist/css/dark-mode.css +0 -134
- package/dist/css/light-mode.css +0 -134
- package/dist/css/sterling.css +0 -37
- package/dist/package.json +0 -108
- /package/dist/{Button.types.js → Callout.types.js} +0 -0
package/dist/MenuItem.svelte
CHANGED
|
@@ -1,46 +1,24 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
1
|
+
<svelte:options runes={true} />
|
|
2
|
+
|
|
3
|
+
<script lang="ts">import { getContext, setContext, tick } from 'svelte';
|
|
3
4
|
import { idGenerator } from './idGenerator';
|
|
4
5
|
import Menu from './Menu.svelte';
|
|
5
6
|
import { MENU_BAR_CONTEXT_KEY } from './MenuBar.constants';
|
|
6
7
|
import { MENU_ITEM_CONTEXT_KEY } from './MenuItem.constants';
|
|
7
8
|
import { isElementEnabledMenuItem } from './MenuItem.utils';
|
|
8
|
-
import MenuItemDisplay from './MenuItemDisplay.svelte';
|
|
9
9
|
import Popover from './Popover.svelte';
|
|
10
10
|
import { usingKeyboard } from './mediaQueries/usingKeyboard';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* Use with role='menuitemcheckbox' or role='menuitemradio'.
|
|
15
|
-
*/
|
|
16
|
-
export let checked = false;
|
|
17
|
-
/** When true, the menu item is disabled. */
|
|
18
|
-
export let disabled = false;
|
|
19
|
-
/** The role of the menu item. */
|
|
20
|
-
export let role = 'menuitem';
|
|
21
|
-
/** The text of the menu item. Not used when the item slot is filled.*/
|
|
22
|
-
export let text = undefined;
|
|
23
|
-
/** The value uniquely identifying this menu item within the menu hierarchy. */
|
|
24
|
-
export let value;
|
|
25
|
-
/** Additional class names to apply. */
|
|
26
|
-
export let variant = '';
|
|
27
|
-
/** Additional class names to apply to the sub Menu*/
|
|
28
|
-
export let menuVariant = '';
|
|
29
|
-
// ----- Get Context ----- //
|
|
30
|
-
const { isMenuBarItem, openValues = writable([]), rootValue = value, depth = 0, closeContainingMenu = undefined, onOpen = undefined, onClose = undefined, onSelect = undefined } = getContext(MENU_ITEM_CONTEXT_KEY) || {};
|
|
31
|
-
const { openPreviousMenuBarItem = undefined, openNextMenuBarItem = undefined } = getContext(MENU_BAR_CONTEXT_KEY) || {};
|
|
32
|
-
// ----- State ----- //
|
|
11
|
+
let { checked, children, class: _class, disabled, item, menuClass, onClose, onOpen, onSelect, role = 'menuitem', text, shortcut, value, ...rest } = $props();
|
|
12
|
+
const menuItemContext = getContext(MENU_ITEM_CONTEXT_KEY) || {};
|
|
13
|
+
const menuBarContext = getContext(MENU_BAR_CONTEXT_KEY) || {};
|
|
33
14
|
const instanceId = idGenerator.nextId('MenuItem');
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let
|
|
38
|
-
let
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
let prevOpen = open;
|
|
42
|
-
$: hasChildren = $$slots.default;
|
|
43
|
-
// ----- Methods ----- //
|
|
15
|
+
let displayId = $derived(`${value}-display-${instanceId}`);
|
|
16
|
+
let open = $derived(menuItemContext.openValues?.includes(value));
|
|
17
|
+
let prevOpen = $state(menuItemContext.openValues?.includes(value));
|
|
18
|
+
let menuId = $derived(`${value}-menu-${instanceId}`);
|
|
19
|
+
let menuItemRef = $state();
|
|
20
|
+
let menuRef = $state();
|
|
21
|
+
//#region methods
|
|
44
22
|
export const blur = () => {
|
|
45
23
|
menuItemRef?.blur();
|
|
46
24
|
};
|
|
@@ -50,30 +28,28 @@ export const click = () => {
|
|
|
50
28
|
export const focus = (options) => {
|
|
51
29
|
menuItemRef?.focus(options);
|
|
52
30
|
};
|
|
53
|
-
|
|
54
|
-
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region events
|
|
55
33
|
const raiseClose = (value) => {
|
|
56
|
-
dispatch('close', { value });
|
|
57
34
|
onClose?.(value);
|
|
35
|
+
menuItemContext.onClose?.(value);
|
|
58
36
|
};
|
|
59
37
|
const raiseOpen = (value) => {
|
|
60
|
-
dispatch('open', { value });
|
|
61
38
|
onOpen?.(value);
|
|
39
|
+
menuItemContext.onOpen?.(value);
|
|
62
40
|
};
|
|
63
|
-
$: {
|
|
64
|
-
if (hasChildren && open !== prevOpen) {
|
|
65
|
-
open ? raiseOpen(value) : raiseClose(value);
|
|
66
|
-
}
|
|
67
|
-
prevOpen = open;
|
|
68
|
-
}
|
|
69
|
-
// dispatches the event and bubbles it up the context
|
|
70
|
-
// so that container components can subscribe to select
|
|
71
|
-
// events for children.
|
|
72
41
|
const raiseSelect = (value) => {
|
|
73
|
-
dispatch('select', { value });
|
|
74
42
|
onSelect?.(value);
|
|
43
|
+
menuItemContext.onSelect?.(value);
|
|
75
44
|
};
|
|
76
|
-
|
|
45
|
+
$effect(() => {
|
|
46
|
+
if (open !== prevOpen) {
|
|
47
|
+
open ? raiseOpen(value) : raiseClose(value);
|
|
48
|
+
}
|
|
49
|
+
prevOpen = open;
|
|
50
|
+
});
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region focus
|
|
77
53
|
const focusPreviousMenuItem = () => {
|
|
78
54
|
let candidate = menuItemRef?.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
79
55
|
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
@@ -96,33 +72,32 @@ const focusNextMenuItem = () => {
|
|
|
96
72
|
candidate?.focus();
|
|
97
73
|
return !!candidate;
|
|
98
74
|
};
|
|
99
|
-
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region open/close
|
|
100
77
|
// opens the menu for this menu item
|
|
101
78
|
const openMenu = () => {
|
|
102
|
-
if (
|
|
79
|
+
if (!menuItemContext.openValues.includes(value)) {
|
|
103
80
|
// slice to depth to close any sibling menus that are open
|
|
104
|
-
|
|
81
|
+
menuItemContext.openValues = [
|
|
82
|
+
...menuItemContext.openValues.slice(0, menuItemContext.depth),
|
|
83
|
+
value
|
|
84
|
+
];
|
|
105
85
|
}
|
|
106
86
|
};
|
|
107
87
|
// closes the menu for this menu item
|
|
108
88
|
const closeMenu = async () => {
|
|
109
|
-
const index =
|
|
89
|
+
const index = menuItemContext.openValues.indexOf(value);
|
|
110
90
|
if (index !== -1) {
|
|
111
|
-
openValues.
|
|
91
|
+
menuItemContext.openValues = [...menuItemContext.openValues.slice(0, index)];
|
|
112
92
|
await tick();
|
|
113
93
|
menuItemRef?.focus();
|
|
114
94
|
}
|
|
115
95
|
};
|
|
116
96
|
const closeAllMenus = () => {
|
|
117
|
-
openValues
|
|
97
|
+
menuItemContext.openValues = [];
|
|
118
98
|
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
mounted = true;
|
|
122
|
-
});
|
|
123
|
-
afterUpdate(() => {
|
|
124
|
-
prevOpen = open;
|
|
125
|
-
});
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region event handlers
|
|
126
101
|
const onKeyDown = async (event) => {
|
|
127
102
|
if (!disabled && !event.altKey && !event.ctrlKey && !event.shiftKey) {
|
|
128
103
|
switch (event.key) {
|
|
@@ -130,7 +105,7 @@ const onKeyDown = async (event) => {
|
|
|
130
105
|
// ARIA menubar/menuitem:
|
|
131
106
|
// If the currently focused menuitem has a submenu,
|
|
132
107
|
// opens the submenu and places focus on the first item in the submenu.
|
|
133
|
-
if (isMenuBarItem &&
|
|
108
|
+
if (menuItemContext.isMenuBarItem && children) {
|
|
134
109
|
openMenu();
|
|
135
110
|
setTimeout(async () => {
|
|
136
111
|
await tick();
|
|
@@ -140,7 +115,7 @@ const onKeyDown = async (event) => {
|
|
|
140
115
|
event.stopPropagation();
|
|
141
116
|
return false;
|
|
142
117
|
}
|
|
143
|
-
if (!isMenuBarItem) {
|
|
118
|
+
if (!menuItemContext.isMenuBarItem) {
|
|
144
119
|
// ARIA menuitem:
|
|
145
120
|
// Moves focus to the next item, optionally wrapping from the last to the first.
|
|
146
121
|
focusNextMenuItem();
|
|
@@ -152,7 +127,7 @@ const onKeyDown = async (event) => {
|
|
|
152
127
|
case 'ArrowLeft':
|
|
153
128
|
// ARIA menubar/menuitem:
|
|
154
129
|
// Moves focus to the previous item, optionally wrapping from the first to the last.
|
|
155
|
-
if (isMenuBarItem) {
|
|
130
|
+
if (menuItemContext.isMenuBarItem) {
|
|
156
131
|
focusPreviousMenuItem();
|
|
157
132
|
event.preventDefault();
|
|
158
133
|
event.stopPropagation();
|
|
@@ -161,8 +136,8 @@ const onKeyDown = async (event) => {
|
|
|
161
136
|
// ARIA menuitem:
|
|
162
137
|
// When focus is in a submenu of an item in a menu,
|
|
163
138
|
// closes the submenu and returns focus to the parent menuitem.
|
|
164
|
-
if (depth > 1) {
|
|
165
|
-
closeContainingMenu?.();
|
|
139
|
+
if (menuItemContext.depth && menuItemContext.depth > 1) {
|
|
140
|
+
menuItemContext.closeContainingMenu?.();
|
|
166
141
|
event.preventDefault();
|
|
167
142
|
event.stopPropagation();
|
|
168
143
|
return false;
|
|
@@ -175,14 +150,14 @@ const onKeyDown = async (event) => {
|
|
|
175
150
|
// if focus is now on a menuitem with a submenu,
|
|
176
151
|
// either opens the submenu of that menuitem without moving focus into the submenu,
|
|
177
152
|
// or opens the submenu of that menuitem and places focus on the first item in the submenu.
|
|
178
|
-
openPreviousMenuBarItem?.();
|
|
153
|
+
menuBarContext.openPreviousMenuBarItem?.();
|
|
179
154
|
event.preventDefault();
|
|
180
155
|
event.stopPropagation();
|
|
181
156
|
return false;
|
|
182
157
|
case 'ArrowRight':
|
|
183
158
|
// ARIA menubar:
|
|
184
159
|
// Moves focus to the next item, optionally wrapping from the last to the first.
|
|
185
|
-
if (isMenuBarItem) {
|
|
160
|
+
if (menuItemContext.isMenuBarItem) {
|
|
186
161
|
focusNextMenuItem();
|
|
187
162
|
event.preventDefault();
|
|
188
163
|
event.stopPropagation();
|
|
@@ -191,7 +166,7 @@ const onKeyDown = async (event) => {
|
|
|
191
166
|
// ARIA menuitem:
|
|
192
167
|
// When focus is in a menu and on a menuitem that has a submenu,
|
|
193
168
|
// opens the submenu and places focus on its first item
|
|
194
|
-
if (
|
|
169
|
+
if (children) {
|
|
195
170
|
openMenu();
|
|
196
171
|
setTimeout(async () => {
|
|
197
172
|
await tick();
|
|
@@ -209,8 +184,8 @@ const onKeyDown = async (event) => {
|
|
|
209
184
|
// if focus is now on a menuitem with a submenu,
|
|
210
185
|
// either opens the submenu of that menuitem without moving focus into the submenu,
|
|
211
186
|
// or opens the submenu of that menuitem and places focus on the first item in the submenu.
|
|
212
|
-
if (openNextMenuBarItem) {
|
|
213
|
-
openNextMenuBarItem();
|
|
187
|
+
if (menuBarContext.openNextMenuBarItem) {
|
|
188
|
+
menuBarContext.openNextMenuBarItem();
|
|
214
189
|
event.preventDefault();
|
|
215
190
|
event.stopPropagation();
|
|
216
191
|
return false;
|
|
@@ -220,7 +195,7 @@ const onKeyDown = async (event) => {
|
|
|
220
195
|
// ARIA menubar/menuitem:
|
|
221
196
|
// If the currently focused menuitem has a submenu,
|
|
222
197
|
// opens the submenu and places focus on the last item in the submenu.
|
|
223
|
-
if (isMenuBarItem &&
|
|
198
|
+
if (menuItemContext.isMenuBarItem && children) {
|
|
224
199
|
openMenu();
|
|
225
200
|
setTimeout(async () => {
|
|
226
201
|
await tick();
|
|
@@ -232,7 +207,7 @@ const onKeyDown = async (event) => {
|
|
|
232
207
|
}
|
|
233
208
|
// ARIA menuitem:
|
|
234
209
|
// Moves focus to the previous item, optionally wrapping from the first to the last.
|
|
235
|
-
if (!isMenuBarItem) {
|
|
210
|
+
if (!menuItemContext.isMenuBarItem) {
|
|
236
211
|
focusPreviousMenuItem();
|
|
237
212
|
event.preventDefault();
|
|
238
213
|
event.stopPropagation();
|
|
@@ -243,21 +218,23 @@ const onKeyDown = async (event) => {
|
|
|
243
218
|
// ARIA menuitem:
|
|
244
219
|
// Close the menu that contains focus and return focus to the element or context,
|
|
245
220
|
// e.g., menu button or parent menuitem, from which the menu was opened.
|
|
246
|
-
open = false;
|
|
221
|
+
// open = false;
|
|
247
222
|
closeAllMenus();
|
|
248
223
|
event.preventDefault();
|
|
249
224
|
event.stopPropagation();
|
|
250
225
|
return false;
|
|
251
226
|
}
|
|
252
227
|
}
|
|
228
|
+
rest.onkeydown?.(event);
|
|
253
229
|
};
|
|
254
230
|
const onMouseEnter = (event) => {
|
|
255
231
|
menuItemRef?.focus();
|
|
232
|
+
rest.onmouseenter?.(event);
|
|
256
233
|
};
|
|
257
234
|
const onClick = (event) => {
|
|
258
235
|
if (!disabled) {
|
|
259
|
-
if (
|
|
260
|
-
if (
|
|
236
|
+
if (children) {
|
|
237
|
+
if (!menuItemContext.openValues.includes(value)) {
|
|
261
238
|
openMenu();
|
|
262
239
|
if ($usingKeyboard) {
|
|
263
240
|
setTimeout(async () => {
|
|
@@ -281,105 +258,84 @@ const onClick = (event) => {
|
|
|
281
258
|
return false;
|
|
282
259
|
}
|
|
283
260
|
}
|
|
261
|
+
rest.onclick?.(event);
|
|
284
262
|
};
|
|
285
|
-
|
|
286
|
-
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region set context
|
|
265
|
+
let menuItemChildContext = {
|
|
287
266
|
isMenuBarItem: false,
|
|
288
|
-
openValues
|
|
289
|
-
|
|
290
|
-
depth: depth + 1,
|
|
291
|
-
closeContainingMenu: () => {
|
|
292
|
-
closeMenu();
|
|
267
|
+
get openValues() {
|
|
268
|
+
return menuItemContext.openValues;
|
|
293
269
|
},
|
|
270
|
+
set openValues(value) {
|
|
271
|
+
menuItemContext.openValues = value;
|
|
272
|
+
},
|
|
273
|
+
rootValue: menuItemContext.rootValue || value,
|
|
274
|
+
depth: menuItemContext.depth ? menuItemContext.depth + 1 : 1,
|
|
275
|
+
closeContainingMenu: closeMenu,
|
|
294
276
|
onOpen: raiseOpen,
|
|
295
277
|
onClose: raiseClose,
|
|
296
278
|
onSelect: raiseSelect
|
|
297
|
-
}
|
|
279
|
+
};
|
|
280
|
+
setContext(MENU_ITEM_CONTEXT_KEY, menuItemChildContext);
|
|
281
|
+
//#endregion
|
|
298
282
|
</script>
|
|
299
283
|
|
|
284
|
+
{#snippet renderDefaultItem()}
|
|
285
|
+
<div class="sterling-menu-item-display" class:disabled>
|
|
286
|
+
<div
|
|
287
|
+
class="check"
|
|
288
|
+
class:checkmark={role === 'menuitemcheckbox'}
|
|
289
|
+
class:bullet={role === 'menuitemradio'}
|
|
290
|
+
class:checked
|
|
291
|
+
></div>
|
|
292
|
+
<div class="content">
|
|
293
|
+
{text}
|
|
294
|
+
</div>
|
|
295
|
+
{#if shortcut}
|
|
296
|
+
<div class="shortcut">
|
|
297
|
+
{shortcut}
|
|
298
|
+
</div>
|
|
299
|
+
{/if}
|
|
300
|
+
<div class="chevron" class:has-children={!menuItemContext.isMenuBarItem && !!children}></div>
|
|
301
|
+
</div>
|
|
302
|
+
{/snippet}
|
|
303
|
+
|
|
300
304
|
<button
|
|
305
|
+
bind:this={menuItemRef}
|
|
301
306
|
aria-controls={menuId}
|
|
302
307
|
aria-disabled={disabled}
|
|
303
308
|
aria-expanded={open}
|
|
304
|
-
aria-haspopup={
|
|
309
|
+
aria-haspopup={!!children}
|
|
305
310
|
aria-owns={menuId}
|
|
306
|
-
|
|
307
|
-
class={`sterling-menu-item ${variant}`}
|
|
311
|
+
class={['sterling-menu-item', _class].filter(Boolean).join(' ')}
|
|
308
312
|
class:using-keyboard={usingKeyboard}
|
|
309
313
|
data-value={value}
|
|
310
|
-
data-root-value={rootValue}
|
|
314
|
+
data-root-value={menuItemContext.rootValue}
|
|
311
315
|
{disabled}
|
|
312
316
|
{role}
|
|
313
317
|
tabindex={0}
|
|
314
318
|
type="button"
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
on:dragenter
|
|
320
|
-
on:dragleave
|
|
321
|
-
on:dragover
|
|
322
|
-
on:dragstart
|
|
323
|
-
on:drop
|
|
324
|
-
on:focus
|
|
325
|
-
on:focusin
|
|
326
|
-
on:focusout
|
|
327
|
-
on:keydown
|
|
328
|
-
on:keypress
|
|
329
|
-
on:keyup
|
|
330
|
-
on:mousedown
|
|
331
|
-
on:mouseenter
|
|
332
|
-
on:mouseleave
|
|
333
|
-
on:mousemove
|
|
334
|
-
on:mouseover
|
|
335
|
-
on:mouseout
|
|
336
|
-
on:mouseup
|
|
337
|
-
on:pointercancel
|
|
338
|
-
on:pointerdown
|
|
339
|
-
on:pointerenter
|
|
340
|
-
on:pointerleave
|
|
341
|
-
on:pointermove
|
|
342
|
-
on:pointerover
|
|
343
|
-
on:pointerout
|
|
344
|
-
on:pointerup
|
|
345
|
-
on:wheel|passive
|
|
346
|
-
on:click={onClick}
|
|
347
|
-
on:keydown={onKeyDown}
|
|
348
|
-
on:mouseenter={onMouseEnter}
|
|
349
|
-
{...$$restProps}
|
|
319
|
+
{...rest}
|
|
320
|
+
onclick={onClick}
|
|
321
|
+
onkeydown={onKeyDown}
|
|
322
|
+
onmouseenter={onMouseEnter}
|
|
350
323
|
>
|
|
351
324
|
<div class="item" id={displayId}>
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
{
|
|
356
|
-
|
|
357
|
-
{hasChildren}
|
|
358
|
-
{isMenuBarItem}
|
|
359
|
-
{open}
|
|
360
|
-
{role}
|
|
361
|
-
{text}
|
|
362
|
-
{value}
|
|
363
|
-
{variant}
|
|
364
|
-
>
|
|
365
|
-
<MenuItemDisplay
|
|
366
|
-
{checked}
|
|
367
|
-
{disabled}
|
|
368
|
-
{hasChildren}
|
|
369
|
-
{isMenuBarItem}
|
|
370
|
-
menuItemRole={role}
|
|
371
|
-
{variant}>{text}</MenuItemDisplay
|
|
372
|
-
>
|
|
373
|
-
</slot>
|
|
325
|
+
{#if item}
|
|
326
|
+
{@render item()}
|
|
327
|
+
{:else}
|
|
328
|
+
{@render renderDefaultItem()}
|
|
329
|
+
{/if}
|
|
374
330
|
</div>
|
|
375
|
-
{#if menuItemRef && open &&
|
|
331
|
+
{#if menuItemRef && open && children}
|
|
376
332
|
<Popover
|
|
377
333
|
reference={menuItemRef}
|
|
378
|
-
placement={isMenuBarItem ? 'bottom-start' : 'right-start'}
|
|
334
|
+
placement={menuItemContext.isMenuBarItem ? 'bottom-start' : 'right-start'}
|
|
379
335
|
{open}
|
|
380
336
|
>
|
|
381
|
-
<Menu bind:this={menuRef} id={menuId}
|
|
382
|
-
|
|
337
|
+
<Menu bind:this={menuRef} id={menuId} class={menuClass}>
|
|
338
|
+
{@render children()}
|
|
383
339
|
</Menu>
|
|
384
340
|
</Popover>
|
|
385
341
|
{/if}
|
|
@@ -1,83 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
events: {
|
|
17
|
-
blur: FocusEvent;
|
|
18
|
-
click: MouseEvent;
|
|
19
|
-
dblclick: MouseEvent;
|
|
20
|
-
dragend: DragEvent;
|
|
21
|
-
dragenter: DragEvent;
|
|
22
|
-
dragleave: DragEvent;
|
|
23
|
-
dragover: DragEvent;
|
|
24
|
-
dragstart: DragEvent;
|
|
25
|
-
drop: DragEvent;
|
|
26
|
-
focus: FocusEvent;
|
|
27
|
-
focusin: FocusEvent;
|
|
28
|
-
focusout: FocusEvent;
|
|
29
|
-
keydown: KeyboardEvent;
|
|
30
|
-
keypress: KeyboardEvent;
|
|
31
|
-
keyup: KeyboardEvent;
|
|
32
|
-
mousedown: MouseEvent;
|
|
33
|
-
mouseenter: MouseEvent;
|
|
34
|
-
mouseleave: MouseEvent;
|
|
35
|
-
mousemove: MouseEvent;
|
|
36
|
-
mouseover: MouseEvent;
|
|
37
|
-
mouseout: MouseEvent;
|
|
38
|
-
mouseup: MouseEvent;
|
|
39
|
-
pointercancel: PointerEvent;
|
|
40
|
-
pointerdown: PointerEvent;
|
|
41
|
-
pointerenter: PointerEvent;
|
|
42
|
-
pointerleave: PointerEvent;
|
|
43
|
-
pointermove: PointerEvent;
|
|
44
|
-
pointerover: PointerEvent;
|
|
45
|
-
pointerout: PointerEvent;
|
|
46
|
-
pointerup: PointerEvent;
|
|
47
|
-
wheel: WheelEvent;
|
|
48
|
-
close: CustomEvent<any>;
|
|
49
|
-
open: CustomEvent<any>;
|
|
50
|
-
select: CustomEvent<any>;
|
|
51
|
-
} & {
|
|
52
|
-
[evt: string]: CustomEvent<any>;
|
|
53
|
-
};
|
|
54
|
-
slots: {
|
|
55
|
-
item: {
|
|
56
|
-
checked: boolean;
|
|
57
|
-
depth: number;
|
|
58
|
-
disabled: boolean;
|
|
59
|
-
hasChildren: boolean;
|
|
60
|
-
isMenuBarItem: boolean | undefined;
|
|
61
|
-
open: boolean;
|
|
62
|
-
role: "menuitem" | "menuitemcheckbox" | "menuitemradio";
|
|
63
|
-
text: string | undefined;
|
|
64
|
-
value: string;
|
|
65
|
-
variant: string;
|
|
66
|
-
};
|
|
67
|
-
default: {
|
|
68
|
-
depth: number;
|
|
69
|
-
disabled: boolean;
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
exports?: undefined;
|
|
73
|
-
bindings?: undefined;
|
|
1
|
+
import type { MenuItemRole } from './MenuItem.types';
|
|
2
|
+
import { type Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
|
+
type Props = HTMLButtonAttributes & {
|
|
5
|
+
checked?: boolean | null;
|
|
6
|
+
item?: Snippet;
|
|
7
|
+
menuClass?: string;
|
|
8
|
+
onClose?: (value: string) => void;
|
|
9
|
+
onOpen?: (value: string) => void;
|
|
10
|
+
onSelect?: (value: string) => void;
|
|
11
|
+
role?: MenuItemRole;
|
|
12
|
+
shortcut?: string;
|
|
13
|
+
text?: string;
|
|
14
|
+
value: string;
|
|
74
15
|
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
export {};
|
|
16
|
+
declare const MenuItem: import("svelte").Component<Props, {
|
|
17
|
+
blur: () => void;
|
|
18
|
+
click: () => void;
|
|
19
|
+
focus: (options?: FocusOptions) => void;
|
|
20
|
+
}, "">;
|
|
21
|
+
type MenuItem = ReturnType<typeof MenuItem>;
|
|
22
|
+
export default MenuItem;
|
package/dist/MenuItem.types.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { Writable } from 'svelte/store';
|
|
3
1
|
import type { MENU_ITEM_ROLES } from './MenuItem.constants';
|
|
4
2
|
type MenuItemRoleTuple = typeof MENU_ITEM_ROLES;
|
|
5
3
|
export type MenuItemRole = MenuItemRoleTuple[number];
|
|
@@ -10,14 +8,8 @@ export type MenuItemRegistration = {
|
|
|
10
8
|
focus: () => void;
|
|
11
9
|
};
|
|
12
10
|
export type MenuItemContext = {
|
|
13
|
-
/**
|
|
14
|
-
* If the menu item is a top-level item in a menu bar
|
|
15
|
-
*/
|
|
16
11
|
isMenuBarItem?: boolean;
|
|
17
|
-
|
|
18
|
-
* The menu item values for the chain of open menus.
|
|
19
|
-
*/
|
|
20
|
-
openValues: Writable<string[]>;
|
|
12
|
+
openValues: string[];
|
|
21
13
|
rootValue?: string;
|
|
22
14
|
depth?: number;
|
|
23
15
|
closeContainingMenu?: () => void;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
1
|
+
<svelte:options runes={true} />
|
|
2
|
+
|
|
3
|
+
<script lang="ts">let { class: _class, ...rest } = $props();
|
|
4
|
+
export {};
|
|
3
5
|
</script>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
<div
|
|
8
|
+
class={['sterling-menu-separator', _class].filter(Boolean).join(' ')}
|
|
9
|
+
role="separator"
|
|
10
|
+
{...rest}
|
|
11
|
+
></div>
|
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
events: {
|
|
8
|
-
[evt: string]: CustomEvent<any>;
|
|
9
|
-
};
|
|
10
|
-
slots: {};
|
|
11
|
-
exports?: undefined;
|
|
12
|
-
bindings?: undefined;
|
|
13
|
-
};
|
|
14
|
-
export type MenuSeparatorProps = typeof __propDef.props;
|
|
15
|
-
export type MenuSeparatorEvents = typeof __propDef.events;
|
|
16
|
-
export type MenuSeparatorSlots = typeof __propDef.slots;
|
|
17
|
-
/** A styled line to visually separate groups of menu items in a menu. */
|
|
18
|
-
export default class MenuSeparator extends SvelteComponent<MenuSeparatorProps, MenuSeparatorEvents, MenuSeparatorSlots> {
|
|
19
|
-
}
|
|
20
|
-
export {};
|
|
1
|
+
/// <reference types="svelte" />
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type Props = HTMLAttributes<HTMLDivElement>;
|
|
4
|
+
declare const MenuSeparator: import("svelte").Component<Props, {}, "">;
|
|
5
|
+
type MenuSeparator = ReturnType<typeof MenuSeparator>;
|
|
6
|
+
export default MenuSeparator;
|