@geoffcox/sterling-svelte 0.0.25 → 0.0.26

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/Dropdown.svelte CHANGED
@@ -241,7 +241,16 @@ const onClickOutside = (event) => {
241
241
  }
242
242
 
243
243
  .popup-content {
244
+ background-color: var(--stsv-Common__background-color);
245
+ border-color: var(--stsv-Common__border-color);
246
+ border-radius: var(--stsv-Common__border-radius);
247
+ border-style: var(--stsv-Common__border-style);
248
+ border-width: var(--stsv-Common__border-width);
244
249
  padding: 0.25em;
250
+ display: grid;
251
+ grid-template-columns: 1fr;
252
+ grid-template-rows: 1fr;
253
+ overflow: hidden;
245
254
  }
246
255
 
247
256
  @media (prefers-reduced-motion) {
package/Field.svelte CHANGED
@@ -1,6 +1,5 @@
1
- <script>import { createKeyborg } from "keyborg";
2
- import { onMount } from "svelte";
3
- import Tooltip from "./Tooltip.svelte";
1
+ <script>import Tooltip from "./Tooltip.svelte";
2
+ import { usingKeyboard } from "./stores/usingKeyboard";
4
3
  export let forwardClick = false;
5
4
  let htmlFor = void 0;
6
5
  export { htmlFor as for };
@@ -62,11 +61,6 @@ $: {
62
61
  });
63
62
  }
64
63
  }
65
- let keyborg = createKeyborg(window);
66
- let usingKeyboard = keyborg.isNavigatingWithKeyboard();
67
- const keyborgHandler = (value) => {
68
- usingKeyboard = value;
69
- };
70
64
  export const click = () => {
71
65
  fieldRef?.click();
72
66
  };
