@geoffcox/sterling-svelte 0.0.31 → 1.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/@types/clickOutside.d.ts +11 -7
- package/Button.svelte +11 -183
- package/Button.svelte.d.ts +2 -6
- package/Callout.svelte +107 -146
- package/Callout.svelte.d.ts +1 -1
- package/Checkbox.svelte +15 -177
- package/Checkbox.svelte.d.ts +2 -2
- package/ColorPicker.svelte +204 -223
- package/ColorPicker.svelte.d.ts +1 -2
- package/Dialog.svelte +90 -187
- package/Dialog.svelte.d.ts +2 -1
- package/Dropdown.svelte +52 -220
- package/Dropdown.svelte.d.ts +4 -8
- package/HexColorSliders.svelte +77 -145
- package/HexColorSliders.svelte.d.ts +28 -1
- package/HslColorSliders.svelte +99 -179
- package/HslColorSliders.svelte.d.ts +28 -1
- package/Input.svelte +27 -136
- package/Input.svelte.d.ts +2 -3
- package/Label.constants.d.ts +1 -0
- package/Label.constants.js +1 -0
- package/Label.svelte +96 -169
- package/Label.svelte.d.ts +6 -1
- package/Label.types.d.ts +3 -1
- package/Link.svelte +9 -106
- package/Link.svelte.d.ts +0 -1
- package/List.svelte +142 -230
- package/List.svelte.d.ts +2 -3
- package/List.types.d.ts +6 -1
- package/ListItem.svelte +25 -94
- package/ListItem.svelte.d.ts +2 -0
- package/Menu.svelte +48 -65
- package/Menu.svelte.d.ts +4 -1
- package/MenuBar.svelte +84 -86
- package/MenuBar.svelte.d.ts +4 -1
- package/MenuButton.svelte +66 -73
- package/MenuButton.svelte.d.ts +7 -3
- package/MenuItem.svelte +256 -288
- package/MenuItem.svelte.d.ts +2 -2
- package/MenuItemDisplay.svelte +12 -116
- package/MenuItemDisplay.svelte.d.ts +21 -7
- package/MenuSeparator.svelte +6 -45
- package/MenuSeparator.svelte.d.ts +8 -78
- package/Popover.constants.d.ts +1 -1
- package/Popover.constants.js +1 -1
- package/Popover.svelte +66 -80
- package/Popover.svelte.d.ts +5 -1
- package/Progress.svelte +28 -126
- package/Progress.svelte.d.ts +4 -3
- package/Radio.svelte +49 -192
- package/Radio.svelte.d.ts +2 -2
- package/RgbColorSliders.svelte +48 -137
- package/RgbColorSliders.svelte.d.ts +5 -5
- package/Select.svelte +122 -250
- package/Select.svelte.d.ts +6 -2
- package/Slider.svelte +90 -259
- package/Slider.svelte.d.ts +1 -2
- package/Switch.svelte +24 -259
- package/Switch.svelte.d.ts +3 -1
- package/Tab.svelte +27 -175
- package/Tab.svelte.d.ts +6 -4
- package/TabList.svelte +146 -171
- package/TabList.svelte.d.ts +3 -2
- package/TabList.types.d.ts +6 -1
- package/TextArea.svelte +32 -129
- package/TextArea.svelte.d.ts +1 -1
- package/Tooltip.svelte +46 -47
- package/Tooltip.svelte.d.ts +8 -3
- package/Tree.constants.d.ts +0 -1
- package/Tree.constants.js +0 -1
- package/Tree.svelte +35 -119
- package/Tree.svelte.d.ts +4 -4
- package/Tree.types.d.ts +1 -3
- package/TreeChevron.svelte +18 -98
- package/TreeChevron.svelte.d.ts +1 -0
- package/TreeItem.constants.d.ts +1 -0
- package/TreeItem.constants.js +1 -0
- package/TreeItem.svelte +251 -211
- package/TreeItem.svelte.d.ts +7 -3
- package/TreeItem.types.d.ts +1 -1
- package/TreeItemDisplay.svelte +20 -104
- package/TreeItemDisplay.svelte.d.ts +2 -2
- package/actions/applyLightDarkMode.d.ts +10 -0
- package/actions/applyLightDarkMode.js +36 -0
- package/actions/forwardEvents.js +3 -3
- package/css/Button.base.css +74 -0
- package/css/Button.colorful.css +17 -0
- package/css/Button.css +7 -0
- package/css/Button.secondary.colorful.css +15 -0
- package/css/Button.secondary.css +11 -0
- package/css/Button.shapes.css +14 -0
- package/css/Button.tool.colorful.css +13 -0
- package/css/Button.tool.css +18 -0
- package/css/Callout.base.css +43 -0
- package/css/Callout.colorful.css +5 -0
- package/css/Callout.css +2 -0
- package/css/Checkbox.base.css +145 -0
- package/css/Checkbox.colorful.css +17 -0
- package/css/Checkbox.css +2 -0
- package/css/ColorPicker.base.css +23 -0
- package/css/ColorPicker.css +1 -0
- package/css/Dialog.base.css +116 -0
- package/css/Dialog.css +1 -0
- package/css/Dropdown.base.css +147 -0
- package/css/Dropdown.colorful.css +23 -0
- package/css/Dropdown.css +2 -0
- package/css/HexColorSliders.base.css +106 -0
- package/css/HexColorSliders.css +1 -0
- package/css/HslColorSliders.base.css +124 -0
- package/css/HslColorSliders.css +1 -0
- package/css/Input.base.css +100 -0
- package/css/Input.colorful.css +22 -0
- package/css/Input.composed.css +8 -0
- package/css/Input.css +3 -0
- package/css/Label.base.css +119 -0
- package/css/Label.boxed.colorful.css +21 -0
- package/css/Label.boxed.css +31 -0
- package/css/Label.colorful.css +3 -0
- package/css/Label.css +4 -0
- package/css/Link.base.css +52 -0
- package/css/Link.colorful.css +15 -0
- package/css/Link.css +6 -0
- package/css/Link.ghost.colorful.css +7 -0
- package/css/Link.ghost.css +11 -0
- package/css/Link.undecorated.colorful.css +6 -0
- package/css/Link.undecorated.css +6 -0
- package/css/List.base.css +98 -0
- package/css/List.css +1 -0
- package/css/ListItem.base.css +59 -0
- package/css/ListItem.css +1 -0
- package/css/Menu.base.css +21 -0
- package/css/Menu.css +1 -0
- package/css/MenuBar.base.css +9 -0
- package/css/MenuBar.css +1 -0
- package/css/MenuButton.base.css +13 -0
- package/css/MenuButton.css +1 -0
- package/css/MenuItem.base.css +48 -0
- package/css/MenuItem.css +1 -0
- package/css/MenuItemDisplay.base.css +104 -0
- package/css/MenuItemDisplay.css +1 -0
- package/css/MenuSeparator.base.css +5 -0
- package/css/MenuSeparator.css +1 -0
- package/css/Popover copy.css +21 -0
- package/css/Popover.css +21 -0
- package/css/Progress.base.css +99 -0
- package/css/Progress.css +1 -0
- package/css/Radio.base.css +135 -0
- package/css/Radio.colorful.css +18 -0
- package/css/Radio.css +2 -0
- package/css/RgbColorSliders.base.css +94 -0
- package/css/RgbColorSliders.css +1 -0
- package/css/Select.base.css +127 -0
- package/css/Select.colorful.css +24 -0
- package/css/Select.composed.css +12 -0
- package/css/Select.css +3 -0
- package/css/Slider.base.css +182 -0
- package/css/Slider.colorful.css +11 -0
- package/css/Slider.composed.css +8 -0
- package/css/Slider.css +3 -0
- package/css/Switch.base.css +193 -0
- package/css/Switch.colorful.css +39 -0
- package/css/Switch.css +2 -0
- package/css/Tab.base.css +135 -0
- package/css/Tab.colorful.css +13 -0
- package/css/Tab.css +2 -0
- package/css/TabList.base.css +34 -0
- package/css/TabList.css +1 -0
- package/css/TextArea.base.css +85 -0
- package/css/TextArea.colorful.css +17 -0
- package/css/TextArea.composed.css +8 -0
- package/css/TextArea.css +3 -0
- package/css/Tooltip.base.css +6 -0
- package/css/Tooltip.css +1 -0
- package/css/Tree.base.css +74 -0
- package/css/Tree.composed.css +8 -0
- package/css/Tree.css +2 -0
- package/css/TreeChevron.base.css +86 -0
- package/css/TreeChevron.css +1 -0
- package/css/TreeItem.base.css +3 -0
- package/css/TreeItem.css +1 -0
- package/css/TreeItemDisplay.base.css +74 -0
- package/css/TreeItemDisplay.colorful.css +9 -0
- package/css/TreeItemDisplay.css +1 -0
- package/css/dark-mode.css +134 -0
- package/css/light-mode.css +134 -0
- package/css/sterling.css +37 -0
- package/index.d.ts +9 -13
- package/index.js +8 -12
- package/mediaQueries/prefersColorSchemeDark.d.ts +2 -0
- package/mediaQueries/prefersColorSchemeDark.js +10 -0
- package/{stores → mediaQueries}/prefersReducedMotion.d.ts +1 -0
- package/{stores → mediaQueries}/usingKeyboard.d.ts +1 -0
- package/package.json +121 -13
- package/Link.constants.d.ts +0 -1
- package/Link.constants.js +0 -1
- package/Link.types.d.ts +0 -4
- package/Link.types.js +0 -1
- package/theme/applyDarkTheme.d.ts +0 -7
- package/theme/applyDarkTheme.js +0 -11
- package/theme/applyLightTheme.d.ts +0 -7
- package/theme/applyLightTheme.js +0 -11
- package/theme/applyTheme.d.ts +0 -7
- package/theme/applyTheme.js +0 -20
- package/theme/colors.d.ts +0 -54
- package/theme/colors.js +0 -82
- package/theme/darkTheme.d.ts +0 -2
- package/theme/darkTheme.js +0 -142
- package/theme/lightTheme.d.ts +0 -2
- package/theme/lightTheme.js +0 -119
- package/theme/toggleDarkTheme.d.ts +0 -18
- package/theme/toggleDarkTheme.js +0 -53
- package/theme/types.d.ts +0 -21
- package/theme/types.js +0 -1
- /package/{stores → mediaQueries}/prefersReducedMotion.js +0 -0
- /package/{stores → mediaQueries}/usingKeyboard.js +0 -0
package/MenuItem.svelte
CHANGED
|
@@ -1,253 +1,297 @@
|
|
|
1
|
-
<script>import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import Popover from "./Popover.svelte";
|
|
17
|
-
import { usingKeyboard } from "./stores/usingKeyboard";
|
|
1
|
+
<script>import { getContext, afterUpdate, createEventDispatcher, onMount, setContext, tick } from 'svelte';
|
|
2
|
+
import { writable } from 'svelte/store';
|
|
3
|
+
import { idGenerator } from './idGenerator';
|
|
4
|
+
import Menu from './Menu.svelte';
|
|
5
|
+
import { MENU_BAR_CONTEXT_KEY } from './MenuBar.constants';
|
|
6
|
+
import { MENU_ITEM_CONTEXT_KEY } from './MenuItem.constants';
|
|
7
|
+
import { isElementEnabledMenuItem } from './MenuItem.utils';
|
|
8
|
+
import MenuItemDisplay from './MenuItemDisplay.svelte';
|
|
9
|
+
import Popover from './Popover.svelte';
|
|
10
|
+
import { usingKeyboard } from './mediaQueries/usingKeyboard';
|
|
11
|
+
// ----- Props ----- //
|
|
12
|
+
/**
|
|
13
|
+
* When true, the menu item is checked.
|
|
14
|
+
* Use with role='menuitemcheckbox' or role='menuitemradio'.
|
|
15
|
+
*/
|
|
18
16
|
export let checked = false;
|
|
19
|
-
|
|
20
|
-
export let composed = false;
|
|
17
|
+
/** When true, the menu item is disabled. */
|
|
21
18
|
export let disabled = false;
|
|
22
|
-
|
|
23
|
-
export let
|
|
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
24
|
export let value;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const { openPreviousMenuBarItem = void 0, openNextMenuBarItem = void 0 } = getContext(MENU_BAR_CONTEXT_KEY) || {};
|
|
36
|
-
const instanceId = idGenerator.nextId("MenuItem");
|
|
37
|
-
$:
|
|
38
|
-
displayId = `${value}-display-${instanceId}`;
|
|
39
|
-
$:
|
|
40
|
-
open = $openValues.includes(value);
|
|
41
|
-
$:
|
|
42
|
-
menuId = `${value}-menu-${instanceId}`;
|
|
25
|
+
/** Additional class names to apply. */
|
|
26
|
+
export let variant = '';
|
|
27
|
+
// ----- Get Context ----- //
|
|
28
|
+
const { isMenuBarItem, openValues = writable([]), rootValue = value, depth = 0, closeContainingMenu = undefined, onOpen = undefined, onClose = undefined, onSelect = undefined } = getContext(MENU_ITEM_CONTEXT_KEY) || {};
|
|
29
|
+
const { openPreviousMenuBarItem = undefined, openNextMenuBarItem = undefined } = getContext(MENU_BAR_CONTEXT_KEY) || {};
|
|
30
|
+
// ----- State ----- //
|
|
31
|
+
const instanceId = idGenerator.nextId('MenuItem');
|
|
32
|
+
$: displayId = `${value}-display-${instanceId}`;
|
|
33
|
+
$: open = $openValues.includes(value);
|
|
34
|
+
$: menuId = `${value}-menu-${instanceId}`;
|
|
43
35
|
let menuItemRef;
|
|
44
36
|
let menuRef;
|
|
45
37
|
const children = writable([]);
|
|
46
38
|
let mounted = false;
|
|
47
39
|
let prevOpen = open;
|
|
48
|
-
$:
|
|
49
|
-
|
|
40
|
+
$: hasChildren = $$slots.default;
|
|
41
|
+
// ----- Methods ----- //
|
|
50
42
|
export const blur = () => {
|
|
51
|
-
|
|
43
|
+
menuItemRef?.blur();
|
|
52
44
|
};
|
|
53
45
|
export const click = () => {
|
|
54
|
-
|
|
46
|
+
menuItemRef?.click();
|
|
55
47
|
};
|
|
56
48
|
export const focus = (options) => {
|
|
57
|
-
|
|
49
|
+
menuItemRef?.focus(options);
|
|
58
50
|
};
|
|
51
|
+
// ----- Events ----- //
|
|
59
52
|
const dispatch = createEventDispatcher();
|
|
60
|
-
const raiseClose = (
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
const raiseClose = (value) => {
|
|
54
|
+
dispatch('close', { value });
|
|
55
|
+
onClose?.(value);
|
|
63
56
|
};
|
|
64
|
-
const raiseOpen = (
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
const raiseOpen = (value) => {
|
|
58
|
+
dispatch('open', { value });
|
|
59
|
+
onOpen?.(value);
|
|
67
60
|
};
|
|
68
61
|
$: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
if (hasChildren && open !== prevOpen) {
|
|
63
|
+
open ? raiseOpen(value) : raiseClose(value);
|
|
64
|
+
}
|
|
65
|
+
prevOpen = open;
|
|
73
66
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
// dispatches the event and bubbles it up the context
|
|
68
|
+
// so that container components can subscribe to select
|
|
69
|
+
// events for children.
|
|
70
|
+
const raiseSelect = (value) => {
|
|
71
|
+
dispatch('select', { value });
|
|
72
|
+
onSelect?.(value);
|
|
77
73
|
};
|
|
74
|
+
// ----- Focus ----- //
|
|
78
75
|
const focusPreviousMenuItem = () => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
let candidate = menuItemRef?.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
77
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
78
|
+
candidate = candidate.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
79
|
+
if (candidate === menuItemRef) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
84
82
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return !!candidate;
|
|
83
|
+
candidate?.focus();
|
|
84
|
+
return !!candidate;
|
|
88
85
|
};
|
|
89
86
|
const focusNextMenuItem = () => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
let candidate = menuItemRef?.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
|
|
88
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
89
|
+
candidate = candidate.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
|
|
90
|
+
if (candidate === menuItemRef) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
95
93
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return !!candidate;
|
|
94
|
+
candidate?.focus();
|
|
95
|
+
return !!candidate;
|
|
99
96
|
};
|
|
97
|
+
// ----- Open/Close ----- //
|
|
98
|
+
// opens the menu for this menu item
|
|
100
99
|
const openMenu = () => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
if (!$openValues.includes(value)) {
|
|
101
|
+
// slice to depth to close any sibling menus that are open
|
|
102
|
+
openValues.set([...$openValues.slice(0, depth), value]);
|
|
103
|
+
}
|
|
104
104
|
};
|
|
105
|
+
// closes the menu for this menu item
|
|
105
106
|
const closeMenu = async () => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
const index = $openValues.indexOf(value);
|
|
108
|
+
if (index !== -1) {
|
|
109
|
+
openValues.set([...$openValues.slice(0, index)]);
|
|
110
|
+
await tick();
|
|
111
|
+
menuItemRef?.focus();
|
|
112
|
+
}
|
|
112
113
|
};
|
|
113
114
|
const closeAllMenus = () => {
|
|
114
|
-
|
|
115
|
+
openValues.set([]);
|
|
115
116
|
};
|
|
117
|
+
// ----- Event Handlers ----- //
|
|
116
118
|
onMount(() => {
|
|
117
|
-
|
|
119
|
+
mounted = true;
|
|
118
120
|
});
|
|
119
121
|
afterUpdate(() => {
|
|
120
|
-
|
|
122
|
+
prevOpen = open;
|
|
121
123
|
});
|
|
122
124
|
const onKeyDown = async (event) => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
125
|
+
if (!disabled && !event.altKey && !event.ctrlKey && !event.shiftKey) {
|
|
126
|
+
switch (event.key) {
|
|
127
|
+
case 'ArrowDown':
|
|
128
|
+
// ARIA menubar/menuitem:
|
|
129
|
+
// If the currently focused menuitem has a submenu,
|
|
130
|
+
// opens the submenu and places focus on the first item in the submenu.
|
|
131
|
+
if (isMenuBarItem && hasChildren) {
|
|
132
|
+
openMenu();
|
|
133
|
+
setTimeout(async () => {
|
|
134
|
+
await tick();
|
|
135
|
+
menuRef?.focusFirstMenuItem();
|
|
136
|
+
}, 10);
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
event.stopPropagation();
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
if (!isMenuBarItem) {
|
|
142
|
+
// ARIA menuitem:
|
|
143
|
+
// Moves focus to the next item, optionally wrapping from the last to the first.
|
|
144
|
+
focusNextMenuItem();
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
event.stopPropagation();
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case 'ArrowLeft':
|
|
151
|
+
// ARIA menubar/menuitem:
|
|
152
|
+
// Moves focus to the previous item, optionally wrapping from the first to the last.
|
|
153
|
+
if (isMenuBarItem) {
|
|
154
|
+
focusPreviousMenuItem();
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
event.stopPropagation();
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
// ARIA menuitem:
|
|
160
|
+
// When focus is in a submenu of an item in a menu,
|
|
161
|
+
// closes the submenu and returns focus to the parent menuitem.
|
|
162
|
+
if (depth > 1) {
|
|
163
|
+
closeContainingMenu?.();
|
|
164
|
+
event.preventDefault();
|
|
165
|
+
event.stopPropagation();
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
// ARIA menubar/menuitem:
|
|
169
|
+
// When focus is in a submenu of an item in a menubar,
|
|
170
|
+
// closes the submenu,
|
|
171
|
+
// moves focus to the previous item in the menubar,
|
|
172
|
+
// and,
|
|
173
|
+
// if focus is now on a menuitem with a submenu,
|
|
174
|
+
// either opens the submenu of that menuitem without moving focus into the submenu,
|
|
175
|
+
// or opens the submenu of that menuitem and places focus on the first item in the submenu.
|
|
176
|
+
openPreviousMenuBarItem?.();
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
event.stopPropagation();
|
|
179
|
+
return false;
|
|
180
|
+
case 'ArrowRight':
|
|
181
|
+
// ARIA menubar:
|
|
182
|
+
// Moves focus to the next item, optionally wrapping from the last to the first.
|
|
183
|
+
if (isMenuBarItem) {
|
|
184
|
+
focusNextMenuItem();
|
|
185
|
+
event.preventDefault();
|
|
186
|
+
event.stopPropagation();
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
// ARIA menuitem:
|
|
190
|
+
// When focus is in a menu and on a menuitem that has a submenu,
|
|
191
|
+
// opens the submenu and places focus on its first item
|
|
192
|
+
if (hasChildren) {
|
|
193
|
+
openMenu();
|
|
194
|
+
setTimeout(async () => {
|
|
195
|
+
await tick();
|
|
196
|
+
menuRef?.focusFirstMenuItem();
|
|
197
|
+
}, 10);
|
|
198
|
+
event.preventDefault();
|
|
199
|
+
event.stopPropagation();
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
// ARIA menubar/menuitem:
|
|
203
|
+
// When focus is in a menu and on an item that does not have a submenu,
|
|
204
|
+
// closes the submenu and any parent menus,
|
|
205
|
+
// moves focus to the next item in the menubar,
|
|
206
|
+
// and,
|
|
207
|
+
// if focus is now on a menuitem with a submenu,
|
|
208
|
+
// either opens the submenu of that menuitem without moving focus into the submenu,
|
|
209
|
+
// or opens the submenu of that menuitem and places focus on the first item in the submenu.
|
|
210
|
+
if (openNextMenuBarItem) {
|
|
211
|
+
openNextMenuBarItem();
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
event.stopPropagation();
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
case 'ArrowUp':
|
|
218
|
+
// ARIA menubar/menuitem:
|
|
219
|
+
// If the currently focused menuitem has a submenu,
|
|
220
|
+
// opens the submenu and places focus on the last item in the submenu.
|
|
221
|
+
if (isMenuBarItem && hasChildren) {
|
|
222
|
+
openMenu();
|
|
223
|
+
setTimeout(async () => {
|
|
224
|
+
await tick();
|
|
225
|
+
menuRef?.focusLastMenuItem();
|
|
226
|
+
}, 10);
|
|
227
|
+
event.preventDefault();
|
|
228
|
+
event.stopPropagation();
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
// ARIA menuitem:
|
|
232
|
+
// Moves focus to the previous item, optionally wrapping from the first to the last.
|
|
233
|
+
if (!isMenuBarItem) {
|
|
234
|
+
focusPreviousMenuItem();
|
|
235
|
+
event.preventDefault();
|
|
236
|
+
event.stopPropagation();
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
case 'Escape':
|
|
241
|
+
// ARIA menuitem:
|
|
242
|
+
// Close the menu that contains focus and return focus to the element or context,
|
|
243
|
+
// e.g., menu button or parent menuitem, from which the menu was opened.
|
|
244
|
+
open = false;
|
|
245
|
+
closeAllMenus();
|
|
246
|
+
event.preventDefault();
|
|
247
|
+
event.stopPropagation();
|
|
248
|
+
return false;
|
|
155
249
|
}
|
|
156
|
-
openPreviousMenuBarItem?.();
|
|
157
|
-
event.preventDefault();
|
|
158
|
-
event.stopPropagation();
|
|
159
|
-
return false;
|
|
160
|
-
case "ArrowRight":
|
|
161
|
-
if (isMenuBarItem) {
|
|
162
|
-
focusNextMenuItem();
|
|
163
|
-
event.preventDefault();
|
|
164
|
-
event.stopPropagation();
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
if (hasChildren) {
|
|
168
|
-
openMenu();
|
|
169
|
-
setTimeout(async () => {
|
|
170
|
-
await tick();
|
|
171
|
-
menuRef?.focusFirstMenuItem();
|
|
172
|
-
}, 10);
|
|
173
|
-
event.preventDefault();
|
|
174
|
-
event.stopPropagation();
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
if (openNextMenuBarItem) {
|
|
178
|
-
openNextMenuBarItem();
|
|
179
|
-
event.preventDefault();
|
|
180
|
-
event.stopPropagation();
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
break;
|
|
184
|
-
case "ArrowUp":
|
|
185
|
-
if (isMenuBarItem && hasChildren) {
|
|
186
|
-
openMenu();
|
|
187
|
-
setTimeout(async () => {
|
|
188
|
-
await tick();
|
|
189
|
-
menuRef?.focusLastMenuItem();
|
|
190
|
-
}, 10);
|
|
191
|
-
event.preventDefault();
|
|
192
|
-
event.stopPropagation();
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
if (!isMenuBarItem) {
|
|
196
|
-
focusPreviousMenuItem();
|
|
197
|
-
event.preventDefault();
|
|
198
|
-
event.stopPropagation();
|
|
199
|
-
return false;
|
|
200
|
-
}
|
|
201
|
-
break;
|
|
202
|
-
case "Escape":
|
|
203
|
-
open = false;
|
|
204
|
-
closeAllMenus();
|
|
205
|
-
event.preventDefault();
|
|
206
|
-
event.stopPropagation();
|
|
207
|
-
return false;
|
|
208
250
|
}
|
|
209
|
-
}
|
|
210
251
|
};
|
|
211
252
|
const onMouseEnter = (event) => {
|
|
212
|
-
|
|
253
|
+
menuItemRef?.focus();
|
|
213
254
|
};
|
|
214
255
|
const onClick = (event) => {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
256
|
+
if (!disabled) {
|
|
257
|
+
if (hasChildren) {
|
|
258
|
+
if (!$openValues.includes(value)) {
|
|
259
|
+
openMenu();
|
|
260
|
+
if ($usingKeyboard) {
|
|
261
|
+
setTimeout(async () => {
|
|
262
|
+
await tick();
|
|
263
|
+
menuRef?.focusFirstMenuItem();
|
|
264
|
+
}, 10);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
closeMenu();
|
|
269
|
+
}
|
|
270
|
+
event.preventDefault();
|
|
271
|
+
event.stopPropagation();
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
raiseSelect(value);
|
|
276
|
+
closeAllMenus();
|
|
277
|
+
event.preventDefault();
|
|
278
|
+
event.stopPropagation();
|
|
279
|
+
return false;
|
|
224
280
|
}
|
|
225
|
-
} else {
|
|
226
|
-
closeMenu();
|
|
227
|
-
}
|
|
228
|
-
event.preventDefault();
|
|
229
|
-
event.stopPropagation();
|
|
230
|
-
return false;
|
|
231
|
-
} else {
|
|
232
|
-
raiseSelect(value);
|
|
233
|
-
closeAllMenus();
|
|
234
|
-
event.preventDefault();
|
|
235
|
-
event.stopPropagation();
|
|
236
|
-
return false;
|
|
237
281
|
}
|
|
238
|
-
}
|
|
239
282
|
};
|
|
283
|
+
// ----- Set Context ----- //
|
|
240
284
|
setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
285
|
+
isMenuBarItem: false,
|
|
286
|
+
openValues,
|
|
287
|
+
rootValue,
|
|
288
|
+
depth: depth + 1,
|
|
289
|
+
closeContainingMenu: () => {
|
|
290
|
+
closeMenu();
|
|
291
|
+
},
|
|
292
|
+
onOpen: raiseOpen,
|
|
293
|
+
onClose: raiseClose,
|
|
294
|
+
onSelect: raiseSelect
|
|
251
295
|
});
|
|
252
296
|
</script>
|
|
253
297
|
|
|
@@ -258,9 +302,7 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
|
258
302
|
aria-haspopup={hasChildren}
|
|
259
303
|
aria-owns={menuId}
|
|
260
304
|
bind:this={menuItemRef}
|
|
261
|
-
class=
|
|
262
|
-
class:colorful
|
|
263
|
-
class:composed
|
|
305
|
+
class={`sterling-menu-item ${variant}`}
|
|
264
306
|
class:using-keyboard={usingKeyboard}
|
|
265
307
|
data-value={value}
|
|
266
308
|
data-root-value={rootValue}
|
|
@@ -316,9 +358,15 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
|
316
358
|
{role}
|
|
317
359
|
{text}
|
|
318
360
|
{value}
|
|
361
|
+
{variant}
|
|
319
362
|
>
|
|
320
|
-
<MenuItemDisplay
|
|
321
|
-
|
|
363
|
+
<MenuItemDisplay
|
|
364
|
+
{checked}
|
|
365
|
+
{disabled}
|
|
366
|
+
{hasChildren}
|
|
367
|
+
{isMenuBarItem}
|
|
368
|
+
menuItemRole={role}
|
|
369
|
+
{variant}>{text}</MenuItemDisplay
|
|
322
370
|
>
|
|
323
371
|
</slot>
|
|
324
372
|
</div>
|
|
@@ -334,83 +382,3 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
|
334
382
|
</Popover>
|
|
335
383
|
{/if}
|
|
336
384
|
</button>
|
|
337
|
-
|
|
338
|
-
<style>
|
|
339
|
-
.sterling-menu-item {
|
|
340
|
-
background-color: transparent;
|
|
341
|
-
border-color: transparent;
|
|
342
|
-
border-radius: var(--stsv-button__border-radius);
|
|
343
|
-
border-style: none;
|
|
344
|
-
border-width: 0;
|
|
345
|
-
box-sizing: border-box;
|
|
346
|
-
color: var(--stsv-common__color);
|
|
347
|
-
cursor: pointer;
|
|
348
|
-
font: inherit;
|
|
349
|
-
margin: 0;
|
|
350
|
-
padding: 0;
|
|
351
|
-
position: relative;
|
|
352
|
-
outline: none;
|
|
353
|
-
overflow: hidden;
|
|
354
|
-
text-decoration: none;
|
|
355
|
-
text-overflow: ellipsis;
|
|
356
|
-
transition: background-color 250ms, color 250ms, border-color 250ms;
|
|
357
|
-
white-space: nowrap;
|
|
358
|
-
user-select: none;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
.sterling-menu-item:hover {
|
|
362
|
-
background-color: var(--stsv-button__background-color--hover);
|
|
363
|
-
color: var(--stsv-button__color--hover);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
.sterling-menu-item:focus {
|
|
367
|
-
outline: none;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
.sterling-menu-item.using-keyboard:focus {
|
|
371
|
-
border-color: var(--stsv-button__border-color--focus);
|
|
372
|
-
outline-color: var(--stsv-common__outline-color);
|
|
373
|
-
outline-offset: var(--stsv-common__outline-offset);
|
|
374
|
-
outline-style: var(--stsv-common__outline-style);
|
|
375
|
-
outline-width: var(--stsv-common__outline-width);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
.sterling-menu-item:focus {
|
|
379
|
-
background-color: var(--stsv-input__background-color--selected);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/** ----- colorful ----- */
|
|
383
|
-
|
|
384
|
-
.sterling-menu-item.colorful {
|
|
385
|
-
color: var(--stsv-common--colorful__color);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
.sterling-menu-item.colorful:hover {
|
|
389
|
-
background-color: var(--stsv-button--colorful__background-color--hover);
|
|
390
|
-
color: var(--stsv-button--colorful__color--hover);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
.sterling-menu-item.colorful.using-keyboard:focus {
|
|
394
|
-
border-color: var(--stsv-button--colorful__border-color--focus);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
.sterling-menu-item.colorful:focus {
|
|
398
|
-
background-color: var(--stsv-button--colorful__background-color--focus);
|
|
399
|
-
color: var(--stsv-button--colorful__color--focus);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
.sterling-menu-item.composed,
|
|
403
|
-
.sterling-menu-item.composed:focus,
|
|
404
|
-
.sterling-menu-item.composed:hover {
|
|
405
|
-
border-width: 0;
|
|
406
|
-
border-color: transparent;
|
|
407
|
-
outline: none;
|
|
408
|
-
background-color: transparent;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
@media (prefers-reduced-motion) {
|
|
412
|
-
.sterling-menu-item {
|
|
413
|
-
transition: none;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
</style>
|
package/MenuItem.svelte.d.ts
CHANGED
|
@@ -3,12 +3,11 @@ declare const __propDef: {
|
|
|
3
3
|
props: {
|
|
4
4
|
[x: string]: any;
|
|
5
5
|
checked?: boolean | undefined;
|
|
6
|
-
colorful?: boolean | undefined;
|
|
7
|
-
composed?: boolean | undefined;
|
|
8
6
|
disabled?: boolean | undefined;
|
|
9
7
|
role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
|
|
10
8
|
text?: string | undefined;
|
|
11
9
|
value: string;
|
|
10
|
+
variant?: string | undefined;
|
|
12
11
|
blur?: (() => void) | undefined;
|
|
13
12
|
click?: (() => void) | undefined;
|
|
14
13
|
focus?: ((options?: FocusOptions) => void) | undefined;
|
|
@@ -62,6 +61,7 @@ declare const __propDef: {
|
|
|
62
61
|
role: "menuitem" | "menuitemcheckbox" | "menuitemradio";
|
|
63
62
|
text: string | undefined;
|
|
64
63
|
value: string;
|
|
64
|
+
variant: string;
|
|
65
65
|
};
|
|
66
66
|
default: {
|
|
67
67
|
depth: number;
|