@geoffcox/sterling-svelte 0.0.24 → 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/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'];
package/MenuItem.svelte CHANGED
@@ -1,50 +1,60 @@
1
- <script>import { createKeyborg } from "keyborg";
2
- import { getContext, onMount, setContext } from "svelte";
1
+ <script>import {
2
+ getContext,
3
+ afterUpdate,
4
+ createEventDispatcher,
5
+ onMount,
6
+ setContext,
7
+ tick
8
+ } from "svelte";
3
9
  import { writable } from "svelte/store";
4
- import { clickOutside } from "./actions/clickOutside";
5
- import { afterUpdate, createEventDispatcher } from "svelte/internal";
6
- import MenuItemDisplay from "./MenuItemDisplay.svelte";
10
+ import { idGenerator } from "./idGenerator";
11
+ import Menu from "./Menu.svelte";
7
12
  import { MENU_BAR_CONTEXT_KEY } from "./MenuBar.constants";
8
13
  import { MENU_ITEM_CONTEXT_KEY } from "./MenuItem.constants";
9
- import Menu from "./Menu.svelte";
10
- import {
11
- focusFirstChild,
12
- focusLastChild,
13
- focusNextChild,
14
- focusPreviousChild
15
- } from "./MenuItem.utils";
16
- import { idGenerator } from "./idGenerator";
14
+ import { isElementEnabledMenuItem } from "./MenuItem.utils";
15
+ import MenuItemDisplay from "./MenuItemDisplay.svelte";
16
+ import Popover from "./Popover.svelte";
17
+ import { usingKeyboard } from "./stores/usingKeyboard";
17
18
  export let checked = false;
18
19
  export let composed = false;
19
20
  export let disabled = false;
20
- export let open = false;
21
21
  export let value;
22
22
  export let role = "menuitem";
23
23
  export let text = void 0;
24
24
  const {
25
+ isMenuBarItem,
26
+ openValues = writable([]),
25
27
  rootValue = value,
26
28
  depth = 0,
27
- register = void 0,
28
- unregister = void 0,
29
- closeMenu = void 0,
30
- focusPrevious = void 0,
31
- focusNext = void 0,
29
+ closeContainingMenu = void 0,
32
30
  onOpen = void 0,
33
31
  onClose = void 0,
34
32
  onSelect = void 0
35
33
  } = getContext(MENU_ITEM_CONTEXT_KEY) || {};
36
- const { openPreviousMenu = void 0, openNextMenu = void 0 } = getContext(MENU_BAR_CONTEXT_KEY) || {};
34
+ const { openPreviousMenuBarItem = void 0, openNextMenuBarItem = void 0 } = getContext(MENU_BAR_CONTEXT_KEY) || {};
37
35
  const instanceId = idGenerator.nextId("MenuItem");
38
36
  $:
39
37
  displayId = `${value}-display-${instanceId}`;
38
+ $:
39
+ open = $openValues.includes(value);
40
40
  $:
41
41
  menuId = `${value}-menu-${instanceId}`;
42
42
  let menuItemRef;
43
+ let menuRef;
43
44
  const children = writable([]);
44
45
  let mounted = false;
45
46
  let prevOpen = open;
46
47
  $:
47
48
  hasChildren = $$slots.default;
49
+ export const blur = () => {
50
+ menuItemRef?.blur();
51
+ };
52
+ export const click = () => {
53
+ menuItemRef?.click();
54
+ };
55
+ export const focus = (options) => {
56
+ menuItemRef?.focus(options);
57
+ };
48
58
  const dispatch = createEventDispatcher();
