@spectrum-web-components/menu 1.0.1 → 1.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.
Files changed (46) hide show
  1. package/package.json +11 -12
  2. package/LICENSE +0 -201
  3. package/stories/index.js +0 -82
  4. package/stories/index.js.map +0 -7
  5. package/stories/menu-divider.stories.js +0 -32
  6. package/stories/menu-divider.stories.js.map +0 -7
  7. package/stories/menu-group.stories.js +0 -144
  8. package/stories/menu-group.stories.js.map +0 -7
  9. package/stories/menu-item.disconnected.stories.js +0 -176
  10. package/stories/menu-item.disconnected.stories.js.map +0 -7
  11. package/stories/menu-item.stories.js +0 -73
  12. package/stories/menu-item.stories.js.map +0 -7
  13. package/stories/menu-sizes.stories.js +0 -11
  14. package/stories/menu-sizes.stories.js.map +0 -7
  15. package/stories/menu.stories.js +0 -403
  16. package/stories/menu.stories.js.map +0 -7
  17. package/stories/submenu.stories.js +0 -346
  18. package/stories/submenu.stories.js.map +0 -7
  19. package/test/benchmark/test-basic.js +0 -24
  20. package/test/benchmark/test-basic.js.map +0 -7
  21. package/test/menu-divider.test-vrt.js +0 -5
  22. package/test/menu-divider.test-vrt.js.map +0 -7
  23. package/test/menu-group.test-vrt.js +0 -5
  24. package/test/menu-group.test-vrt.js.map +0 -7
  25. package/test/menu-group.test.js +0 -405
  26. package/test/menu-group.test.js.map +0 -7
  27. package/test/menu-item.disconnected.test-vrt.js +0 -5
  28. package/test/menu-item.disconnected.test-vrt.js.map +0 -7
  29. package/test/menu-item.test-vrt.js +0 -5
  30. package/test/menu-item.test-vrt.js.map +0 -7
  31. package/test/menu-item.test.js +0 -189
  32. package/test/menu-item.test.js.map +0 -7
  33. package/test/menu-memory.test.js +0 -5
  34. package/test/menu-memory.test.js.map +0 -7
  35. package/test/menu-selects.test.js +0 -530
  36. package/test/menu-selects.test.js.map +0 -7
  37. package/test/menu-sizes.test-vrt.js +0 -5
  38. package/test/menu-sizes.test-vrt.js.map +0 -7
  39. package/test/menu.test-vrt.js +0 -5
  40. package/test/menu.test-vrt.js.map +0 -7
  41. package/test/menu.test.js +0 -559
  42. package/test/menu.test.js.map +0 -7
  43. package/test/submenu.test-vrt.js +0 -5
  44. package/test/submenu.test-vrt.js.map +0 -7
  45. package/test/submenu.test.js +0 -970
  46. package/test/submenu.test.js.map +0 -7