@@ -76,12 +70,6 @@ export const blur = () => {
76
70
  export const focus = (options) => {
77
71
  fieldRef?.focus(options);
78
72
  };
79
- onMount(() => {
80
- keyborg.subscribe(keyborgHandler);
81
- return () => {
82
- keyborg.unsubscribe(keyborgHandler);
83
- };
84
- });
85
73
  const onClick = () => {
86
74
  if (forwardClick) {
87
75
  targetRef?.click();
@@ -94,7 +82,7 @@ const onClick = () => {
94
82
  aria-disabled={targetDisabled}
95
83
  class="sterling-field"
96
84
  class:disabled={targetDisabled}
97
- class:using-keyboard={usingKeyboard}
85
+ class:using-keyboard={$usingKeyboard}
98
86
  for={htmlFor}
99
87
  on:blur
100
88
  on:click
package/List.svelte CHANGED
@@ -1,7 +1,7 @@
1
- <script>import { createKeyborg } from "keyborg";
2
- import { createEventDispatcher, onMount, setContext } from "svelte";
1
+ <script>import { createEventDispatcher, setContext } from "svelte";
3
2
  import { writable } from "svelte/store";
4
3
  import { LIST_CONTEXT_KEY } from "./List.constants";
4
+ import { usingKeyboard } from "./stores/usingKeyboard";
5
5
  export let composed = false;
6
6
  export let disabled = false;
7
7
  export let horizontal = false;
@@ -43,11 +43,6 @@ export const scrollToSelectedItem = () => {
43
43
  const element = getSelectedItemElement();
44
44
  element?.scrollIntoView({ block: "nearest", inline: "nearest" });
45
45
  };
46
- let keyborg = createKeyborg(window);
47
- let usingKeyboard = keyborg.isNavigatingWithKeyboard();
48
- const keyborgHandler = (value) => {
49
- usingKeyboard = value;
50
- };
51
46
  const isElementListItem = (candidate) => {
52
47
  return candidate && candidate.getAttribute("data-value") !== null && candidate.getAttribute("data-value") !== void 0 && candidate.getAttribute("role") === "listitem";
53
48
  };
@@ -113,12 +108,6 @@ export const selectLastItem = () => {
113
108
  }
114
109
  return false;
115
110
  };
116
- onMount(() => {
117
- keyborg.subscribe(keyborgHandler);
118
- return () => {
119
- keyborg.unsubscribe(keyborgHandler);
120
- };
121
- });
122
111
  const onClick = (event) => {
123
112
  if (!disabled) {
124
113
  let candidate = event.target;
@@ -197,7 +186,7 @@ A list of items where a single item can be selected.
197
186
  class:composed
198
187
  class:disabled
199
188
  class:horizontal
200
- class:using-keyboard={usingKeyboard}
189
+ class:using-keyboard={$usingKeyboard}
201
190
  role="list"
202
191
  tabindex={0}
203
192
  on:blur
package/Menu.svelte CHANGED
@@ -1,155 +1,126 @@
1
- <script>import { getContext, onMount } from "svelte";
2
- import { autoUpdate, computePosition, flip, offset, shift } from "@floating-ui/dom";
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
- export let reference;
6
- export let open = false;
4
+ import { isElementEnabledMenuItem, isElementMenuItem } from "./MenuItem.utils";
5
+ import { prefersReducedMotion } from "./stores/prefersReducedMotion";
7
6
  let menuRef;
8
- let menuPosition = { x: 0, y: 0 };
9
- const { rootValue, depth = 0 } = getContext(MENU_ITEM_CONTEXT_KEY) || {};
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 ensurePortalHost = () => {
17
- let host = document.querySelector("#SterlingMenuPortal");
18
- if (!host) {
19
- host = document.createElement("div");
20
- host.id = "SterlingMenuPortal";
21
- host.style.overflow = "visible";
22
- document.body.append(host);
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
- return host;
28
+ candidate?.focus({ preventScroll: true });
29
+ return !!candidate;
25
30
  };
26
- const portalTarget = ensurePortalHost();
27
- let bodyHeight = 0;
28
- const resizeObserver = new ResizeObserver((entries) => {
29
- bodyHeight = entries[0].target.clientHeight;
30
- });
31
- const menuPlacement = depth > 1 ? "right-start" : "bottom-start";
32
- const middleware = [
33
- offset({ mainAxis: -2 }),
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
- let cleanupAutoUpdate = () => {
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 autoUpdateMenuPosition = () => {
50
- cleanupAutoUpdate();
51
- if (reference && menuRef) {
52
- cleanupAutoUpdate = autoUpdate(reference, menuRef, computeMenuPosition);
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
- {#if open}
68
- <div
69
- use:portal={{ target: portalTarget }}
70
- class="sterling-menu-portal"
71
- data-root-value={rootValue}
72
- >
73
- <div
74
- bind:this={menuRef}
75
- class="sterling-menu"
76
- role="menu"
77
- class:open
78
- on:blur
79
- on:click
80
- on:copy
81
- on:cut
82
- on:dblclick
83
- on:dragend
84
- on:dragenter
85
- on:dragleave
86
- on:dragover
87
- on:dragstart
88
- on:drop
89
- on:focus
90
- on:focusin
91
- on:focusout
92
- on:keydown
93
- on:keypress
94
- on:keyup
95
- on:mousedown
96
- on:mouseenter
97
- on:mouseleave
98
- on:mousemove
99
- on:mouseover
100
- on:mouseout
101
- on:mouseup
102
- on:scroll
103
- on:wheel
104
- on:paste
105
- {...$$restProps}
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
97
+ on:paste
98
+ {...$$restProps}
99
+ >
100
+ <div bind:this={menuItemsRef} class="menu-items">
101
+ <slot />
112
102
  </div>
113
- {/if}
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
107
  background-color: var(--stsv-Common__background-color);
124
108
  border-color: var(--stsv-Common__border-color);
125
109
  border-radius: var(--stsv-Common__border-radius);
126
110
  border-style: var(--stsv-Common__border-style);
127
111
  border-width: var(--stsv-Common__border-width);
128
- box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px -1px;
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
- .sterling-menu-content {
120
+ .menu-items {
146
121
  display: grid;
147
122
  grid-template-columns: 1fr;
148
123
  grid-template-rows: auto;
149
124
  row-gap: calc(2 * var(--stsv-Common__outline-width));
150
125
  }
151
-
152
- .sterling-menu.open {
153
- display: grid;
154
- }
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 children = writable([]);
23
- const openPreviousChild = (currentValue) => {
24
- const index = $children?.findIndex((menuItem) => menuItem.value === currentValue);
25
- if (index !== -1) {
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 openNextChild = (currentValue) => {
32
- const index = $children?.findIndex((menuItem) => menuItem.value === currentValue);
33
- if (index !== -1) {
34
- const focusIndex = (index + 1) % $children.length;
35
- $children[focusIndex].focus();
36
- $children[focusIndex].open();
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 focusChild = (value) => {
40
- const focusIndex = $children?.findIndex((menuItem) => menuItem.value === value);
41
- if (focusIndex !== -1) {
42
- $children[focusIndex].focus();
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
- register: (menuItem) => {
47
- children.set([...$children, menuItem]);
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
@@ -95,6 +138,8 @@ setContext(MENU_BAR_CONTEXT_KEY, {
95
138
  on:wheel
96
139
  on:paste
97
140
  {...$$restProps}
141
+ use:clickOutside
142
+ on:click_outside={onClickOutside}
98
143
  >
99
144
  <slot />
100
145
  </div>
@@ -1,4 +1,4 @@
1
1
  export type MenuBarContext = {
2
- openPreviousMenu?: (currentValue: string) => void;
3
- openNextMenu?: (currentValue: string) => void;
2
+ openPreviousMenuBarItem?: () => void;
3
+ openNextMenuBarItem?: () => void;
4
4
  };
package/MenuButton.svelte CHANGED
@@ -1,10 +1,12 @@
1
- <script>import { createEventDispatcher, getContext, setContext } from "svelte";
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";
9
+ import { usingKeyboard } from "./stores/usingKeyboard";
8
10
  export let open = false;
9
11
  export let shape = "rounded";
10
12
  export let value;
@@ -12,12 +14,16 @@ export let variant = "regular";
12
14
  const instanceId = idGenerator.nextId("MenuButton");
13
15
  let buttonRef;
14
16
  let reference;
17
+ let menuRef;
15
18
  let prevOpen = open;
16
19
  $:
17
20
  menuId = `${value}-menu-${instanceId}`;
18
21
  $:
19
22
  hasChildren = $$slots.items;
20
- const children = writable([]);
23
+ const openValues = writable([]);
24
+ $: {
25
+ open = $openValues.length > 0;
26
+ }
21
27
  const dispatch = createEventDispatcher();
22
28
  const raiseClose = (value2) => {
23
29
  dispatch("close", { value: value2 });
@@ -28,10 +34,25 @@ const raiseOpen = (value2) => {
28
34
  const raiseSelect = (value2) => {
29
35
  dispatch("select", { value: value2 });
30
36
  };
31
- const onClick = () => {
32
- open = !open;
33
- if (open) {
34
- setTimeout(() => focusFirstChild($children), 10);
37
+ export const click = () => {
38
+ buttonRef?.click();
39
+ };
40
+ export const blur = () => {
41
+ buttonRef?.blur();
42
+ };
43
+ export const focus = (options) => {
44
+ buttonRef?.focus(options);
45
+ };
46
+ const onClick = async () => {
47
+ if (!open) {
48
+ openValues.set(["menu-button"]);
49
+ if ($usingKeyboard) {
50
+ await tick();
51
+ menuRef?.focusFirstMenuItem();
52
+ }
53
+ } else {
54
+ open = false;
55
+ openValues.set([]);
35
56
  }
36
57
  };
37
58
  $: {
@@ -40,29 +61,28 @@ $: {
40
61
  }
41
62
  prevOpen = open;
42
63
  }
43
- export const click = () => {
44
- buttonRef?.click();
45
- };
46
- export const blur = () => {
47
- buttonRef?.blur();
64
+ const closeAllMenus = () => {
65
+ openValues.set([]);
48
66
  };
49
- export const focus = (options) => {
50
- buttonRef?.focus(options);
67
+ const onClickOutside = (event) => {
68
+ const {
69
+ detail: { mouseEvent }
70
+ } = event;
71
+ let element = mouseEvent.target;
72
+ while (element) {
73
+ if (element.getAttribute("data-root-value") === value) {
74
+ return;
75
+ }
76
+ element = element.parentElement;
77
+ }
78
+ closeAllMenus?.();
51
79
  };
52
80
  setContext(MENU_ITEM_CONTEXT_KEY, {
81
+ openValues,
53
82
  rootValue: value,
54
- depth: 1,
55
- register: (menuItem) => {
56
- children.set([...$children, menuItem]);
57
- },
58
- unregister: (menuItem) => {
59
- children.set($children.filter((x) => x.value !== menuItem.value));
60
- },
61
- closeMenu: (recursive) => {
83
+ closeContainingMenu: () => {
62
84
  open = false;
63
85
  },
64
- focusPrevious: (currentValue) => focusPreviousChild($children, currentValue),
65
- focusNext: (currentValue) => focusNextChild($children, currentValue),
66
86
  onOpen: raiseOpen,
67
87
  onClose: raiseClose,
68
88
  onSelect: raiseSelect
@@ -117,12 +137,14 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
117
137
  on:wheel
118
138
  {...$$restProps}
119
139
  >
120
- <div class="reference" bind:this={reference}>
140
+ <div class="reference" bind:this={reference} use:clickOutside on:click_outside={onClickOutside}>
121
141
  <slot {shape} {variant} />
122
142
  </div>
123
- <Menu id={menuId} {reference} {open}>
124
- <slot name="items" />
125
- </Menu>
143
+ <Popover {reference} placement="bottom-start" {open}>
144
+ <Menu bind:this={menuRef} id={menuId} {reference} {open}>
145
+ <slot name="items" />
146
+ </Menu>
147
+ </Popover>
126
148
  </Button>
127
149
 
128
150
  <style>
@@ -1 +1,2 @@
1
1
  export declare const MENU_ITEM_CONTEXT_KEY = "sterlingMenuItem";
2
+ export declare const MENU_ITEM_ROLES: readonly ["menuitem", "menuitemcheckbox", "menuitemradio"];
@@ -1 +1,2 @@
1
1
  export const MENU_ITEM_CONTEXT_KEY = 'sterlingMenuItem';
2
+ export const MENU_ITEM_ROLES = ['menuitem', 'menuitemcheckbox', 'menuitemradio'];