49
59
  const raiseClose = (value2) => {
50
60
  dispatch("close", { value: value2 });
@@ -64,157 +74,176 @@ const raiseSelect = (value2) => {
64
74
  dispatch("select", { value: value2 });
65
75
  onSelect?.(value2);
66
76
  };
67
- let keyborg = createKeyborg(window);
68
- let usingKeyboard = keyborg.isNavigatingWithKeyboard();
69
- const keyborgHandler = (value2) => {
70
- usingKeyboard = value2;
77
+ const focusPreviousMenuItem = () => {
78
+ let candidate = menuItemRef?.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
79
+ while (candidate && !isElementEnabledMenuItem(candidate)) {
80
+ candidate = candidate.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
81
+ if (candidate === menuItemRef) {
82
+ return false;
83
+ }
84
+ }
85
+ candidate?.focus();
86
+ return !!candidate;
71
87
  };
72
- const autoFocusFirstChild = (open2, insideMenu) => {
73
- if (open2 && insideMenu) {
74
- setTimeout(() => focusFirstChild($children), 10);
88
+ const focusNextMenuItem = () => {
89
+ let candidate = menuItemRef?.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
90
+ while (candidate && !isElementEnabledMenuItem(candidate)) {
91
+ candidate = candidate.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
92
+ if (candidate === menuItemRef) {
93
+ return false;
94
+ }
75
95
  }
96
+ candidate?.focus();
97
+ return !!candidate;
76
98
  };
77
- $:
78
- autoFocusFirstChild(open, depth > 0);
79
- export const click = () => {
80
- menuItemRef?.click();
99
+ const openMenu = () => {
100
+ if (!$openValues.includes(value)) {
101
+ openValues.set([...$openValues.slice(0, depth), value]);
102
+ }
81
103
  };
82
- export const blur = () => {
83
- menuItemRef?.blur();
104
+ const closeMenu = async () => {
105
+ const index = $openValues.indexOf(value);
106
+ if (index !== -1) {
107
+ openValues.set([...$openValues.slice(0, index)]);
108
+ await tick();
109
+ menuItemRef?.focus();
110
+ }
84
111
  };
85
- export const focus = (options) => {
86
- menuItemRef?.focus(options);
112
+ const closeAllMenus = () => {
113
+ openValues.set([]);
87
114
  };
88
115
  onMount(() => {
89
116
  mounted = true;
90
- keyborg.subscribe(keyborgHandler);
91
- const menuItemSelf = {
92
- value,
93
- open: () => {
94
- open = true;
95
- },
96
- close: () => {
97
- open = false;
98
- },
99
- focus: () => {
100
- menuItemRef?.focus();
101
- }
102
- };
103
- register?.(menuItemSelf);
104
- return () => {
105
- keyborg.unsubscribe(keyborgHandler);
106
- unregister?.(menuItemSelf);
107
- };
108
117
  });
109
118
  afterUpdate(() => {
110
119
  prevOpen = open;
111
120
  });
112
- const onKeyDown = (event) => {
121
+ const onKeyDown = async (event) => {
113
122
  if (!disabled && !event.altKey && !event.ctrlKey && !event.shiftKey) {
114
123
  switch (event.key) {
115
124
  case "ArrowDown":
116
- if (depth === 0 && hasChildren) {
117
- open = true;
118
- setTimeout(() => focusFirstChild($children), 10);
125
+ if (isMenuBarItem && hasChildren) {
126
+ openMenu();
127
+ setTimeout(async () => {
128
+ await tick();
129
+ menuRef?.focusFirstMenuItem();
130
+ }, 10);
119
131
  event.preventDefault();
132
+ event.stopPropagation();
120
133
  return false;
121
- } else if (depth > 0) {
122
- focusNext?.(value);
134
+ }
135
+ if (!isMenuBarItem) {
136
+ focusNextMenuItem();
123
137
  event.preventDefault();
138
+ event.stopPropagation();
124
139
  return false;
125
140
  }
126
141
  break;
127
142
  case "ArrowLeft":
128
- if (depth < 2) {
129
- open = false;
130
- closeMenu?.(true);
131
- openPreviousMenu?.(rootValue);
132
- } else {
133
- closeMenu?.();
143
+ if (isMenuBarItem) {
144
+ focusPreviousMenuItem();
145
+ event.preventDefault();
146
+ event.stopPropagation();
147
+ return false;
148
+ }
149
+ if (depth > 1) {
150
+ closeContainingMenu?.();
151
+ event.preventDefault();
152
+ event.stopPropagation();
153
+ return false;
134
154
  }
155
+ openPreviousMenuBarItem?.();
135
156
  event.preventDefault();
157
+ event.stopPropagation();
136
158
  return false;
137
159
  case "ArrowRight":
138
- if (depth > 0 && hasChildren) {
139
- open = true;
140
- setTimeout(focusFirstChild, 10);
141
- } else {
142
- open = false;
143
- closeMenu?.(true);
144
- openNextMenu?.(rootValue);
160
+ if (isMenuBarItem) {
161
+ focusNextMenuItem();
162
+ event.preventDefault();
163
+ event.stopPropagation();
164
+ return false;
145
165
  }
146
- event.preventDefault();
147
- return false;
166
+ if (hasChildren) {
167
+ openMenu();
168
+ setTimeout(async () => {
169
+ await tick();
170
+ menuRef?.focusFirstMenuItem();
171
+ }, 10);
172
+ event.preventDefault();
173
+ event.stopPropagation();
174
+ return false;
175
+ }
176
+ if (openNextMenuBarItem) {
177
+ openNextMenuBarItem();
178
+ event.preventDefault();
179
+ event.stopPropagation();
180
+ return false;
181
+ }
182
+ break;
148
183
  case "ArrowUp":
149
- if (depth === 0 && hasChildren) {
150
- open = true;
151
- setTimeout(() => focusLastChild($children), 10);
184
+ if (isMenuBarItem && hasChildren) {
185
+ openMenu();
186
+ setTimeout(async () => {
187
+ await tick();
188
+ menuRef?.focusLastMenuItem();
189
+ }, 10);
152
190
  event.preventDefault();
191
+ event.stopPropagation();
153
192
  return false;
154
- } else if (depth > 0) {
155
- focusPrevious?.(value);
193
+ }
194
+ if (!isMenuBarItem) {
195
+ focusPreviousMenuItem();
156
196
  event.preventDefault();
197
+ event.stopPropagation();
157
198
  return false;
158
199
  }
200
+ break;
159
201
  case "Escape":
160
202
  open = false;
161
- closeMenu?.(true);
203
+ closeAllMenus();
162
204
  event.preventDefault();
205
+ event.stopPropagation();
163
206
  return false;
164
207
  }
165
208
  }
166
209
  };
167
210
  const onMouseEnter = (event) => {
168
- setTimeout(() => {
169
- menuItemRef?.focus();
170
- }, 10);
211
+ menuItemRef?.focus();
171
212
  };
172
- const onMenuItemClick = (event) => {
213
+ const onClick = (event) => {
173
214
  if (!disabled) {
174
215
  if (hasChildren) {
175
- open = !open;
216
+ if (!$openValues.includes(value)) {
217
+ openMenu();
218
+ if ($usingKeyboard) {
219
+ setTimeout(async () => {
220
+ await tick();
221
+ menuRef?.focusFirstMenuItem();
222
+ }, 10);
223
+ }
224
+ } else {
225
+ closeMenu();
226
+ }
176
227
  event.preventDefault();
177
228
  event.stopPropagation();
178
229
  return false;
179
230
  } else {
180
231
  raiseSelect(value);
181
- closeMenu?.(true);
182
- }
183
- }
184
- };
185
- const onClickOutside = (event) => {
186
- const {
187
- detail: { mouseEvent }
188
- } = event;
189
- let element = mouseEvent.target;
190
- while (element) {
191
- if (element.getAttribute("data-root-value") === rootValue) {
192
- return;
232
+ closeAllMenus();
233
+ event.preventDefault();
234
+ event.stopPropagation();
235
+ return false;
193
236
  }
194
- element = element.parentElement;
195
237
  }
196
- closeMenu?.(true);
197
238
  };
198
239
  setContext(MENU_ITEM_CONTEXT_KEY, {
240
+ isMenuBarItem: false,
241
+ openValues,
199
242
  rootValue,
200
243
  depth: depth + 1,
201
- register: (menuItem) => {
202
- children.set([...$children, menuItem]);
203
- },
204
- unregister: (menuItem) => {
205
- children.set($children.filter((x) => x.value !== menuItem.value));
206
- },
207
- closeMenu: (recursive) => {
208
- open = false;
209
- if (recursive) {
210
- closeMenu?.(recursive);
211
- }
212
- if (!recursive || depth === 0) {
213
- menuItemRef?.focus();
214
- }
244
+ closeContainingMenu: () => {
245
+ closeMenu();
215
246
  },
216
- focusPrevious: (currentValue) => focusPreviousChild($children, currentValue),
217
- focusNext: (currentValue) => focusNextChild($children, currentValue),
218
247
  onOpen: raiseOpen,
219
248
  onClose: raiseClose,
220
249
  onSelect: raiseSelect
@@ -230,14 +259,13 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
230
259
  bind:this={menuItemRef}
231
260
  class="sterling-menu-item"
232
261
  class:composed
233
- class:disabled
234
262
  class:using-keyboard={usingKeyboard}
235
263
  data-value={value}
236
264
  data-root-value={rootValue}
265
+ {disabled}
237
266
  {role}
238
267
  tabindex={0}
239
268
  type="button"
240
- use:clickOutside
241
269
  on:blur
242
270
  on:click
243
271
  on:dblclick
@@ -269,26 +297,39 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
269
297
  on:pointerout
270
298
  on:pointerup
271
299
  on:wheel
272
- on:click={onMenuItemClick}
273
- on:click_outside={onClickOutside}
300
+ on:click={onClick}
274
301
  on:keydown={onKeyDown}
275
302
  on:mouseenter={onMouseEnter}
276
303
  {...$$restProps}
277
304
  >
278
305
  <div class="item" id={displayId}>
279
- <slot name="item" {checked} {depth} {disabled} {hasChildren} {open} {role} {text} {value}>
280
- <MenuItemDisplay
281
- {checked}
282
- {disabled}
283
- hasChildren={depth > 0 && hasChildren}
284
- menuItemRole={role}>{text}</MenuItemDisplay
306
+ <slot
307
+ name="item"
308
+ {checked}
309
+ {depth}
310
+ {disabled}
311
+ {hasChildren}
312
+ {isMenuBarItem}
313
+ {open}
314
+ {role}
315
+ {text}
316
+ {value}
317
+ >
318
+ <MenuItemDisplay {checked} {disabled} {hasChildren} {isMenuBarItem} menuItemRole={role}
319
+ >{text}</MenuItemDisplay
285
320
  >
286
321
  </slot>
287
322
  </div>
288
323
  {#if menuItemRef && open && hasChildren}
289
- <Menu id={menuId} {open} reference={menuItemRef}>
290
- <slot {depth} {disabled} />
291
- </Menu>
324
+ <Popover
325
+ reference={menuItemRef}
326
+ placement={isMenuBarItem ? 'bottom-start' : 'right-start'}
327
+ {open}
328
+ >
329
+ <Menu bind:this={menuRef} id={menuId}>
330
+ <slot {depth} {disabled} />
331
+ </Menu>
332
+ </Popover>
292
333
  {/if}
293
334
  </button>
294
335
 
@@ -5,12 +5,11 @@ declare const __propDef: {
5
5
  checked?: boolean | undefined;
6
6
  composed?: boolean | undefined;
7
7
  disabled?: boolean | undefined;
8
- open?: boolean | undefined;
9
8
  value: string;
10
9
  role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
11
10
  text?: string | undefined;
12
- click?: (() => void) | undefined;
13
11
  blur?: (() => void) | undefined;
12
+ click?: (() => void) | undefined;
14
13
  focus?: ((options?: FocusOptions) => void) | undefined;
15
14
  };
16
15
  events: {
@@ -45,6 +44,9 @@ declare const __propDef: {
45
44
  pointerout: PointerEvent;
46
45
  pointerup: PointerEvent;
47
46
  wheel: WheelEvent;
47
+ close: CustomEvent<any>;
48
+ open: CustomEvent<any>;
49
+ select: CustomEvent<any>;
48
50
  } & {
49
51
  [evt: string]: CustomEvent<any>;
50
52
  };
@@ -54,6 +56,7 @@ declare const __propDef: {
54
56
  depth: number;
55
57
  disabled: boolean;
56
58
  hasChildren: boolean;
59
+ isMenuBarItem: boolean | undefined;
57
60
  open: boolean;
58
61
  role: "menuitem" | "menuitemcheckbox" | "menuitemradio";
59
62
  text: string | undefined;
@@ -69,8 +72,8 @@ export type MenuItemProps = typeof __propDef.props;
69
72
  export type MenuItemEvents = typeof __propDef.events;
70
73
  export type MenuItemSlots = typeof __propDef.slots;
71
74
  export default class MenuItem extends SvelteComponentTyped<MenuItemProps, MenuItemEvents, MenuItemSlots> {
72
- get click(): () => void;
73
75
  get blur(): () => void;
76
+ get click(): () => void;
74
77
  get focus(): (options?: FocusOptions | undefined) => void;
75
78
  }
76
79
  export {};
@@ -1,3 +1,7 @@
1
+ import type { Writable } from 'svelte/store';
2
+ import type { MENU_ITEM_ROLES } from './MenuItem.constants';
3
+ type MenuItemRoleTuple = typeof MENU_ITEM_ROLES;
4
+ export type MenuItemRole = MenuItemRoleTuple[number];
1
5
  export type MenuItemRegistration = {
2
6
  value: string;
3
7
  open: () => void;
@@ -5,14 +9,19 @@ export type MenuItemRegistration = {
5
9
  focus: () => void;
6
10
  };
7
11
  export type MenuItemContext = {
12
+ /**
13
+ * If the menu item is a top-elvel item in a menu bar
14
+ */
15
+ isMenuBarItem?: boolean;
16
+ /**
17
+ * The menu item values for the chain of open menus.
18
+ */
19
+ openValues: Writable<string[]>;
8
20
  rootValue?: string;
9
21
  depth?: number;
10
- register?: (menuItem: MenuItemRegistration) => void;
11
- unregister?: (menuItem: MenuItemRegistration) => void;
12
- focusPrevious?: (currentValue: string) => void;
13
- focusNext?: (currentValue: string) => void;
14
- closeMenu?: (recursive?: boolean) => void;
22
+ closeContainingMenu?: () => void;
15
23
  onOpen?: (value: string) => void;
16
24
  onClose?: (value: string) => void;
17
25
  onSelect?: (value: string) => void;
18
26
  };
27
+ export {};
@@ -3,3 +3,5 @@ export declare const focusPreviousChild: (children: MenuItemRegistration[], curr
3
3
  export declare const focusNextChild: (children: MenuItemRegistration[], currentValue: string) => void;
4
4
  export declare const focusFirstChild: (children: MenuItemRegistration[]) => void;
5
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;
package/MenuItem.utils.js CHANGED
@@ -18,3 +18,19 @@ export const focusFirstChild = (children) => {
18
18
  export const focusLastChild = (children) => {
19
19
  children?.[children.length - 1]?.focus();
20
20
  };
21
+ export const isElementMenuItem = (candidate) => {
22
+ if (!candidate)
23
+ return false;
24
+ const dataValue = candidate?.getAttribute('data-value');
25
+ const role = candidate?.getAttribute('role');
26
+ return ((role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio') &&
27
+ dataValue !== null &&
28
+ dataValue !== undefined);
29
+ };
30
+ export const isElementEnabledMenuItem = (candidate) => {
31
+ if (!isElementMenuItem(candidate)) {
32
+ return false;
33
+ }
34
+ const disabled = candidate?.getAttribute('disabled');
35
+ return disabled === null || disabled === 'false';
36
+ };
@@ -1,6 +1,7 @@
1
1
  <script>export let checked = false;
2
2
  export let disabled = false;
3
3
  export let hasChildren = false;
4
+ export let isMenuBarItem = false;
4
5
  export let menuItemRole = "menuitem";
5
6
  </script>
6
7
 
@@ -19,7 +20,7 @@ export let menuItemRole = "menuitem";
19
20
  <slot name="shortcut" />
20
21
  </div>
21
22
  {:else}
22
- <div class="chevron" class:has-children={hasChildren} />
23
+ <div class="chevron" class:has-children={!isMenuBarItem && hasChildren} />
23
24
  {/if}
24
25
  </div>
25
26
 
@@ -4,6 +4,7 @@ declare const __propDef: {
4
4
  checked?: boolean | undefined;
5
5
  disabled?: boolean | undefined;
6
6
  hasChildren?: boolean | undefined;
7
+ isMenuBarItem?: boolean | undefined;
7
8
  menuItemRole?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
8
9
  };
9
10
  events: {