@geoffcox/sterling-svelte 2.0.0 → 2.0.2
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/package.json +21 -23
- package/.DS_Store +0 -0
- package/@types/clickOutside.d.ts +0 -15
- package/Button.svelte +0 -25
- package/Button.svelte.d.ts +0 -9
- package/Callout.svelte +0 -177
- package/Callout.svelte.d.ts +0 -15
- package/Callout.types.d.ts +0 -11
- package/Callout.types.js +0 -1
- package/Checkbox.svelte +0 -43
- package/Checkbox.svelte.d.ts +0 -10
- package/Dialog.svelte +0 -151
- package/Dialog.svelte.d.ts +0 -14
- package/Dropdown.svelte +0 -109
- package/Dropdown.svelte.d.ts +0 -18
- package/Input.svelte +0 -55
- package/Input.svelte.d.ts +0 -12
- package/Label.constants.d.ts +0 -2
- package/Label.constants.js +0 -2
- package/Label.svelte +0 -91
- package/Label.svelte.d.ts +0 -17
- package/Link.svelte +0 -25
- package/Link.svelte.d.ts +0 -12
- package/List.constants.d.ts +0 -1
- package/List.constants.js +0 -1
- package/List.svelte +0 -203
- package/List.svelte.d.ts +0 -20
- package/List.types.d.ts +0 -5
- package/List.types.js +0 -1
- package/ListItem.svelte +0 -49
- package/ListItem.svelte.d.ts +0 -13
- package/Menu.svelte +0 -83
- package/Menu.svelte.d.ts +0 -13
- package/MenuBar.constants.d.ts +0 -1
- package/MenuBar.constants.js +0 -1
- package/MenuBar.svelte +0 -113
- package/MenuBar.svelte.d.ts +0 -13
- package/MenuBar.types.d.ts +0 -4
- package/MenuBar.types.js +0 -1
- package/MenuButton.svelte +0 -116
- package/MenuButton.svelte.d.ts +0 -20
- package/MenuItem.constants.d.ts +0 -2
- package/MenuItem.constants.js +0 -2
- package/MenuItem.svelte +0 -342
- package/MenuItem.svelte.d.ts +0 -22
- package/MenuItem.types.d.ts +0 -20
- package/MenuItem.types.js +0 -1
- package/MenuItem.utils.d.ts +0 -7
- package/MenuItem.utils.js +0 -36
- package/MenuSeparator.svelte +0 -11
- package/MenuSeparator.svelte.d.ts +0 -6
- package/Popover.constants.d.ts +0 -1
- package/Popover.constants.js +0 -14
- package/Popover.svelte +0 -121
- package/Popover.svelte.d.ts +0 -15
- package/Popover.types.d.ts +0 -4
- package/Popover.types.js +0 -1
- package/Portal.constants.d.ts +0 -2
- package/Portal.constants.js +0 -2
- package/Portal.types.d.ts +0 -6
- package/Portal.types.js +0 -1
- package/Progress.constants.d.ts +0 -1
- package/Progress.constants.js +0 -1
- package/Progress.svelte +0 -36
- package/Progress.svelte.d.ts +0 -12
- package/Progress.types.d.ts +0 -4
- package/Progress.types.js +0 -1
- package/Radio.svelte +0 -53
- package/Radio.svelte.d.ts +0 -13
- package/Select.svelte +0 -196
- package/Select.svelte.d.ts +0 -20
- package/Slider.svelte +0 -133
- package/Slider.svelte.d.ts +0 -19
- package/Switch.svelte +0 -61
- package/Switch.svelte.d.ts +0 -21
- package/Tab.svelte +0 -51
- package/Tab.svelte.d.ts +0 -12
- package/TabList.constants.d.ts +0 -1
- package/TabList.constants.js +0 -1
- package/TabList.svelte +0 -202
- package/TabList.svelte.d.ts +0 -18
- package/TabList.types.d.ts +0 -5
- package/TabList.types.js +0 -1
- package/TextArea.constants.d.ts +0 -1
- package/TextArea.constants.js +0 -1
- package/TextArea.svelte +0 -74
- package/TextArea.svelte.d.ts +0 -19
- package/TextArea.types.d.ts +0 -4
- package/TextArea.types.js +0 -1
- package/Tooltip.svelte +0 -63
- package/Tooltip.svelte.d.ts +0 -10
- package/Tree.constants.d.ts +0 -1
- package/Tree.constants.js +0 -1
- package/Tree.svelte +0 -53
- package/Tree.svelte.d.ts +0 -15
- package/Tree.types.d.ts +0 -5
- package/Tree.types.js +0 -1
- package/TreeChevron.svelte +0 -27
- package/TreeChevron.svelte.d.ts +0 -9
- package/TreeItem.constants.d.ts +0 -1
- package/TreeItem.constants.js +0 -1
- package/TreeItem.svelte +0 -329
- package/TreeItem.svelte.d.ts +0 -22
- package/TreeItem.types.d.ts +0 -4
- package/TreeItem.types.js +0 -1
- package/actions/applyLightDarkMode.d.ts +0 -10
- package/actions/applyLightDarkMode.js +0 -36
- package/actions/clickOutside.d.ts +0 -15
- package/actions/clickOutside.js +0 -28
- package/actions/extraClass.d.ts +0 -8
- package/actions/extraClass.js +0 -14
- package/actions/forwardEvents.d.ts +0 -12
- package/actions/forwardEvents.js +0 -32
- package/actions/portal.d.ts +0 -8
- package/actions/portal.js +0 -19
- package/actions/trapKeyboardFocus.d.ts +0 -3
- package/actions/trapKeyboardFocus.js +0 -52
- package/idGenerator.d.ts +0 -4
- package/idGenerator.js +0 -10
- package/index.d.ts +0 -59
- package/index.js +0 -54
- package/mediaQueries/prefersColorSchemeDark.d.ts +0 -2
- package/mediaQueries/prefersColorSchemeDark.js +0 -14
- package/mediaQueries/prefersReducedMotion.d.ts +0 -2
- package/mediaQueries/prefersReducedMotion.js +0 -14
- package/mediaQueries/usingKeyboard.d.ts +0 -2
- package/mediaQueries/usingKeyboard.js +0 -17
package/MenuBar.svelte
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
<svelte:options runes={true} />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">import { setContext } from 'svelte';
|
|
4
|
-
import { clickOutside } from './actions/clickOutside';
|
|
5
|
-
import { idGenerator } from './idGenerator';
|
|
6
|
-
import { MENU_BAR_CONTEXT_KEY } from './MenuBar.constants';
|
|
7
|
-
import { MENU_ITEM_CONTEXT_KEY } from './MenuItem.constants';
|
|
8
|
-
import { isElementEnabledMenuItem } from './MenuItem.utils';
|
|
9
|
-
let { class: _class, children, onClose, onOpen, onSelect, ...rest } = $props();
|
|
10
|
-
const rootValue = idGenerator.nextId('MenuBar');
|
|
11
|
-
let openValues = $state([]);
|
|
12
|
-
let prevOpenValue = $state();
|
|
13
|
-
let menuBarRef;
|
|
14
|
-
$effect(() => {
|
|
15
|
-
prevOpenValue = openValues[0];
|
|
16
|
-
});
|
|
17
|
-
// Restore focus to the last open menu bar item when it closes
|
|
18
|
-
$effect(() => {
|
|
19
|
-
if (openValues.length === 0 && prevOpenValue !== undefined) {
|
|
20
|
-
const candidate = menuBarRef.querySelector(`[data-value="${prevOpenValue}"]`);
|
|
21
|
-
candidate?.focus();
|
|
22
|
-
prevOpenValue = undefined;
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
export const blur = () => {
|
|
26
|
-
menuBarRef?.blur();
|
|
27
|
-
};
|
|
28
|
-
export const focus = (options) => {
|
|
29
|
-
menuBarRef?.focus(options);
|
|
30
|
-
};
|
|
31
|
-
const getOpenMenuBarItem = () => {
|
|
32
|
-
const value = openValues[0];
|
|
33
|
-
if (value) {
|
|
34
|
-
return menuBarRef.querySelector(`[data-value="${value}"]`);
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
};
|
|
38
|
-
const openPreviousMenuBarItem = () => {
|
|
39
|
-
const openItem = getOpenMenuBarItem() || menuBarRef.firstElementChild;
|
|
40
|
-
let candidate = openItem?.previousElementSibling || menuBarRef.lastElementChild;
|
|
41
|
-
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
42
|
-
candidate = candidate.previousElementSibling || menuBarRef.lastElementChild;
|
|
43
|
-
if (candidate === openItem) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (!candidate) {
|
|
48
|
-
candidate = menuBarRef.lastElementChild;
|
|
49
|
-
candidate = candidate && isElementEnabledMenuItem(candidate) ? candidate : null;
|
|
50
|
-
}
|
|
51
|
-
candidate?.click();
|
|
52
|
-
return !!candidate;
|
|
53
|
-
};
|
|
54
|
-
const openNextMenuBarItem = () => {
|
|
55
|
-
const openItem = getOpenMenuBarItem() || menuBarRef.lastElementChild;
|
|
56
|
-
let candidate = openItem?.nextElementSibling || menuBarRef.firstElementChild;
|
|
57
|
-
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
58
|
-
candidate = candidate.nextElementSibling || menuBarRef.firstElementChild;
|
|
59
|
-
if (candidate === openItem) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (!candidate) {
|
|
64
|
-
candidate = menuBarRef.firstElementChild;
|
|
65
|
-
candidate = candidate && isElementEnabledMenuItem(candidate) ? candidate : null;
|
|
66
|
-
}
|
|
67
|
-
candidate?.click();
|
|
68
|
-
return !!candidate;
|
|
69
|
-
};
|
|
70
|
-
const closeAllMenus = () => {
|
|
71
|
-
openValues = [];
|
|
72
|
-
};
|
|
73
|
-
const onClickOutside = (event) => {
|
|
74
|
-
let element = event.target;
|
|
75
|
-
while (element) {
|
|
76
|
-
if (element.getAttribute('data-root-value') === rootValue) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
element = element.parentElement;
|
|
80
|
-
}
|
|
81
|
-
closeAllMenus?.();
|
|
82
|
-
};
|
|
83
|
-
let menuBarContext = { openPreviousMenuBarItem, openNextMenuBarItem };
|
|
84
|
-
setContext(MENU_BAR_CONTEXT_KEY, menuBarContext);
|
|
85
|
-
let menuItemContext = {
|
|
86
|
-
isMenuBarItem: true,
|
|
87
|
-
depth: 0,
|
|
88
|
-
get openValues() {
|
|
89
|
-
return openValues;
|
|
90
|
-
},
|
|
91
|
-
set openValues(value) {
|
|
92
|
-
openValues = value;
|
|
93
|
-
},
|
|
94
|
-
rootValue,
|
|
95
|
-
onClose,
|
|
96
|
-
onOpen,
|
|
97
|
-
onSelect
|
|
98
|
-
};
|
|
99
|
-
setContext(MENU_ITEM_CONTEXT_KEY, menuItemContext);
|
|
100
|
-
</script>
|
|
101
|
-
|
|
102
|
-
<div
|
|
103
|
-
bind:this={menuBarRef}
|
|
104
|
-
class={['sterling-menu-bar', _class].filter(Boolean).join(' ')}
|
|
105
|
-
role="menubar"
|
|
106
|
-
tabindex="-1"
|
|
107
|
-
{...rest}
|
|
108
|
-
use:clickOutside={{ onclickoutside: onClickOutside }}
|
|
109
|
-
>
|
|
110
|
-
{#if children}
|
|
111
|
-
{@render children()}
|
|
112
|
-
{/if}
|
|
113
|
-
</div>
|
package/MenuBar.svelte.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
-
onClose?: (value: string) => void;
|
|
5
|
-
onOpen?: (value: string) => void;
|
|
6
|
-
onSelect?: (value: string) => void;
|
|
7
|
-
};
|
|
8
|
-
declare const MenuBar: import("svelte").Component<Props, {
|
|
9
|
-
blur: () => void;
|
|
10
|
-
focus: (options?: FocusOptions) => void;
|
|
11
|
-
}, "">;
|
|
12
|
-
type MenuBar = ReturnType<typeof MenuBar>;
|
|
13
|
-
export default MenuBar;
|
package/MenuBar.types.d.ts
DELETED
package/MenuBar.types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/MenuButton.svelte
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
<svelte:options runes={true} />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">import { setContext, tick } from 'svelte';
|
|
4
|
-
import Button from './Button.svelte';
|
|
5
|
-
import Menu from './Menu.svelte';
|
|
6
|
-
import { MENU_ITEM_CONTEXT_KEY } from './MenuItem.constants';
|
|
7
|
-
import { idGenerator } from './idGenerator';
|
|
8
|
-
import Popover from './Popover.svelte';
|
|
9
|
-
import { clickOutside } from './actions/clickOutside';
|
|
10
|
-
let { children, class: _class, items, menuClass, open = $bindable(false), onClose, onOpen, onSelect, popoverPlacement = 'bottom-start', value, ...rest } = $props();
|
|
11
|
-
const instanceId = idGenerator.nextId('MenuButton');
|
|
12
|
-
let buttonRef;
|
|
13
|
-
let openValues = $state([]);
|
|
14
|
-
let menuRef;
|
|
15
|
-
let menuId = $derived(`${value}-menu-${instanceId}`);
|
|
16
|
-
let prevOpen = $state(open);
|
|
17
|
-
let reference = $state();
|
|
18
|
-
export const click = () => {
|
|
19
|
-
buttonRef?.click();
|
|
20
|
-
};
|
|
21
|
-
export const blur = () => {
|
|
22
|
-
buttonRef?.blur();
|
|
23
|
-
};
|
|
24
|
-
export const focus = (options) => {
|
|
25
|
-
buttonRef?.focus(options);
|
|
26
|
-
};
|
|
27
|
-
// update open based on openValues
|
|
28
|
-
$effect(() => {
|
|
29
|
-
open = openValues.length > 0;
|
|
30
|
-
});
|
|
31
|
-
// update openValues based on open
|
|
32
|
-
$effect(() => {
|
|
33
|
-
if (open) {
|
|
34
|
-
openValues = openValues.length > 0 ? openValues : ['menu-button'];
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
openValues = openValues.length === 0 ? openValues : [];
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
// focus when closing
|
|
41
|
-
$effect(() => {
|
|
42
|
-
if (!open && open !== prevOpen) {
|
|
43
|
-
focus();
|
|
44
|
-
}
|
|
45
|
-
prevOpen = open;
|
|
46
|
-
});
|
|
47
|
-
const onClick = async () => {
|
|
48
|
-
if (!open) {
|
|
49
|
-
openValues = ['menu-button'];
|
|
50
|
-
open = true;
|
|
51
|
-
await tick();
|
|
52
|
-
menuRef?.focusFirstMenuItem();
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
open = false;
|
|
56
|
-
openValues = [];
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
const closeAllMenus = () => {
|
|
60
|
-
openValues = [];
|
|
61
|
-
open = false;
|
|
62
|
-
};
|
|
63
|
-
const onClickOutside = (event) => {
|
|
64
|
-
let element = event.target;
|
|
65
|
-
while (element) {
|
|
66
|
-
if (element.getAttribute('data-root-value') === value) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
element = element.parentElement;
|
|
70
|
-
}
|
|
71
|
-
closeAllMenus?.();
|
|
72
|
-
};
|
|
73
|
-
// ----- Context ----- //
|
|
74
|
-
setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
75
|
-
depth: 1,
|
|
76
|
-
get openValues() {
|
|
77
|
-
return openValues;
|
|
78
|
-
},
|
|
79
|
-
set openValues(value) {
|
|
80
|
-
openValues = value;
|
|
81
|
-
},
|
|
82
|
-
rootValue: value,
|
|
83
|
-
closeContainingMenu: () => {
|
|
84
|
-
open = false;
|
|
85
|
-
},
|
|
86
|
-
onOpen,
|
|
87
|
-
onClose,
|
|
88
|
-
onSelect
|
|
89
|
-
});
|
|
90
|
-
</script>
|
|
91
|
-
|
|
92
|
-
<Button
|
|
93
|
-
bind:this={buttonRef}
|
|
94
|
-
aria-controls={menuId}
|
|
95
|
-
aria-expanded={!!open}
|
|
96
|
-
aria-haspopup={!!children}
|
|
97
|
-
aria-owns={menuId}
|
|
98
|
-
class={['sterling-menu-button', _class].filter(Boolean).join(' ')}
|
|
99
|
-
data-value={value}
|
|
100
|
-
data-root-value={value}
|
|
101
|
-
{...rest}
|
|
102
|
-
onclick={onClick}
|
|
103
|
-
>
|
|
104
|
-
<div
|
|
105
|
-
class="reference"
|
|
106
|
-
bind:this={reference}
|
|
107
|
-
use:clickOutside={{ onclickoutside: onClickOutside }}
|
|
108
|
-
>
|
|
109
|
-
{@render children?.()}
|
|
110
|
-
</div>
|
|
111
|
-
<Popover {reference} {open} placement={popoverPlacement}>
|
|
112
|
-
<Menu bind:this={menuRef} id={menuId} class={menuClass}>
|
|
113
|
-
{@render items?.()}
|
|
114
|
-
</Menu>
|
|
115
|
-
</Popover>
|
|
116
|
-
</Button>
|
package/MenuButton.svelte.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
2
|
-
import { type Snippet } from 'svelte';
|
|
3
|
-
import type { PopoverPlacement } from './Popover.types';
|
|
4
|
-
type Props = HTMLButtonAttributes & {
|
|
5
|
-
items: Snippet;
|
|
6
|
-
menuClass?: string;
|
|
7
|
-
onOpen?: (value: string) => void;
|
|
8
|
-
onClose?: (value: string) => void;
|
|
9
|
-
onSelect?: (value: string) => void;
|
|
10
|
-
open?: boolean | null | undefined;
|
|
11
|
-
popoverPlacement?: PopoverPlacement;
|
|
12
|
-
value?: string;
|
|
13
|
-
};
|
|
14
|
-
declare const MenuButton: import("svelte").Component<Props, {
|
|
15
|
-
click: () => void;
|
|
16
|
-
blur: () => void;
|
|
17
|
-
focus: (options?: FocusOptions) => void;
|
|
18
|
-
}, "open">;
|
|
19
|
-
type MenuButton = ReturnType<typeof MenuButton>;
|
|
20
|
-
export default MenuButton;
|
package/MenuItem.constants.d.ts
DELETED
package/MenuItem.constants.js
DELETED
package/MenuItem.svelte
DELETED
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
<svelte:options runes={true} />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">import { getContext, setContext, tick } from 'svelte';
|
|
4
|
-
import { idGenerator } from './idGenerator';
|
|
5
|
-
import Menu from './Menu.svelte';
|
|
6
|
-
import { MENU_BAR_CONTEXT_KEY } from './MenuBar.constants';
|
|
7
|
-
import { MENU_ITEM_CONTEXT_KEY } from './MenuItem.constants';
|
|
8
|
-
import { isElementEnabledMenuItem } from './MenuItem.utils';
|
|
9
|
-
import Popover from './Popover.svelte';
|
|
10
|
-
import { usingKeyboard } from './mediaQueries/usingKeyboard';
|
|
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) || {};
|
|
14
|
-
const instanceId = idGenerator.nextId('MenuItem');
|
|
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
|
|
22
|
-
export const blur = () => {
|
|
23
|
-
menuItemRef?.blur();
|
|
24
|
-
};
|
|
25
|
-
export const click = () => {
|
|
26
|
-
menuItemRef?.click();
|
|
27
|
-
};
|
|
28
|
-
export const focus = (options) => {
|
|
29
|
-
menuItemRef?.focus(options);
|
|
30
|
-
};
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region events
|
|
33
|
-
const raiseClose = (value) => {
|
|
34
|
-
onClose?.(value);
|
|
35
|
-
menuItemContext.onClose?.(value);
|
|
36
|
-
};
|
|
37
|
-
const raiseOpen = (value) => {
|
|
38
|
-
onOpen?.(value);
|
|
39
|
-
menuItemContext.onOpen?.(value);
|
|
40
|
-
};
|
|
41
|
-
const raiseSelect = (value) => {
|
|
42
|
-
onSelect?.(value);
|
|
43
|
-
menuItemContext.onSelect?.(value);
|
|
44
|
-
};
|
|
45
|
-
$effect(() => {
|
|
46
|
-
if (open !== prevOpen) {
|
|
47
|
-
open ? raiseOpen(value) : raiseClose(value);
|
|
48
|
-
}
|
|
49
|
-
prevOpen = open;
|
|
50
|
-
});
|
|
51
|
-
//#endregion
|
|
52
|
-
//#region focus
|
|
53
|
-
const focusPreviousMenuItem = () => {
|
|
54
|
-
let candidate = menuItemRef?.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
55
|
-
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
56
|
-
candidate = candidate.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
57
|
-
if (candidate === menuItemRef) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
candidate?.focus();
|
|
62
|
-
return !!candidate;
|
|
63
|
-
};
|
|
64
|
-
const focusNextMenuItem = () => {
|
|
65
|
-
let candidate = menuItemRef?.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
|
|
66
|
-
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
67
|
-
candidate = candidate.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
|
|
68
|
-
if (candidate === menuItemRef) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
candidate?.focus();
|
|
73
|
-
return !!candidate;
|
|
74
|
-
};
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region open/close
|
|
77
|
-
// opens the menu for this menu item
|
|
78
|
-
const openMenu = () => {
|
|
79
|
-
if (!menuItemContext.openValues.includes(value)) {
|
|
80
|
-
// slice to depth to close any sibling menus that are open
|
|
81
|
-
menuItemContext.openValues = [
|
|
82
|
-
...menuItemContext.openValues.slice(0, menuItemContext.depth),
|
|
83
|
-
value
|
|
84
|
-
];
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
// closes the menu for this menu item
|
|
88
|
-
const closeMenu = async () => {
|
|
89
|
-
const index = menuItemContext.openValues.indexOf(value);
|
|
90
|
-
if (index !== -1) {
|
|
91
|
-
menuItemContext.openValues = [...menuItemContext.openValues.slice(0, index)];
|
|
92
|
-
await tick();
|
|
93
|
-
menuItemRef?.focus();
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
const closeAllMenus = () => {
|
|
97
|
-
menuItemContext.openValues = [];
|
|
98
|
-
};
|
|
99
|
-
//#endregion
|
|
100
|
-
//#region event handlers
|
|
101
|
-
const onKeyDown = async (event) => {
|
|
102
|
-
if (!disabled && !event.altKey && !event.ctrlKey && !event.shiftKey) {
|
|
103
|
-
switch (event.key) {
|
|
104
|
-
case 'ArrowDown':
|
|
105
|
-
// ARIA menubar/menuitem:
|
|
106
|
-
// If the currently focused menuitem has a submenu,
|
|
107
|
-
// opens the submenu and places focus on the first item in the submenu.
|
|
108
|
-
if (menuItemContext.isMenuBarItem && children) {
|
|
109
|
-
openMenu();
|
|
110
|
-
setTimeout(async () => {
|
|
111
|
-
await tick();
|
|
112
|
-
menuRef?.focusFirstMenuItem();
|
|
113
|
-
}, 10);
|
|
114
|
-
event.preventDefault();
|
|
115
|
-
event.stopPropagation();
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
if (!menuItemContext.isMenuBarItem) {
|
|
119
|
-
// ARIA menuitem:
|
|
120
|
-
// Moves focus to the next item, optionally wrapping from the last to the first.
|
|
121
|
-
focusNextMenuItem();
|
|
122
|
-
event.preventDefault();
|
|
123
|
-
event.stopPropagation();
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
break;
|
|
127
|
-
case 'ArrowLeft':
|
|
128
|
-
// ARIA menubar/menuitem:
|
|
129
|
-
// Moves focus to the previous item, optionally wrapping from the first to the last.
|
|
130
|
-
if (menuItemContext.isMenuBarItem) {
|
|
131
|
-
focusPreviousMenuItem();
|
|
132
|
-
event.preventDefault();
|
|
133
|
-
event.stopPropagation();
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
// ARIA menuitem:
|
|
137
|
-
// When focus is in a submenu of an item in a menu,
|
|
138
|
-
// closes the submenu and returns focus to the parent menuitem.
|
|
139
|
-
if (menuItemContext.depth && menuItemContext.depth > 1) {
|
|
140
|
-
menuItemContext.closeContainingMenu?.();
|
|
141
|
-
event.preventDefault();
|
|
142
|
-
event.stopPropagation();
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
// ARIA menubar/menuitem:
|
|
146
|
-
// When focus is in a submenu of an item in a menubar,
|
|
147
|
-
// closes the submenu,
|
|
148
|
-
// moves focus to the previous item in the menubar,
|
|
149
|
-
// and,
|
|
150
|
-
// if focus is now on a menuitem with a submenu,
|
|
151
|
-
// either opens the submenu of that menuitem without moving focus into the submenu,
|
|
152
|
-
// or opens the submenu of that menuitem and places focus on the first item in the submenu.
|
|
153
|
-
menuBarContext.openPreviousMenuBarItem?.();
|
|
154
|
-
event.preventDefault();
|
|
155
|
-
event.stopPropagation();
|
|
156
|
-
return false;
|
|
157
|
-
case 'ArrowRight':
|
|
158
|
-
// ARIA menubar:
|
|
159
|
-
// Moves focus to the next item, optionally wrapping from the last to the first.
|
|
160
|
-
if (menuItemContext.isMenuBarItem) {
|
|
161
|
-
focusNextMenuItem();
|
|
162
|
-
event.preventDefault();
|
|
163
|
-
event.stopPropagation();
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
// ARIA menuitem:
|
|
167
|
-
// When focus is in a menu and on a menuitem that has a submenu,
|
|
168
|
-
// opens the submenu and places focus on its first item
|
|
169
|
-
if (children) {
|
|
170
|
-
openMenu();
|
|
171
|
-
setTimeout(async () => {
|
|
172
|
-
await tick();
|
|
173
|
-
menuRef?.focusFirstMenuItem();
|
|
174
|
-
}, 10);
|
|
175
|
-
event.preventDefault();
|
|
176
|
-
event.stopPropagation();
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
// ARIA menubar/menuitem:
|
|
180
|
-
// When focus is in a menu and on an item that does not have a submenu,
|
|
181
|
-
// closes the submenu and any parent menus,
|
|
182
|
-
// moves focus to the next item in the menubar,
|
|
183
|
-
// and,
|
|
184
|
-
// if focus is now on a menuitem with a submenu,
|
|
185
|
-
// either opens the submenu of that menuitem without moving focus into the submenu,
|
|
186
|
-
// or opens the submenu of that menuitem and places focus on the first item in the submenu.
|
|
187
|
-
if (menuBarContext.openNextMenuBarItem) {
|
|
188
|
-
menuBarContext.openNextMenuBarItem();
|
|
189
|
-
event.preventDefault();
|
|
190
|
-
event.stopPropagation();
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
break;
|
|
194
|
-
case 'ArrowUp':
|
|
195
|
-
// ARIA menubar/menuitem:
|
|
196
|
-
// If the currently focused menuitem has a submenu,
|
|
197
|
-
// opens the submenu and places focus on the last item in the submenu.
|
|
198
|
-
if (menuItemContext.isMenuBarItem && children) {
|
|
199
|
-
openMenu();
|
|
200
|
-
setTimeout(async () => {
|
|
201
|
-
await tick();
|
|
202
|
-
menuRef?.focusLastMenuItem();
|
|
203
|
-
}, 10);
|
|
204
|
-
event.preventDefault();
|
|
205
|
-
event.stopPropagation();
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
// ARIA menuitem:
|
|
209
|
-
// Moves focus to the previous item, optionally wrapping from the first to the last.
|
|
210
|
-
if (!menuItemContext.isMenuBarItem) {
|
|
211
|
-
focusPreviousMenuItem();
|
|
212
|
-
event.preventDefault();
|
|
213
|
-
event.stopPropagation();
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
break;
|
|
217
|
-
case 'Escape':
|
|
218
|
-
// ARIA menuitem:
|
|
219
|
-
// Close the menu that contains focus and return focus to the element or context,
|
|
220
|
-
// e.g., menu button or parent menuitem, from which the menu was opened.
|
|
221
|
-
// open = false;
|
|
222
|
-
closeAllMenus();
|
|
223
|
-
event.preventDefault();
|
|
224
|
-
event.stopPropagation();
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
rest.onkeydown?.(event);
|
|
229
|
-
};
|
|
230
|
-
const onMouseEnter = (event) => {
|
|
231
|
-
menuItemRef?.focus();
|
|
232
|
-
rest.onmouseenter?.(event);
|
|
233
|
-
};
|
|
234
|
-
const onClick = (event) => {
|
|
235
|
-
if (!disabled) {
|
|
236
|
-
if (children) {
|
|
237
|
-
if (!menuItemContext.openValues.includes(value)) {
|
|
238
|
-
openMenu();
|
|
239
|
-
if ($usingKeyboard) {
|
|
240
|
-
setTimeout(async () => {
|
|
241
|
-
await tick();
|
|
242
|
-
menuRef?.focusFirstMenuItem();
|
|
243
|
-
}, 10);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
closeMenu();
|
|
248
|
-
}
|
|
249
|
-
event.preventDefault();
|
|
250
|
-
event.stopPropagation();
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
raiseSelect(value);
|
|
255
|
-
closeAllMenus();
|
|
256
|
-
event.preventDefault();
|
|
257
|
-
event.stopPropagation();
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
rest.onclick?.(event);
|
|
262
|
-
};
|
|
263
|
-
//#endregion
|
|
264
|
-
//#region set context
|
|
265
|
-
let menuItemChildContext = {
|
|
266
|
-
isMenuBarItem: false,
|
|
267
|
-
get openValues() {
|
|
268
|
-
return menuItemContext.openValues;
|
|
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,
|
|
276
|
-
onOpen: raiseOpen,
|
|
277
|
-
onClose: raiseClose,
|
|
278
|
-
onSelect: raiseSelect
|
|
279
|
-
};
|
|
280
|
-
setContext(MENU_ITEM_CONTEXT_KEY, menuItemChildContext);
|
|
281
|
-
//#endregion
|
|
282
|
-
</script>
|
|
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
|
-
|
|
304
|
-
<button
|
|
305
|
-
bind:this={menuItemRef}
|
|
306
|
-
aria-controls={menuId}
|
|
307
|
-
aria-disabled={disabled}
|
|
308
|
-
aria-expanded={open}
|
|
309
|
-
aria-haspopup={!!children}
|
|
310
|
-
aria-owns={menuId}
|
|
311
|
-
class={['sterling-menu-item', _class].filter(Boolean).join(' ')}
|
|
312
|
-
class:using-keyboard={usingKeyboard}
|
|
313
|
-
data-value={value}
|
|
314
|
-
data-root-value={menuItemContext.rootValue}
|
|
315
|
-
{disabled}
|
|
316
|
-
{role}
|
|
317
|
-
tabindex={0}
|
|
318
|
-
type="button"
|
|
319
|
-
{...rest}
|
|
320
|
-
onclick={onClick}
|
|
321
|
-
onkeydown={onKeyDown}
|
|
322
|
-
onmouseenter={onMouseEnter}
|
|
323
|
-
>
|
|
324
|
-
<div class="item" id={displayId}>
|
|
325
|
-
{#if item}
|
|
326
|
-
{@render item()}
|
|
327
|
-
{:else}
|
|
328
|
-
{@render renderDefaultItem()}
|
|
329
|
-
{/if}
|
|
330
|
-
</div>
|
|
331
|
-
{#if menuItemRef && open && children}
|
|
332
|
-
<Popover
|
|
333
|
-
reference={menuItemRef}
|
|
334
|
-
placement={menuItemContext.isMenuBarItem ? 'bottom-start' : 'right-start'}
|
|
335
|
-
{open}
|
|
336
|
-
>
|
|
337
|
-
<Menu bind:this={menuRef} id={menuId} class={menuClass}>
|
|
338
|
-
{@render children()}
|
|
339
|
-
</Menu>
|
|
340
|
-
</Popover>
|
|
341
|
-
{/if}
|
|
342
|
-
</button>
|
package/MenuItem.svelte.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
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;
|
|
15
|
-
};
|
|
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/MenuItem.types.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { MENU_ITEM_ROLES } from './MenuItem.constants';
|
|
2
|
-
type MenuItemRoleTuple = typeof MENU_ITEM_ROLES;
|
|
3
|
-
export type MenuItemRole = MenuItemRoleTuple[number];
|
|
4
|
-
export type MenuItemRegistration = {
|
|
5
|
-
value: string;
|
|
6
|
-
open: () => void;
|
|
7
|
-
close: () => void;
|
|
8
|
-
focus: () => void;
|
|
9
|
-
};
|
|
10
|
-
export type MenuItemContext = {
|
|
11
|
-
isMenuBarItem?: boolean;
|
|
12
|
-
openValues: string[];
|
|
13
|
-
rootValue?: string;
|
|
14
|
-
depth?: number;
|
|
15
|
-
closeContainingMenu?: () => void;
|
|
16
|
-
onOpen?: (value: string) => void;
|
|
17
|
-
onClose?: (value: string) => void;
|
|
18
|
-
onSelect?: (value: string) => void;
|
|
19
|
-
};
|
|
20
|
-
export {};
|
package/MenuItem.types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/MenuItem.utils.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { MenuItemRegistration } from './MenuItem.types';
|
|
2
|
-
export declare const focusPreviousChild: (children: MenuItemRegistration[], currentValue: string) => void;
|
|
3
|
-
export declare const focusNextChild: (children: MenuItemRegistration[], currentValue: string) => void;
|
|
4
|
-
export declare const focusFirstChild: (children: MenuItemRegistration[]) => void;
|
|
5
|
-
export declare const focusLastChild: (children: MenuItemRegistration[]) => void;
|
|
6
|
-
export declare const isElementMenuItem: (candidate: Element | null | undefined) => boolean;
|
|
7
|
-
export declare const isElementEnabledMenuItem: (candidate: Element | null | undefined) => boolean;
|