@spectrum-web-components/menu 0.32.0 → 0.32.1-overlay.41
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/custom-elements.json +478 -225
- package/package.json +9 -9
- package/src/Menu.d.ts +16 -6
- package/src/Menu.dev.js +161 -62
- package/src/Menu.dev.js.map +2 -2
- package/src/Menu.js +7 -3
- package/src/Menu.js.map +3 -3
- package/src/MenuGroup.d.ts +1 -3
- package/src/MenuGroup.dev.js +6 -10
- package/src/MenuGroup.dev.js.map +2 -2
- package/src/MenuGroup.js +3 -5
- package/src/MenuGroup.js.map +3 -3
- package/src/MenuItem.d.ts +24 -22
- package/src/MenuItem.dev.js +132 -150
- package/src/MenuItem.dev.js.map +3 -3
- package/src/MenuItem.js +35 -15
- package/src/MenuItem.js.map +3 -3
- package/src/menu-item.css.dev.js +1 -1
- package/src/menu-item.css.dev.js.map +1 -1
- package/src/menu-item.css.js +1 -1
- package/src/menu-item.css.js.map +1 -1
- package/src/menu.css.dev.js +1 -1
- package/src/menu.css.dev.js.map +1 -1
- package/src/menu.css.js +1 -1
- package/src/menu.css.js.map +1 -1
- package/stories/submenu.stories.js +28 -21
- package/stories/submenu.stories.js.map +3 -3
- package/test/menu-group.test.js +14 -1
- package/test/menu-group.test.js.map +2 -2
- package/test/menu-selects.test.js +3 -1
- package/test/menu-selects.test.js.map +2 -2
- package/test/menu.test.js +7 -0
- package/test/menu.test.js.map +2 -2
- package/test/submenu.test.js +198 -83
- package/test/submenu.test.js.map +2 -2
package/src/MenuGroup.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["MenuGroup.ts"],
|
|
4
|
-
"sourcesContent": ["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport {\n CSSResultArray,\n html,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n queryAssignedNodes,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\n\nimport { Menu } from './Menu.js';\n// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225\nimport
|
|
5
|
-
"mappings": "qNAYA,OAEI,QAAAA,MAEG,gCACP,OACI,sBAAAC,EACA,SAAAC,MACG,kDAEP,OAAS,QAAAC,MAAY,YAErB,MAAO,2CACP,OAAOC,MAAqB,sBAQrB,
|
|
6
|
-
"names": ["html", "queryAssignedNodes", "state", "Menu", "menuGroupStyles", "
|
|
4
|
+
"sourcesContent": ["/*\nCopyright 2020 Adobe. All rights reserved.\nThis file is licensed to you under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License. You may obtain a copy\nof the License at http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under\nthe License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\nOF ANY KIND, either express or implied. See the License for the specific language\ngoverning permissions and limitations under the License.\n*/\n\nimport {\n CSSResultArray,\n html,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n queryAssignedNodes,\n state,\n} from '@spectrum-web-components/base/src/decorators.js';\n\nimport { Menu } from './Menu.js';\n// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225\nimport '@spectrum-web-components/menu/sp-menu.js';\nimport menuGroupStyles from './menu-group.css.js';\n\n/**\n * @element sp-menu-group\n *\n * @slot header - headline of the menu group\n * @slot - menu items to be listed in the group\n */\nexport class MenuGroup extends Menu {\n public static override get styles(): CSSResultArray {\n return [...super.styles, menuGroupStyles];\n }\n\n private headerId = '';\n\n @queryAssignedNodes({\n slot: 'header',\n flatten: true,\n })\n private headerElements!: NodeListOf<HTMLElement>;\n\n @state()\n private headerElement?: HTMLElement;\n\n protected override get ownRole(): string {\n switch (this.selects) {\n case 'multiple':\n case 'single':\n case 'inherit':\n return 'group';\n default:\n return 'menu';\n }\n }\n\n protected updateLabel(): void {\n const headerElement = this.headerElements.length\n ? this.headerElements[0]\n : undefined;\n if (headerElement !== this.headerElement) {\n if (this.headerElement && this.headerElement.id === this.headerId) {\n this.headerElement.removeAttribute('id');\n }\n if (headerElement) {\n this.headerId =\n this.headerId ||\n `sp-menu-group-label-${crypto.randomUUID().slice(0, 8)}`;\n const headerId = headerElement.id || this.headerId;\n if (!headerElement.id) {\n headerElement.id = headerId;\n }\n this.setAttribute('aria-labelledby', headerId);\n } else {\n this.removeAttribute('aria-labelledby');\n }\n }\n this.headerElement = headerElement;\n }\n\n public override render(): TemplateResult {\n return html`\n <span\n class=\"header\"\n aria-hidden=\"true\"\n ?hidden=${!this.headerElement}\n >\n <slot name=\"header\" @slotchange=${this.updateLabel}></slot>\n </span>\n <sp-menu role=\"none\">${this.renderMenuItemSlot()}</sp-menu>\n `;\n }\n}\n"],
|
|
5
|
+
"mappings": "qNAYA,OAEI,QAAAA,MAEG,gCACP,OACI,sBAAAC,EACA,SAAAC,MACG,kDAEP,OAAS,QAAAC,MAAY,YAErB,MAAO,2CACP,OAAOC,MAAqB,sBAQrB,aAAM,kBAAkBD,CAAK,CAA7B,kCAKH,KAAQ,SAAW,GAJnB,WAA2B,QAAyB,CAChD,MAAO,CAAC,GAAG,MAAM,OAAQC,CAAe,CAC5C,CAaA,IAAuB,SAAkB,CACrC,OAAQ,KAAK,QAAS,CAClB,IAAK,WACL,IAAK,SACL,IAAK,UACD,MAAO,QACX,QACI,MAAO,MACf,CACJ,CAEU,aAAoB,CAC1B,MAAMC,EAAgB,KAAK,eAAe,OACpC,KAAK,eAAe,CAAC,EACrB,OACN,GAAIA,IAAkB,KAAK,cAIvB,GAHI,KAAK,eAAiB,KAAK,cAAc,KAAO,KAAK,UACrD,KAAK,cAAc,gBAAgB,IAAI,EAEvCA,EAAe,CACf,KAAK,SACD,KAAK,UACL,uBAAuB,OAAO,WAAW,EAAE,MAAM,EAAG,CAAC,IACzD,MAAMC,EAAWD,EAAc,IAAM,KAAK,SACrCA,EAAc,KACfA,EAAc,GAAKC,GAEvB,KAAK,aAAa,kBAAmBA,CAAQ,OAE7C,KAAK,gBAAgB,iBAAiB,EAG9C,KAAK,cAAgBD,CACzB,CAEgB,QAAyB,CACrC,OAAOL;AAAA;AAAA;AAAA;AAAA,0BAIW,CAAC,KAAK;AAAA;AAAA,kDAEkB,KAAK;AAAA;AAAA,mCAEpB,KAAK,mBAAmB;AAAA,SAEvD,CACJ,CApDYO,EAAA,CAJPN,EAAmB,CAChB,KAAM,SACN,QAAS,EACb,CAAC,GAVQ,UAWD,8BAGAM,EAAA,CADPL,EAAM,GAbE,UAcD",
|
|
6
|
+
"names": ["html", "queryAssignedNodes", "state", "Menu", "menuGroupStyles", "headerElement", "headerId", "__decorateClass"]
|
|
7
7
|
}
|
package/src/MenuItem.d.ts
CHANGED
|
@@ -3,23 +3,19 @@ import '@spectrum-web-components/icons-ui/icons/sp-icon-checkmark100.js';
|
|
|
3
3
|
import { Focusable } from '@spectrum-web-components/shared/src/focusable.js';
|
|
4
4
|
import '@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js';
|
|
5
5
|
import type { Menu } from './Menu.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
6
|
+
import '@spectrum-web-components/overlay/sp-overlay.js';
|
|
7
|
+
import { OverlayBase } from 'overlay/src/OverlayBase.js';
|
|
8
|
+
declare type MenuCascadeItem = {
|
|
9
|
+
hadFocusRoot: boolean;
|
|
10
|
+
ancestorWithSelects?: HTMLElement;
|
|
11
|
+
};
|
|
13
12
|
export declare class MenuItemAddedOrUpdatedEvent extends Event {
|
|
14
|
-
constructor();
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
constructor(item: MenuItem);
|
|
14
|
+
clear(item: MenuItem): void;
|
|
15
|
+
menuCascade: WeakMap<HTMLElement, MenuCascadeItem>;
|
|
17
16
|
get item(): MenuItem;
|
|
18
|
-
_item
|
|
19
|
-
|
|
20
|
-
get currentAncestorWithSelects(): Menu | undefined;
|
|
21
|
-
_currentAncestorWithSelects?: Menu;
|
|
22
|
-
reset(item: MenuItem): void;
|
|
17
|
+
private _item;
|
|
18
|
+
currentAncestorWithSelects?: Menu;
|
|
23
19
|
}
|
|
24
20
|
export declare type MenuItemChildren = {
|
|
25
21
|
icon: Element[];
|
|
@@ -37,12 +33,9 @@ declare const MenuItem_base: typeof Focusable & {
|
|
|
37
33
|
* @slot value - content placed at the end of the Menu Item like values, keyboard shortcuts, etc.
|
|
38
34
|
* @slot submenu - content placed in a submenu
|
|
39
35
|
* @fires sp-menu-item-added - announces the item has been added so a parent menu can take ownerships
|
|
40
|
-
* @fires sp-menu-item-removed - announces when removed from the DOM so the parent menu can remove ownership and update selected state
|
|
41
36
|
*/
|
|
42
37
|
export declare class MenuItem extends MenuItem_base {
|
|
43
38
|
static get styles(): CSSResultArray;
|
|
44
|
-
static instanceCount: number;
|
|
45
|
-
private isInSubmenu;
|
|
46
39
|
active: boolean;
|
|
47
40
|
focused: boolean;
|
|
48
41
|
selected: boolean;
|
|
@@ -56,6 +49,7 @@ export declare class MenuItem extends MenuItem_base {
|
|
|
56
49
|
hasSubmenu: boolean;
|
|
57
50
|
noWrap: boolean;
|
|
58
51
|
private anchorElement;
|
|
52
|
+
overlayElement: OverlayBase;
|
|
59
53
|
get focusElement(): HTMLElement;
|
|
60
54
|
get itemChildren(): MenuItemChildren;
|
|
61
55
|
private _itemChildren?;
|
|
@@ -66,6 +60,7 @@ export declare class MenuItem extends MenuItem_base {
|
|
|
66
60
|
private proxyFocus;
|
|
67
61
|
private shouldProxyClick;
|
|
68
62
|
protected breakItemChildrenCache(): void;
|
|
63
|
+
protected renderSubmenu(): TemplateResult;
|
|
69
64
|
protected render(): TemplateResult;
|
|
70
65
|
protected manageSubmenu(event: Event & {
|
|
71
66
|
target: HTMLSlotElement;
|
|
@@ -75,9 +70,10 @@ export declare class MenuItem extends MenuItem_base {
|
|
|
75
70
|
protected firstUpdated(changes: PropertyValues): void;
|
|
76
71
|
protected closeOverlaysForRoot(): void;
|
|
77
72
|
closeOverlay?: () => Promise<void>;
|
|
78
|
-
protected handleSubmenuClick(): void;
|
|
73
|
+
protected handleSubmenuClick(event: Event): void;
|
|
79
74
|
protected handlePointerenter(): void;
|
|
80
75
|
protected leaveTimeout?: ReturnType<typeof setTimeout>;
|
|
76
|
+
protected recentlyLeftChild: boolean;
|
|
81
77
|
protected handlePointerleave(): void;
|
|
82
78
|
/**
|
|
83
79
|
* When there is a `change` event in the submenu for this item
|
|
@@ -86,8 +82,11 @@ export declare class MenuItem extends MenuItem_base {
|
|
|
86
82
|
* and the root of the tree to have their selection changes and
|
|
87
83
|
* be closed.
|
|
88
84
|
*/
|
|
89
|
-
protected handleSubmenuChange:
|
|
90
|
-
protected handleSubmenuPointerenter
|
|
85
|
+
protected handleSubmenuChange(event: Event): void;
|
|
86
|
+
protected handleSubmenuPointerenter(): void;
|
|
87
|
+
protected handleSubmenuPointerleave(): Promise<void>;
|
|
88
|
+
protected handleSubmenuOpen(event: Event): void;
|
|
89
|
+
protected cleanup(): void;
|
|
91
90
|
openOverlay(): Promise<void>;
|
|
92
91
|
updateAriaSelected(): void;
|
|
93
92
|
setRole(role: string): void;
|
|
@@ -95,16 +94,19 @@ export declare class MenuItem extends MenuItem_base {
|
|
|
95
94
|
connectedCallback(): void;
|
|
96
95
|
_parentElement: HTMLElement;
|
|
97
96
|
disconnectedCallback(): void;
|
|
97
|
+
private willDispatchUpdate;
|
|
98
98
|
triggerUpdate(): Promise<void>;
|
|
99
|
+
dispatchUpdate(): void;
|
|
99
100
|
menuData: {
|
|
100
101
|
focusRoot?: Menu;
|
|
102
|
+
parentMenu?: Menu;
|
|
101
103
|
selectionRoot?: Menu;
|
|
104
|
+
cleanupSteps: ((item: MenuItem) => void)[];
|
|
102
105
|
};
|
|
103
106
|
}
|
|
104
107
|
declare global {
|
|
105
108
|
interface GlobalEventHandlersEventMap {
|
|
106
109
|
'sp-menu-item-added-or-updated': MenuItemAddedOrUpdatedEvent;
|
|
107
|
-
'sp-menu-item-removed': MenuItemRemovedEvent;
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
export {};
|
package/src/MenuItem.dev.js
CHANGED
|
@@ -22,65 +22,38 @@ import { LikeAnchor } from "@spectrum-web-components/shared/src/like-anchor.js";
|
|
|
22
22
|
import { Focusable } from "@spectrum-web-components/shared/src/focusable.js";
|
|
23
23
|
import "@spectrum-web-components/icons-ui/icons/sp-icon-chevron100.js";
|
|
24
24
|
import chevronStyles from "@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js";
|
|
25
|
-
import { openOverlay } from "@spectrum-web-components/overlay/src/loader.js";
|
|
26
|
-
import { OverlayCloseEvent } from "@spectrum-web-components/overlay/src/overlay-events.js";
|
|
27
25
|
import menuItemStyles from "./menu-item.css.js";
|
|
28
26
|
import checkmarkStyles from "@spectrum-web-components/icon/src/spectrum-icon-checkmark.css.js";
|
|
29
|
-
import { reparentChildren } from "@spectrum-web-components/shared/src/reparent-children.js";
|
|
30
27
|
import { MutationController } from "@lit-labs/observers/mutation-controller.js";
|
|
28
|
+
import "@spectrum-web-components/overlay/sp-overlay.js";
|
|
31
29
|
const POINTERLEAVE_TIMEOUT = 100;
|
|
32
|
-
export class MenuItemRemovedEvent extends Event {
|
|
33
|
-
constructor() {
|
|
34
|
-
super("sp-menu-item-removed", {
|
|
35
|
-
bubbles: true,
|
|
36
|
-
composed: true
|
|
37
|
-
});
|
|
38
|
-
this.focused = false;
|
|
39
|
-
}
|
|
40
|
-
get item() {
|
|
41
|
-
return this._item;
|
|
42
|
-
}
|
|
43
|
-
reset(item) {
|
|
44
|
-
this._item = item;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
30
|
export class MenuItemAddedOrUpdatedEvent extends Event {
|
|
48
|
-
constructor() {
|
|
31
|
+
constructor(item) {
|
|
49
32
|
super("sp-menu-item-added-or-updated", {
|
|
50
33
|
bubbles: true,
|
|
51
34
|
composed: true
|
|
52
35
|
});
|
|
36
|
+
this.menuCascade = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
this.clear(item);
|
|
53
38
|
}
|
|
54
|
-
|
|
55
|
-
this.item.menuData.focusRoot = this.item.menuData.focusRoot || root;
|
|
56
|
-
}
|
|
57
|
-
set selectionRoot(root) {
|
|
58
|
-
this.item.menuData.selectionRoot = this.item.menuData.selectionRoot || root;
|
|
59
|
-
}
|
|
60
|
-
get item() {
|
|
61
|
-
return this._item;
|
|
62
|
-
}
|
|
63
|
-
set currentAncestorWithSelects(ancestor) {
|
|
64
|
-
this._currentAncestorWithSelects = ancestor;
|
|
65
|
-
}
|
|
66
|
-
get currentAncestorWithSelects() {
|
|
67
|
-
return this._currentAncestorWithSelects;
|
|
68
|
-
}
|
|
69
|
-
reset(item) {
|
|
39
|
+
clear(item) {
|
|
70
40
|
this._item = item;
|
|
71
|
-
this.
|
|
41
|
+
this.currentAncestorWithSelects = void 0;
|
|
72
42
|
item.menuData = {
|
|
43
|
+
cleanupSteps: [],
|
|
73
44
|
focusRoot: void 0,
|
|
74
|
-
selectionRoot: void 0
|
|
45
|
+
selectionRoot: void 0,
|
|
46
|
+
parentMenu: void 0
|
|
75
47
|
};
|
|
48
|
+
this.menuCascade = /* @__PURE__ */ new WeakMap();
|
|
49
|
+
}
|
|
50
|
+
get item() {
|
|
51
|
+
return this._item;
|
|
76
52
|
}
|
|
77
53
|
}
|
|
78
|
-
|
|
79
|
-
const removeEvent = new MenuItemRemovedEvent();
|
|
80
|
-
const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
54
|
+
export class MenuItem extends LikeAnchor(Focusable) {
|
|
81
55
|
constructor() {
|
|
82
56
|
super();
|
|
83
|
-
this.isInSubmenu = false;
|
|
84
57
|
this.active = false;
|
|
85
58
|
this.focused = false;
|
|
86
59
|
this.selected = false;
|
|
@@ -88,28 +61,17 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
88
61
|
this.hasSubmenu = false;
|
|
89
62
|
this.noWrap = false;
|
|
90
63
|
this.open = false;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* then we "click" this item to cascade the selection up the
|
|
94
|
-
* menu tree allowing all submenus between the initial selection
|
|
95
|
-
* and the root of the tree to have their selection changes and
|
|
96
|
-
* be closed.
|
|
97
|
-
*/
|
|
98
|
-
this.handleSubmenuChange = () => {
|
|
99
|
-
var _a;
|
|
100
|
-
(_a = this.menuData.selectionRoot) == null ? void 0 : _a.selectOrToggleItem(this);
|
|
101
|
-
};
|
|
102
|
-
this.handleSubmenuPointerenter = () => {
|
|
103
|
-
if (this.leaveTimeout) {
|
|
104
|
-
clearTimeout(this.leaveTimeout);
|
|
105
|
-
delete this.leaveTimeout;
|
|
106
|
-
}
|
|
64
|
+
this.proxyFocus = () => {
|
|
65
|
+
this.focus();
|
|
107
66
|
};
|
|
67
|
+
this.recentlyLeftChild = false;
|
|
68
|
+
this.willDispatchUpdate = false;
|
|
108
69
|
this.menuData = {
|
|
109
70
|
focusRoot: void 0,
|
|
110
|
-
|
|
71
|
+
parentMenu: void 0,
|
|
72
|
+
selectionRoot: void 0,
|
|
73
|
+
cleanupSteps: []
|
|
111
74
|
};
|
|
112
|
-
this.proxyFocus = this.proxyFocus.bind(this);
|
|
113
75
|
this.addEventListener("click", this.handleClickCapture, {
|
|
114
76
|
capture: true
|
|
115
77
|
});
|
|
@@ -191,9 +153,6 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
191
153
|
return false;
|
|
192
154
|
}
|
|
193
155
|
}
|
|
194
|
-
proxyFocus() {
|
|
195
|
-
this.focus();
|
|
196
|
-
}
|
|
197
156
|
shouldProxyClick() {
|
|
198
157
|
let handled = false;
|
|
199
158
|
if (this.anchorElement) {
|
|
@@ -206,6 +165,50 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
206
165
|
this._itemChildren = void 0;
|
|
207
166
|
this.triggerUpdate();
|
|
208
167
|
}
|
|
168
|
+
renderSubmenu() {
|
|
169
|
+
const slot = html`
|
|
170
|
+
<slot
|
|
171
|
+
name="submenu"
|
|
172
|
+
@slotchange=${this.manageSubmenu}
|
|
173
|
+
@sp-menu-item-added-or-updated=${{
|
|
174
|
+
handleEvent: (event) => {
|
|
175
|
+
event.clear(event.item);
|
|
176
|
+
},
|
|
177
|
+
capture: true
|
|
178
|
+
}}
|
|
179
|
+
@focusin=${(event) => event.stopPropagation()}
|
|
180
|
+
></slot>
|
|
181
|
+
`;
|
|
182
|
+
if (!this.hasSubmenu) {
|
|
183
|
+
return slot;
|
|
184
|
+
}
|
|
185
|
+
return html`
|
|
186
|
+
<sp-overlay
|
|
187
|
+
.triggerElement=${this}
|
|
188
|
+
?disabled=${!this.hasSubmenu}
|
|
189
|
+
?open=${this.hasSubmenu && this.open}
|
|
190
|
+
.placement=${this.isLTR ? "right-start" : "left-start"}
|
|
191
|
+
.offset=${[-10, -5]}
|
|
192
|
+
.type=${"auto"}
|
|
193
|
+
@close=${(event) => event.stopPropagation()}
|
|
194
|
+
>
|
|
195
|
+
<sp-popover
|
|
196
|
+
@change=${(event) => {
|
|
197
|
+
this.handleSubmenuChange(event);
|
|
198
|
+
this.open = false;
|
|
199
|
+
}}
|
|
200
|
+
@pointerenter=${this.handleSubmenuPointerenter}
|
|
201
|
+
@pointerleave=${this.handleSubmenuPointerleave}
|
|
202
|
+
@sp-menu-item-added-or-updated=${(event) => event.stopPropagation()}
|
|
203
|
+
>
|
|
204
|
+
${slot}
|
|
205
|
+
</sp-popover>
|
|
206
|
+
</sp-overlay>
|
|
207
|
+
<sp-icon-chevron100
|
|
208
|
+
class="spectrum-UIIcon-ChevronRight100 chevron icon"
|
|
209
|
+
></sp-icon-chevron100>
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
209
212
|
render() {
|
|
210
213
|
return html`
|
|
211
214
|
<slot name="icon"></slot>
|
|
@@ -224,26 +227,17 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
224
227
|
ariaHidden: true,
|
|
225
228
|
className: "button anchor hidden"
|
|
226
229
|
}) : html``}
|
|
227
|
-
|
|
228
|
-
hidden
|
|
229
|
-
name="submenu"
|
|
230
|
-
@slotchange=${this.manageSubmenu}
|
|
231
|
-
></slot>
|
|
232
|
-
${this.hasSubmenu ? html`
|
|
233
|
-
<sp-icon-chevron100
|
|
234
|
-
class="spectrum-UIIcon-ChevronRight100 chevron icon"
|
|
235
|
-
></sp-icon-chevron100>
|
|
236
|
-
` : html``}
|
|
230
|
+
${this.renderSubmenu()}
|
|
237
231
|
`;
|
|
238
232
|
}
|
|
239
233
|
manageSubmenu(event) {
|
|
240
234
|
const assignedElements = event.target.assignedElements({
|
|
241
235
|
flatten: true
|
|
242
236
|
});
|
|
243
|
-
this.hasSubmenu =
|
|
237
|
+
this.hasSubmenu = !!assignedElements.length;
|
|
244
238
|
}
|
|
245
|
-
handleRemoveActive(
|
|
246
|
-
if (
|
|
239
|
+
handleRemoveActive() {
|
|
240
|
+
if (this.open) {
|
|
247
241
|
return;
|
|
248
242
|
}
|
|
249
243
|
this.active = false;
|
|
@@ -255,20 +249,21 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
255
249
|
super.firstUpdated(changes);
|
|
256
250
|
this.setAttribute("tabindex", "-1");
|
|
257
251
|
this.addEventListener("pointerdown", this.handlePointerdown);
|
|
252
|
+
this.addEventListener("pointerenter", this.closeOverlaysForRoot);
|
|
258
253
|
if (!this.hasAttribute("id")) {
|
|
259
|
-
this.id = `sp-menu-item-${
|
|
254
|
+
this.id = `sp-menu-item-${crypto.randomUUID().slice(0, 8)}`;
|
|
260
255
|
}
|
|
261
|
-
this.addEventListener("pointerenter", this.closeOverlaysForRoot);
|
|
262
256
|
}
|
|
263
257
|
closeOverlaysForRoot() {
|
|
258
|
+
var _a;
|
|
264
259
|
if (this.open)
|
|
265
260
|
return;
|
|
266
|
-
|
|
267
|
-
root: this.menuData.focusRoot
|
|
268
|
-
});
|
|
269
|
-
this.dispatchEvent(overalyCloseEvent);
|
|
261
|
+
(_a = this.menuData.parentMenu) == null ? void 0 : _a.closeDescendentOverlays();
|
|
270
262
|
}
|
|
271
|
-
handleSubmenuClick() {
|
|
263
|
+
handleSubmenuClick(event) {
|
|
264
|
+
if (event.composedPath().includes(this.overlayElement)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
272
267
|
this.openOverlay();
|
|
273
268
|
}
|
|
274
269
|
handlePointerenter() {
|
|
@@ -280,64 +275,53 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
280
275
|
this.openOverlay();
|
|
281
276
|
}
|
|
282
277
|
handlePointerleave() {
|
|
283
|
-
if (this.
|
|
278
|
+
if (this.open && !this.recentlyLeftChild) {
|
|
284
279
|
this.leaveTimeout = setTimeout(() => {
|
|
285
280
|
delete this.leaveTimeout;
|
|
286
|
-
|
|
287
|
-
this.closeOverlay();
|
|
281
|
+
this.open = false;
|
|
288
282
|
}, POINTERLEAVE_TIMEOUT);
|
|
289
283
|
}
|
|
290
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* When there is a `change` event in the submenu for this item
|
|
287
|
+
* then we "click" this item to cascade the selection up the
|
|
288
|
+
* menu tree allowing all submenus between the initial selection
|
|
289
|
+
* and the root of the tree to have their selection changes and
|
|
290
|
+
* be closed.
|
|
291
|
+
*/
|
|
292
|
+
handleSubmenuChange(event) {
|
|
293
|
+
var _a;
|
|
294
|
+
event.stopPropagation();
|
|
295
|
+
(_a = this.menuData.selectionRoot) == null ? void 0 : _a.selectOrToggleItem(this);
|
|
296
|
+
}
|
|
297
|
+
handleSubmenuPointerenter() {
|
|
298
|
+
this.recentlyLeftChild = true;
|
|
299
|
+
}
|
|
300
|
+
async handleSubmenuPointerleave() {
|
|
301
|
+
requestAnimationFrame(() => {
|
|
302
|
+
this.recentlyLeftChild = false;
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
handleSubmenuOpen(event) {
|
|
306
|
+
this.focused = false;
|
|
307
|
+
const parentOverlay = event.composedPath().find((el) => {
|
|
308
|
+
return el !== this.overlayElement && el.localName === "sp-overlay";
|
|
309
|
+
});
|
|
310
|
+
this.overlayElement.parentOverlayToForceClose = parentOverlay;
|
|
311
|
+
}
|
|
312
|
+
cleanup() {
|
|
313
|
+
this.open = false;
|
|
314
|
+
this.active = false;
|
|
315
|
+
}
|
|
291
316
|
async openOverlay() {
|
|
292
317
|
if (!this.hasSubmenu || this.open || this.disabled) {
|
|
293
318
|
return;
|
|
294
319
|
}
|
|
295
320
|
this.open = true;
|
|
296
321
|
this.active = true;
|
|
297
|
-
|
|
298
|
-
'slot[name="submenu"]'
|
|
299
|
-
).assignedElements()[0];
|
|
300
|
-
submenu.addEventListener(
|
|
301
|
-
"pointerenter",
|
|
302
|
-
this.handleSubmenuPointerenter
|
|
303
|
-
);
|
|
304
|
-
submenu.addEventListener("change", this.handleSubmenuChange);
|
|
305
|
-
const popover = document.createElement("sp-popover");
|
|
306
|
-
const returnSubmenu = reparentChildren([submenu], popover, {
|
|
307
|
-
position: "beforeend",
|
|
308
|
-
prepareCallback: (el) => {
|
|
309
|
-
const slotName = el.slot;
|
|
310
|
-
el.tabIndex = 0;
|
|
311
|
-
el.removeAttribute("slot");
|
|
312
|
-
el.isSubmenu = true;
|
|
313
|
-
return (el2) => {
|
|
314
|
-
el2.tabIndex = -1;
|
|
315
|
-
el2.slot = slotName;
|
|
316
|
-
el2.isSubmenu = false;
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
const closeOverlay = openOverlay(this, "click", popover, {
|
|
321
|
-
placement: this.isLTR ? "right-start" : "left-start",
|
|
322
|
-
receivesFocus: "auto",
|
|
323
|
-
root: this.menuData.focusRoot
|
|
324
|
-
});
|
|
325
|
-
const closeSubmenu = async () => {
|
|
326
|
-
delete this.closeOverlay;
|
|
327
|
-
(await closeOverlay)();
|
|
328
|
-
};
|
|
329
|
-
this.closeOverlay = closeSubmenu;
|
|
330
|
-
const cleanup = (event) => {
|
|
331
|
-
event.stopPropagation();
|
|
332
|
-
delete this.closeOverlay;
|
|
333
|
-
returnSubmenu();
|
|
334
|
-
this.open = false;
|
|
335
|
-
this.active = false;
|
|
336
|
-
};
|
|
337
|
-
this.addEventListener("sp-closed", cleanup, {
|
|
322
|
+
this.addEventListener("sp-closed", this.cleanup, {
|
|
338
323
|
once: true
|
|
339
324
|
});
|
|
340
|
-
popover.addEventListener("change", closeSubmenu);
|
|
341
325
|
}
|
|
342
326
|
updateAriaSelected() {
|
|
343
327
|
const role = this.getAttribute("role");
|
|
@@ -355,12 +339,14 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
355
339
|
this.updateAriaSelected();
|
|
356
340
|
}
|
|
357
341
|
updated(changes) {
|
|
342
|
+
var _a;
|
|
358
343
|
super.updated(changes);
|
|
359
|
-
if (changes.has("label")) {
|
|
344
|
+
if (changes.has("label") && (this.label || typeof changes.get("label") !== "undefined")) {
|
|
360
345
|
this.setAttribute("aria-label", this.label || "");
|
|
361
346
|
}
|
|
362
|
-
if (changes.has("active")) {
|
|
347
|
+
if (changes.has("active") && (this.active || typeof changes.get("active") !== "undefined")) {
|
|
363
348
|
if (this.active) {
|
|
349
|
+
(_a = this.menuData.selectionRoot) == null ? void 0 : _a.closeDescendentOverlays();
|
|
364
350
|
this.addEventListener("pointerup", this.handleRemoveActive);
|
|
365
351
|
this.addEventListener("pointerleave", this.handleRemoveActive);
|
|
366
352
|
this.addEventListener("pointercancel", this.handleRemoveActive);
|
|
@@ -383,11 +369,12 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
383
369
|
if (changes.has("selected")) {
|
|
384
370
|
this.updateAriaSelected();
|
|
385
371
|
}
|
|
386
|
-
if (changes.has("hasSubmenu")) {
|
|
372
|
+
if (changes.has("hasSubmenu") && (this.hasSubmenu || typeof changes.get("hasSubmenu") !== "undefined")) {
|
|
387
373
|
if (this.hasSubmenu) {
|
|
388
374
|
this.addEventListener("click", this.handleSubmenuClick);
|
|
389
375
|
this.addEventListener("pointerenter", this.handlePointerenter);
|
|
390
376
|
this.addEventListener("pointerleave", this.handlePointerleave);
|
|
377
|
+
this.addEventListener("sp-opened", this.handleSubmenuOpen);
|
|
391
378
|
} else if (!this.closeOverlay) {
|
|
392
379
|
this.removeEventListener("click", this.handleSubmenuClick);
|
|
393
380
|
this.removeEventListener(
|
|
@@ -398,39 +385,31 @@ const _MenuItem = class extends LikeAnchor(Focusable) {
|
|
|
398
385
|
"pointerleave",
|
|
399
386
|
this.handlePointerleave
|
|
400
387
|
);
|
|
388
|
+
this.removeEventListener("sp-opened", this.handleSubmenuOpen);
|
|
401
389
|
}
|
|
402
390
|
}
|
|
403
391
|
}
|
|
404
392
|
connectedCallback() {
|
|
405
393
|
super.connectedCallback();
|
|
406
|
-
this.
|
|
407
|
-
if (this.isInSubmenu) {
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
addOrUpdateEvent.reset(this);
|
|
411
|
-
this.dispatchEvent(addOrUpdateEvent);
|
|
412
|
-
this._parentElement = this.parentElement;
|
|
394
|
+
this.triggerUpdate();
|
|
413
395
|
}
|
|
414
396
|
disconnectedCallback() {
|
|
415
|
-
|
|
416
|
-
removeEvent.reset(this);
|
|
417
|
-
if (!this.isInSubmenu) {
|
|
418
|
-
(_a = this._parentElement) == null ? void 0 : _a.dispatchEvent(removeEvent);
|
|
419
|
-
}
|
|
420
|
-
this.isInSubmenu = false;
|
|
397
|
+
this.menuData.cleanupSteps.forEach((removal) => removal(this));
|
|
421
398
|
super.disconnectedCallback();
|
|
422
399
|
}
|
|
423
400
|
async triggerUpdate() {
|
|
424
|
-
if (this.
|
|
401
|
+
if (this.willDispatchUpdate) {
|
|
425
402
|
return;
|
|
426
403
|
}
|
|
404
|
+
this.willDispatchUpdate = true;
|
|
427
405
|
await new Promise((ready) => requestAnimationFrame(ready));
|
|
428
|
-
|
|
429
|
-
this.dispatchEvent(addOrUpdateEvent);
|
|
406
|
+
this.dispatchUpdate();
|
|
430
407
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
408
|
+
dispatchUpdate() {
|
|
409
|
+
this.dispatchEvent(new MenuItemAddedOrUpdatedEvent(this));
|
|
410
|
+
this.willDispatchUpdate = false;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
434
413
|
__decorateClass([
|
|
435
414
|
property({ type: Boolean, reflect: true })
|
|
436
415
|
], MenuItem.prototype, "active", 2);
|
|
@@ -460,6 +439,9 @@ __decorateClass([
|
|
|
460
439
|
query(".anchor")
|
|
461
440
|
], MenuItem.prototype, "anchorElement", 2);
|
|
462
441
|
__decorateClass([
|
|
463
|
-
|
|
442
|
+
query("sp-overlay")
|
|
443
|
+
], MenuItem.prototype, "overlayElement", 2);
|
|
444
|
+
__decorateClass([
|
|
445
|
+
property({ type: Boolean, reflect: true })
|
|
464
446
|
], MenuItem.prototype, "open", 2);
|
|
465
447
|
//# sourceMappingURL=MenuItem.dev.js.map
|