@@ -1,970 +0,0 @@
1
- "use strict";
2
- import "@spectrum-web-components/menu/sp-menu.js";
3
- import "@spectrum-web-components/menu/sp-menu-item.js";
4
- import {
5
- aTimeout,
6
- elementUpdated,
7
- expect,
8
- html,
9
- nextFrame,
10
- oneEvent
11
- } from "@open-wc/testing";
12
- import { fixture } from "../../../test/testing-helpers.js";
13
- import { sendMouse } from "../../../test/plugins/browser.js";
14
- import { spy } from "sinon";
15
- import { sendKeys } from "@web/test-runner-commands";
16
- import "@spectrum-web-components/action-menu/sp-action-menu.js";
17
- import "@spectrum-web-components/menu/sp-menu-group.js";
18
- import "@spectrum-web-components/overlay/sp-overlay.js";
19
- import "@spectrum-web-components/icons-workflow/icons/sp-icon-show-menu.js";
20
- import { slottableRequest } from "@spectrum-web-components/overlay/src/slottable-request-directive.js";
21
- const selectsWithKeyboardData = [
22
- {
23
- dir: "ltr",
24
- openKey: "ArrowRight",
25
- closeKey: "ArrowLeft"
26
- },
27
- {
28
- dir: "rtl",
29
- openKey: "ArrowLeft",
30
- closeKey: "ArrowRight"
31
- }
32
- ];
33
- describe("Submenu", () => {
34
- function selectWithPointer() {
35
- it("with pointer", async function() {
36
- const rootItemBoundingRect = this.rootItem.getBoundingClientRect();
37
- expect(this.rootItem.open).to.be.false;
38
- const opened = oneEvent(this.rootItem, "sp-opened");
39
- await sendMouse({
40
- steps: [
41
- {
42
- type: "move",
43
- position: [
44
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
45
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
46
- ]
47
- }
48
- ]
49
- });
50
- await opened;
51
- expect(this.rootItem.open).to.be.true;
52
- const item2 = document.querySelector(".submenu-item-2");
53
- const item2BoundingRect = item2.getBoundingClientRect();
54
- const closed = oneEvent(this.rootItem, "sp-closed");
55
- await sendMouse({
56
- steps: [
57
- {
58
- type: "click",
59
- position: [
60
- item2BoundingRect.left + item2BoundingRect.width / 2,
61
- item2BoundingRect.top + item2BoundingRect.height / 2
62
- ]
63
- }
64
- ]
65
- });
66
- await closed;
67
- expect(
68
- this.submenuChanged.withArgs("Two").calledOnce,
69
- `submenu changed ${this.submenuChanged.callCount} times`
70
- ).to.be.true;
71
- expect(
72
- this.rootChanged.withArgs("Has submenu").calledOnce,
73
- "root changed"
74
- ).to.be.true;
75
- });
76
- }
77
- function selectsWithKeyboard(testData) {
78
- it(`with keyboard: ${testData.dir}`, async function() {
79
- var _a, _b;
80
- this.el.parentElement.dir = testData.dir;
81
- await elementUpdated(this.el);
82
- expect(this.rootItem.open).to.be.false;
83
- const input = document.createElement("input");
84
- this.el.insertAdjacentElement("beforebegin", input);
85
- input.focus();
86
- await sendKeys({
87
- press: "Tab"
88
- });
89
- await sendKeys({
90
- press: "ArrowDown"
91
- });
92
- await elementUpdated(this.rootItem);
93
- expect(this.rootItem.focused).to.be.true;
94
- let opened = oneEvent(this.rootItem, "sp-opened");
95
- await sendKeys({
96
- press: testData.openKey
97
- });
98
- await opened;
99
- let submenu = this.el.querySelector('[slot="submenu"]');
100
- let submenuItem = this.el.querySelector(
101
- ".submenu-item-2"
102
- );
103
- expect(this.rootItem.open).to.be.true;
104
- expect(
105
- submenu === document.activeElement,
106
- `${(_a = document.activeElement) == null ? void 0 : _a.id}`
107
- ).to.be.true;
108
- let closed = oneEvent(this.rootItem, "sp-closed");
109
- await sendKeys({
110
- press: testData.closeKey
111
- });
112
- await closed;
113
- expect(this.rootItem.open).to.be.false;
114
- expect(
115
- this.el === document.activeElement,
116
- `${(_b = document.activeElement) == null ? void 0 : _b.id}`
117
- ).to.be.true;
118
- opened = oneEvent(this.rootItem, "sp-opened");
119
- await sendKeys({
120
- press: testData.openKey
121
- });
122
- await opened;
123
- submenu = this.el.querySelector('[slot="submenu"]');
124
- submenuItem = this.el.querySelector(".submenu-item-2");
125
- expect(this.rootItem.open).to.be.true;
126
- await sendKeys({
127
- press: "ArrowDown"
128
- });
129
- await elementUpdated(submenu);
130
- await elementUpdated(submenuItem);
131
- expect(submenu.getAttribute("aria-activedescendant")).to.equal(
132
- submenuItem.id
133
- );
134
- closed = oneEvent(this.rootItem, "sp-closed");
135
- await sendKeys({
136
- press: "Enter"
137
- });
138
- await closed;
139
- expect(this.submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
140
- expect(this.rootChanged.called, "root has changed").to.be.true;
141
- expect(
142
- this.rootChanged.calledWith("Has submenu"),
143
- "root specifically changed"
144
- ).to.be.true;
145
- });
146
- }
147
- function returnsFocusToRootWhenClosingSubmenu() {
148
- it("returns visible focus when submenu closed", async function() {
149
- var _a;
150
- const input = document.createElement("input");
151
- this.el.insertAdjacentElement("beforebegin", input);
152
- input.focus();
153
- await sendKeys({
154
- press: "Tab"
155
- });
156
- await elementUpdated(this.el);
157
- await nextFrame();
158
- await nextFrame();
159
- await sendKeys({
160
- press: "ArrowDown"
161
- });
162
- await elementUpdated(this.el);
163
- await nextFrame();
164
- await nextFrame();
165
- expect(this.rootItem.active, "not active").to.be.false;
166
- expect(
167
- this.rootItem.focused,
168
- `focused: ${(_a = document.activeElement) == null ? void 0 : _a.localName}`
169
- ).to.be.true;
170
- expect(this.rootItem.open, "not open").to.be.false;
171
- const opened = oneEvent(this.rootItem, "sp-opened");
172
- await sendKeys({
173
- press: "ArrowRight"
174
- });
175
- await opened;
176
- expect(this.rootItem.active).to.be.true;
177
- expect(this.rootItem.focused).to.be.false;
178
- expect(this.rootItem.open).to.be.true;
179
- await sendKeys({
180
- press: "ArrowDown"
181
- });
182
- expect(this.rootItem.active).to.be.true;
183
- expect(this.rootItem.focused).to.be.false;
184
- expect(this.rootItem.open).to.be.true;
185
- const closed = oneEvent(this.rootItem, "sp-closed");
186
- await sendKeys({
187
- press: "ArrowLeft"
188
- });
189
- await closed;
190
- expect(this.rootItem.active).to.be.false;
191
- expect(this.rootItem.focused).to.be.true;
192
- expect(this.rootItem.open).to.be.false;
193
- });
194
- }
195
- function closesOnPointerLeave() {
196
- it("closes on `pointerleave`", async function() {
197
- const rootItemBoundingRect = this.rootItem.getBoundingClientRect();
198
- expect(this.rootItem.open).to.be.false;
199
- const opened = oneEvent(this.rootItem, "sp-opened");
200
- await sendMouse({
201
- steps: [
202
- {
203
- type: "move",
204
- position: [
205
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
206
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
207
- ]
208
- }
209
- ]
210
- });
211
- await opened;
212
- expect(this.rootItem.open).to.be.true;
213
- const closed = oneEvent(this.rootItem, "sp-closed");
214
- await sendMouse({
215
- steps: [
216
- {
217
- type: "move",
218
- position: [
219
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
220
- rootItemBoundingRect.top + rootItemBoundingRect.height * 2
221
- ]
222
- }
223
- ]
224
- });
225
- await closed;
226
- expect(this.rootItem.open).to.be.false;
227
- });
228
- }
229
- function persistsThroughMouseLeaveAndReturn() {
230
- it("stays open when mousing off menu item and back again", async function() {
231
- const rootItemBoundingRect = this.rootItem.getBoundingClientRect();
232
- expect(this.rootItem.open).to.be.false;
233
- const opened = oneEvent(this.rootItem, "sp-opened");
234
- await sendMouse({
235
- steps: [
236
- {
237
- type: "move",
238
- position: [
239
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
240
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
241
- ]
242
- }
243
- ]
244
- });
245
- await sendMouse({
246
- steps: [
247
- {
248
- type: "move",
249
- position: [
250
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
251
- rootItemBoundingRect.top + rootItemBoundingRect.height * 2
252
- ]
253
- }
254
- ]
255
- });
256
- await sendMouse({
257
- steps: [
258
- {
259
- type: "move",
260
- position: [
261
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
262
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
263
- ]
264
- }
265
- ]
266
- });
267
- await opened;
268
- expect(this.rootItem.open).to.be.true;
269
- const closed = oneEvent(this.rootItem, "sp-closed");
270
- await sendMouse({
271
- steps: [
272
- {
273
- type: "move",
274
- position: [
275
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
276
- rootItemBoundingRect.top + rootItemBoundingRect.height * 2
277
- ]
278
- }
279
- ]
280
- });
281
- await closed;
282
- });
283
- }
284
- function doesNotOpenWhenDisabled() {
285
- it("does not open when disabled", async function() {
286
- this.rootItem.disabled = true;
287
- await elementUpdated(this.rootItem);
288
- const rootItemBoundingRect = this.rootItem.getBoundingClientRect();
289
- expect(this.rootItem.open).to.be.false;
290
- await sendMouse({
291
- steps: [
292
- {
293
- type: "move",
294
- position: [
295
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
296
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
297
- ]
298
- }
299
- ]
300
- });
301
- await new Promise((r) => setTimeout(r, 200));
302
- expect(this.rootItem.open).to.be.false;
303
- });
304
- }
305
- function persistsWhenMovingBetweenItemAndSubmenu() {
306
- it("stays open when mousing between menu item and submenu", async function() {
307
- const rootItemBoundingRect = this.rootItem.getBoundingClientRect();
308
- expect(this.rootItem.open).to.be.false;
309
- const opened = oneEvent(this.rootItem, "sp-opened");
310
- await sendMouse({
311
- steps: [
312
- {
313
- type: "move",
314
- position: [
315
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
316
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
317
- ]
318
- }
319
- ]
320
- });
321
- await opened;
322
- await nextFrame();
323
- await nextFrame();
324
- const subItem = this.el.querySelector(
325
- ".submenu-item-2"
326
- );
327
- const clickSpy = spy();
328
- subItem.addEventListener("click", () => clickSpy());
329
- const subItemBoundingRect = subItem.getBoundingClientRect();
330
- expect(this.rootItem.open).to.be.true;
331
- await sendMouse({
332
- steps: [
333
- {
334
- type: "move",
335
- position: [
336
- subItemBoundingRect.left + subItemBoundingRect.width / 2,
337
- subItemBoundingRect.top + subItemBoundingRect.height / 2
338
- ]
339
- }
340
- ]
341
- });
342
- expect(this.rootItem.open).to.be.true;
343
- await aTimeout(150);
344
- expect(this.rootItem.open).to.be.true;
345
- const closed = oneEvent(this.rootItem, "sp-closed");
346
- await sendMouse({
347
- steps: [
348
- {
349
- type: "click",
350
- position: [
351
- subItemBoundingRect.left + subItemBoundingRect.width / 2,
352
- subItemBoundingRect.top + subItemBoundingRect.height / 2
353
- ]
354
- }
355
- ]
356
- });
357
- await closed;
358
- expect(clickSpy.callCount).to.equal(1);
359
- });
360
- }
361
- function continuesToOpenWhenMovingBetweenItemAndSubmenu() {
362
- it("continues to open when mousing between menu item and submenu", async function() {
363
- const rootItemBoundingRect = this.rootItem.getBoundingClientRect();
364
- expect(this.rootItem.open).to.be.false;
365
- const opened = oneEvent(this.rootItem, "sp-opened");
366
- await sendMouse({
367
- steps: [
368
- {
369
- type: "move",
370
- position: [
371
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
372
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
373
- ]
374
- }
375
- ]
376
- });
377
- await nextFrame();
378
- await nextFrame();
379
- await nextFrame();
380
- await nextFrame();
381
- await nextFrame();
382
- await nextFrame();
383
- await nextFrame();
384
- await nextFrame();
385
- const subItem = this.el.querySelector(
386
- ".submenu-item-2"
387
- );
388
- const clickSpy = spy();
389
- subItem.addEventListener("click", () => clickSpy());
390
- const subItemBoundingRect = subItem.getBoundingClientRect();
391
- await sendMouse({
392
- steps: [
393
- {
394
- type: "move",
395
- position: [
396
- subItemBoundingRect.left + subItemBoundingRect.width / 2,
397
- subItemBoundingRect.top + subItemBoundingRect.height / 2
398
- ]
399
- }
400
- ]
401
- });
402
- await opened;
403
- expect(this.rootItem.open).to.be.true;
404
- await aTimeout(150);
405
- expect(this.rootItem.open).to.be.true;
406
- const closed = oneEvent(this.rootItem, "sp-closed");
407
- await sendMouse({
408
- steps: [
409
- {
410
- type: "click",
411
- position: [
412
- subItemBoundingRect.left + subItemBoundingRect.width / 2,
413
- subItemBoundingRect.top + subItemBoundingRect.height / 2
414
- ]
415
- }
416
- ]
417
- });
418
- await closed;
419
- expect(clickSpy.callCount).to.equal(1);
420
- });
421
- }
422
- const renderSubmenu = () => html`
423
- <sp-menu-item class="submenu-item-1">One</sp-menu-item>
424
- <sp-menu-item class="submenu-item-2">Two</sp-menu-item>
425
- <sp-menu-item class="submenu-item-3">Three</sp-menu-item>
426
- `;
427
- describe("static DOM", () => {
428
- beforeEach(async function() {
429
- this.rootChanged = spy();
430
- this.submenuChanged = spy();
431
- this.el = await fixture(html`
432
- <sp-menu
433
- @change=${(event) => {
434
- this.rootChanged(event.target.value);
435
- }}
436
- >
437
- <sp-menu-item>No submenu</sp-menu-item>
438
- <sp-menu-item class="root">
439
- Has submenu
440
- <sp-menu
441
- slot="submenu"
442
- @change=${(event) => {
443
- this.submenuChanged(event.target.value);
444
- }}
445
- >
446
- ${renderSubmenu()}
447
- </sp-menu>
448
- </sp-menu-item>
449
- </sp-menu>
450
- `);
451
- await elementUpdated(this.el);
452
- this.rootItem = this.el.querySelector(".root");
453
- await elementUpdated(this.rootItem);
454
- });
455
- describe.skip("selects", () => {
456
- selectWithPointer();
457
- selectsWithKeyboardData.map((testData) => {
458
- selectsWithKeyboard(testData);
459
- });
460
- });
461
- closesOnPointerLeave();
462
- returnsFocusToRootWhenClosingSubmenu();
463
- persistsThroughMouseLeaveAndReturn();
464
- doesNotOpenWhenDisabled();
465
- persistsWhenMovingBetweenItemAndSubmenu();
466
- continuesToOpenWhenMovingBetweenItemAndSubmenu();
467
- });
468
- describe("directive", () => {
469
- beforeEach(async function() {
470
- this.rootChanged = spy();
471
- this.submenuChanged = spy();
472
- this.el = await fixture(html`
473
- <sp-menu
474
- @change=${(event) => {
475
- this.rootChanged(event.target.value);
476
- }}
477
- >
478
- <sp-menu-item>No submenu</sp-menu-item>
479
- <sp-menu-item class="root">
480
- Has submenu
481
- <sp-menu
482
- slot="submenu"
483
- @change=${(event) => {
484
- this.submenuChanged(event.target.value);
485
- }}
486
- ${slottableRequest(renderSubmenu)}
487
- ></sp-menu>
488
- </sp-menu-item>
489
- </sp-menu>
490
- `);
491
- await elementUpdated(this.el);
492
- this.rootItem = this.el.querySelector(".root");
493
- await elementUpdated(this.rootItem);
494
- });
495
- describe("selects", () => {
496
- selectWithPointer();
497
- selectsWithKeyboardData.map((testData) => {
498
- selectsWithKeyboard(testData);
499
- });
500
- });
501
- closesOnPointerLeave();
502
- returnsFocusToRootWhenClosingSubmenu();
503
- persistsThroughMouseLeaveAndReturn();
504
- doesNotOpenWhenDisabled();
505
- persistsWhenMovingBetweenItemAndSubmenu();
506
- continuesToOpenWhenMovingBetweenItemAndSubmenu();
507
- });
508
- it("closes deep tree on selection", async function() {
509
- const rootChanged = spy();
510
- const submenuChanged = spy();
511
- const subSubmenuChanged = spy();
512
- const el = await fixture(html`
513
- <sp-menu
514
- @change=${(event) => {
515
- rootChanged(event.target.value);
516
- }}
517
- >
518
- <sp-menu-item class="root">
519
- Has submenu
520
- <sp-menu
521
- slot="submenu"
522
- @change=${(event) => {
523
- submenuChanged(event.target.value);
524
- }}
525
- >
526
- <sp-menu-item class="submenu-item-1">One</sp-menu-item>
527
- <sp-menu-item class="submenu-item-2">
528
- Two
529
- <sp-menu
530
- slot="submenu"
531
- @change=${(event) => {
532
- subSubmenuChanged(event.target.value);
533
- }}
534
- >
535
- <sp-menu-item class="sub-submenu-item-1">
536
- A
537
- </sp-menu-item>
538
- <sp-menu-item class="sub-submenu-item-2">
539
- B
540
- </sp-menu-item>
541
- <sp-menu-item class="sub-submenu-item-3">
542
- C
543
- </sp-menu-item>
544
- </sp-menu>
545
- </sp-menu-item>
546
- <sp-menu-item class="submenu-item-3">
547
- Three
548
- </sp-menu-item>
549
- </sp-menu>
550
- </sp-menu-item>
551
- </sp-menu>
552
- `);
553
- const rootItem = el.querySelector(".root");
554
- const rootItemBoundingRect = rootItem.getBoundingClientRect();
555
- const item2 = document.querySelector(".submenu-item-2");
556
- const itemC = document.querySelector(".sub-submenu-item-3");
557
- expect(rootItem.open).to.be.false;
558
- let opened = oneEvent(rootItem, "sp-opened");
559
- await sendMouse({
560
- steps: [
561
- {
562
- type: "move",
563
- position: [
564
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
565
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
566
- ]
567
- }
568
- ]
569
- });
570
- await opened;
571
- expect(rootItem.open).to.be.true;
572
- const item2BoundingRect = item2.getBoundingClientRect();
573
- opened = oneEvent(item2, "sp-opened");
574
- await sendMouse({
575
- steps: [
576
- {
577
- type: "move",
578
- position: [
579
- item2BoundingRect.left + item2BoundingRect.width / 2,
580
- item2BoundingRect.top + item2BoundingRect.height / 2
581
- ]
582
- }
583
- ]
584
- });
585
- await opened;
586
- expect(item2.open).to.be.true;
587
- const closed = oneEvent(rootItem, "sp-closed");
588
- const itemCBoundingRect = itemC.getBoundingClientRect();
589
- await sendMouse({
590
- steps: [
591
- {
592
- type: "click",
593
- position: [
594
- itemCBoundingRect.left + itemCBoundingRect.width / 2,
595
- itemCBoundingRect.top + itemCBoundingRect.height / 2
596
- ]
597
- }
598
- ]
599
- });
600
- await closed;
601
- expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
602
- expect(submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
603
- expect(subSubmenuChanged.calledWith("C"), "sub submenu changed").to.be.true;
604
- });
605
- it("closes all decendent submenus when closing a ancestor menu", async () => {
606
- const el = await fixture(html`
607
- <sp-action-menu label="Closing ancestors will close submenus">
608
- <sp-icon-show-menu slot="icon"></sp-icon-show-menu>
609
- <sp-menu-group role="none" id="group">
610
- <span slot="header">New York</span>
611
- <sp-menu-item>Bronx</sp-menu-item>
612
- <sp-menu-item id="submenu-item-1">
613
- Brooklyn
614
- <sp-menu slot="submenu" id="submenu-1">
615
- <sp-menu-item id="submenu-item-2">
616
- Ft. Greene
617
- <sp-menu slot="submenu" id="submenu-2">
618
- <sp-menu-item>S. Oxford St</sp-menu-item>
619
- <sp-menu-item>S. Portland Ave</sp-menu-item>
620
- <sp-menu-item>S. Elliot Pl</sp-menu-item>
621
- </sp-menu>
622
- </sp-menu-item>
623
- <sp-menu-item disabled>Park Slope</sp-menu-item>
624
- <sp-menu-item>Williamsburg</sp-menu-item>
625
- </sp-menu>
626
- </sp-menu-item>
627
- <sp-menu-item id="submenu-item-3">
628
- Manhattan
629
- <sp-menu slot="submenu" id="submenu-3">
630
- <sp-menu-item disabled>SoHo</sp-menu-item>
631
- <sp-menu-item>
632
- Union Square
633
- <sp-menu slot="submenu">
634
- <sp-menu-item>14th St</sp-menu-item>
635
- <sp-menu-item>Broadway</sp-menu-item>
636
- <sp-menu-item>Park Ave</sp-menu-item>
637
- </sp-menu>
638
- </sp-menu-item>
639
- <sp-menu-item>Upper East Side</sp-menu-item>
640
- </sp-menu>
641
- </sp-menu-item>
642
- </sp-menu-group>
643
- </sp-action-menu>
644
- `);
645
- const rootMenu1 = el.querySelector("#submenu-item-1");
646
- const rootMenu2 = el.querySelector("#submenu-item-3");
647
- const childMenu2 = el.querySelector("#submenu-item-2");
648
- expect(el.open).to.be.false;
649
- let opened = oneEvent(el, "sp-opened");
650
- el.click();
651
- await opened;
652
- expect(el.open).to.be.true;
653
- opened = oneEvent(rootMenu1, "sp-opened");
654
- rootMenu1.dispatchEvent(
655
- new PointerEvent("pointerenter", { bubbles: true })
656
- );
657
- await opened;
658
- expect(rootMenu1.open).to.be.true;
659
- opened = oneEvent(childMenu2, "sp-opened");
660
- childMenu2.dispatchEvent(
661
- new PointerEvent("pointerenter", { bubbles: true })
662
- );
663
- await opened;
664
- expect(childMenu2.open).to.be.true;
665
- const childMenu2Closed = oneEvent(childMenu2, "sp-closed");
666
- const rootMenu1Closed = oneEvent(rootMenu1, "sp-closed");
667
- const rootMenu2Opened = oneEvent(rootMenu2, "sp-opened");
668
- rootMenu2.dispatchEvent(
669
- new PointerEvent("pointerenter", { bubbles: true })
670
- );
671
- await childMenu2Closed;
672
- await rootMenu1Closed;
673
- await rootMenu2Opened;
674
- });
675
- describe("deep tree", () => {
676
- beforeEach(async function() {
677
- this.el = await fixture(html`
678
- <sp-action-menu label="Deep submenu tree">
679
- <sp-icon-show-menu slot="icon"></sp-icon-show-menu>
680
- <sp-menu-group role="none">
681
- <span slot="header">New York</span>
682
- <sp-menu-item id="no-submenu">Bronx</sp-menu-item>
683
- <sp-menu-item id="submenu-item-1">
684
- Brooklyn
685
- <sp-menu slot="submenu">
686
- <sp-menu-item id="submenu-item-2">
687
- Ft. Greene
688
- <sp-menu slot="submenu">
689
- <sp-menu-item>
690
- S. Oxford St
691
- </sp-menu-item>
692
- <sp-menu-item>
693
- S. Portland Ave
694
- </sp-menu-item>
695
- <sp-menu-item>
696
- S. Elliot Pl
697
- </sp-menu-item>
698
- </sp-menu>
699
- </sp-menu-item>
700
- <sp-menu-item disabled>Park Slope</sp-menu-item>
701
- <sp-menu-item id="ancestor-item">
702
- Williamsburg
703
- </sp-menu-item>
704
- </sp-menu>
705
- </sp-menu-item>
706
- <sp-menu-item id="submenu-item-3">
707
- Manhattan
708
- <sp-menu slot="submenu">
709
- <sp-menu-item disabled>SoHo</sp-menu-item>
710
- <sp-menu-item>
711
- Union Square
712
- <sp-menu slot="submenu">
713
- <sp-menu-item>14th St</sp-menu-item>
714
- <sp-menu-item>Broadway</sp-menu-item>
715
- <sp-menu-item>Park Ave</sp-menu-item>
716
- </sp-menu>
717
- </sp-menu-item>
718
- <sp-menu-item>Upper East Side</sp-menu-item>
719
- </sp-menu>
720
- </sp-menu-item>
721
- </sp-menu-group>
722
- </sp-action-menu>
723
- `);
724
- await nextFrame();
725
- await nextFrame();
726
- });
727
- it("closes back to the first overlay without a `root` when clicking away", async function() {
728
- const rootMenu1 = this.el.querySelector("#submenu-item-1");
729
- const childMenu2 = this.el.querySelector("#submenu-item-2");
730
- expect(this.el.open).to.be.false;
731
- let opened = oneEvent(this.el, "sp-opened");
732
- this.el.click();
733
- await opened;
734
- expect(this.el.open).to.be.true;
735
- opened = oneEvent(rootMenu1, "sp-opened");
736
- rootMenu1.dispatchEvent(
737
- new PointerEvent("pointerenter", { bubbles: true })
738
- );
739
- await opened;
740
- opened = oneEvent(childMenu2, "sp-opened");
741
- childMenu2.dispatchEvent(
742
- new PointerEvent("pointerenter", { bubbles: true })
743
- );
744
- await opened;
745
- const closed = Promise.all([
746
- oneEvent(childMenu2, "sp-closed"),
747
- oneEvent(rootMenu1, "sp-closed"),
748
- oneEvent(this.el, "sp-closed")
749
- ]);
750
- await sendMouse({
751
- steps: [
752
- {
753
- type: "click",
754
- position: [600, 5]
755
- }
756
- ]
757
- });
758
- await closed;
759
- });
760
- it("closes decendent menus when Menu Item in ancestor without a submenu is pointerentered", async function() {
761
- const rootMenu = this.el.querySelector(
762
- "#submenu-item-1"
763
- );
764
- const noSubmenu = this.el.querySelector("#no-submenu");
765
- expect(this.el.open).to.be.false;
766
- let opened = oneEvent(this.el, "sp-opened");
767
- this.el.click();
768
- await opened;
769
- expect(this.el.open).to.be.true;
770
- opened = oneEvent(rootMenu, "sp-opened");
771
- rootMenu.dispatchEvent(
772
- new PointerEvent("pointerenter", { bubbles: true })
773
- );
774
- await opened;
775
- const closed = oneEvent(rootMenu, "sp-closed");
776
- noSubmenu.dispatchEvent(
777
- new PointerEvent("pointerenter", { bubbles: true })
778
- );
779
- await closed;
780
- });
781
- it("closes decendent menus when Menu Item in ancestor is clicked", async function() {
782
- const rootMenu1 = this.el.querySelector(
783
- "#submenu-item-1"
784
- );
785
- const childMenu2 = this.el.querySelector(
786
- "#submenu-item-2"
787
- );
788
- const ancestorItem = this.el.querySelector(
789
- "#ancestor-item"
790
- );
791
- expect(this.el.open).to.be.false;
792
- let opened = oneEvent(this.el, "sp-opened");
793
- this.el.click();
794
- await opened;
795
- expect(this.el.open).to.be.true;
796
- opened = oneEvent(rootMenu1, "sp-opened");
797
- rootMenu1.dispatchEvent(
798
- new PointerEvent("pointerenter", { bubbles: true })
799
- );
800
- await opened;
801
- opened = oneEvent(childMenu2, "sp-opened");
802
- childMenu2.dispatchEvent(
803
- new PointerEvent("pointerenter", { bubbles: true })
804
- );
805
- await opened;
806
- const closed = Promise.all([
807
- oneEvent(childMenu2, "sp-closed"),
808
- oneEvent(rootMenu1, "sp-closed"),
809
- oneEvent(this.el, "sp-closed")
810
- ]);
811
- const rect = ancestorItem.getBoundingClientRect();
812
- await sendMouse({
813
- steps: [
814
- {
815
- type: "click",
816
- position: [
817
- rect.left + rect.width / 2,
818
- rect.top + rect.height / 2
819
- ]
820
- }
821
- ]
822
- });
823
- await closed;
824
- });
825
- });
826
- it('cleans up submenus that close before they are "open"', async () => {
827
- if ("showPopover" in document.createElement("div")) {
828
- return;
829
- }
830
- await sendMouse({
831
- steps: [
832
- {
833
- type: "move",
834
- position: [1, 1]
835
- }
836
- ]
837
- });
838
- const el = await fixture(html`
839
- <sp-menu>
840
- <sp-menu-item class="root-1">
841
- Has submenu
842
- <sp-menu slot="submenu">${renderSubmenu()}</sp-menu>
843
- </sp-menu-item>
844
- <sp-menu-item class="root-2">
845
- Has submenu
846
- <sp-menu slot="submenu">${renderSubmenu()}</sp-menu>
847
- </sp-menu-item>
848
- </sp-menu>
849
- `);
850
- await elementUpdated(el);
851
- const rootItem1 = el.querySelector(".root-1");
852
- const rootItem2 = el.querySelector(".root-2");
853
- expect(rootItem1.open, "initially closed 1").to.be.false;
854
- expect(rootItem2.open, "initially closed 2").to.be.false;
855
- const rootItemBoundingRect1 = rootItem1.getBoundingClientRect();
856
- const rootItemBoundingRect2 = rootItem2.getBoundingClientRect();
857
- await sendMouse({
858
- steps: [
859
- {
860
- type: "move",
861
- position: [
862
- rootItemBoundingRect1.left + rootItemBoundingRect1.width / 2,
863
- rootItemBoundingRect1.top + rootItemBoundingRect1.height / 2
864
- ]
865
- }
866
- ]
867
- });
868
- await sendMouse({
869
- steps: [
870
- {
871
- type: "move",
872
- position: [
873
- rootItemBoundingRect2.left + rootItemBoundingRect2.width / 2,
874
- rootItemBoundingRect2.top + rootItemBoundingRect2.height / 2
875
- ]
876
- }
877
- ]
878
- });
879
- await sendMouse({
880
- steps: [
881
- {
882
- type: "move",
883
- position: [
884
- rootItemBoundingRect1.left + rootItemBoundingRect1.width / 2,
885
- rootItemBoundingRect1.top + rootItemBoundingRect1.height / 2
886
- ]
887
- }
888
- ]
889
- });
890
- await sendMouse({
891
- steps: [
892
- {
893
- type: "move",
894
- position: [
895
- rootItemBoundingRect2.left + rootItemBoundingRect2.width / 2,
896
- rootItemBoundingRect2.top + rootItemBoundingRect2.height / 2
897
- ]
898
- }
899
- ]
900
- });
901
- await nextFrame();
902
- await nextFrame();
903
- await nextFrame();
904
- await nextFrame();
905
- await nextFrame();
906
- await nextFrame();
907
- const closed = oneEvent(rootItem2, "sp-closed");
908
- await sendMouse({
909
- steps: [
910
- {
911
- type: "move",
912
- position: [
913
- rootItemBoundingRect2.left + rootItemBoundingRect2.width / 2,
914
- rootItemBoundingRect2.top + rootItemBoundingRect2.height * 2
915
- ]
916
- }
917
- ]
918
- });
919
- await closed;
920
- expect(rootItem1.open, "finally closed 1").to.be.false;
921
- expect(rootItem2.open, "finally closed 2").to.be.false;
922
- });
923
- it("allows using non-menu-item elements as the root of a submenu", async () => {
924
- var _a;
925
- const el = await fixture(html`
926
- <sp-menu>
927
- <sp-menu-item class="root">
928
- Has submenu
929
- <div role="menuitem" slot="submenu">
930
- <sp-menu-item class="submenu-1">One</sp-menu-item>
931
- <sp-menu-item>Two</sp-menu-item>
932
- <sp-menu-item>Three</sp-menu-item>
933
- </div
934
- ></div>
935
- </sp-menu-item>
936
- </sp-menu>
937
- `);
938
- await elementUpdated(el);
939
- const rootItem = el.querySelector(".root");
940
- const rootItemBoundingRect = rootItem.getBoundingClientRect();
941
- await sendMouse({
942
- steps: [
943
- {
944
- type: "move",
945
- position: [
946
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
947
- rootItemBoundingRect.top + rootItemBoundingRect.height / 2
948
- ]
949
- }
950
- ]
951
- });
952
- expect(rootItem.open).to.be.true;
953
- const firstSubMenuItemRect = (_a = el.querySelector(".submenu-1")) == null ? void 0 : _a.getBoundingClientRect();
954
- if (!firstSubMenuItemRect) {
955
- throw new Error("Submenu item not found");
956
- }
957
- await sendMouse({
958
- steps: [
959
- {
960
- type: "click",
961
- position: [
962
- firstSubMenuItemRect.left + firstSubMenuItemRect.width / 2,
963
- firstSubMenuItemRect.top + firstSubMenuItemRect.height / 2
964
- ]
965
- }
966
- ]
967
- });
968
- });
969
- });
970
- //# sourceMappingURL=submenu.test.js.map