@spectrum-web-components/menu 0.16.17 → 0.16.18-overlay.11

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.
@@ -2,6 +2,7 @@
2
2
  import "@spectrum-web-components/menu/sp-menu.js";
3
3
  import "@spectrum-web-components/menu/sp-menu-item.js";
4
4
  import {
5
+ aTimeout,
5
6
  elementUpdated,
6
7
  expect,
7
8
  fixture,
@@ -19,7 +20,40 @@ import "@spectrum-web-components/menu/sp-menu-group.js";
19
20
  import "@spectrum-web-components/icons-workflow/icons/sp-icon-show-menu.js";
20
21
  async function styledFixture(story, dir = "ltr") {
21
22
  const test = await fixture(html`
22
- <sp-theme dir=${dir} scale="medium" color="dark">${story}</sp-theme>
23
+ <sp-theme dir=${dir} scale="medium" color="dark">
24
+ ${story}
25
+ <style>
26
+ sp-theme {
27
+ --spectrum-global-animation-duration-100: 50ms;
28
+ --spectrum-global-animation-duration-200: 50ms;
29
+ --spectrum-global-animation-duration-300: 50ms;
30
+ --spectrum-global-animation-duration-400: 50ms;
31
+ --spectrum-global-animation-duration-500: 50ms;
32
+ --spectrum-global-animation-duration-600: 50ms;
33
+ --spectrum-global-animation-duration-700: 50ms;
34
+ --spectrum-global-animation-duration-800: 50ms;
35
+ --spectrum-global-animation-duration-900: 50ms;
36
+ --spectrum-global-animation-duration-1000: 50ms;
37
+ --spectrum-global-animation-duration-2000: 50ms;
38
+ --spectrum-global-animation-duration-4000: 50ms;
39
+ --spectrum-animation-duration-0: 50ms;
40
+ --spectrum-animation-duration-100: 50ms;
41
+ --spectrum-animation-duration-200: 50ms;
42
+ --spectrum-animation-duration-300: 50ms;
43
+ --spectrum-animation-duration-400: 50ms;
44
+ --spectrum-animation-duration-500: 50ms;
45
+ --spectrum-animation-duration-600: 50ms;
46
+ --spectrum-animation-duration-700: 50ms;
47
+ --spectrum-animation-duration-800: 50ms;
48
+ --spectrum-animation-duration-900: 50ms;
49
+ --spectrum-animation-duration-1000: 50ms;
50
+ --spectrum-animation-duration-2000: 50ms;
51
+ --spectrum-animation-duration-4000: 50ms;
52
+ --spectrum-coachmark-animation-indicator-ring-duration: 50ms;
53
+ --swc-test-duration: 1ms;
54
+ }
55
+ </style>
56
+ </sp-theme>
23
57
  `);
24
58
  document.documentElement.dir = dir;
25
59
  return test.children[0];
@@ -90,9 +124,8 @@ describe("Submenu", () => {
90
124
  ]
91
125
  });
92
126
  await closed;
93
- await nextFrame();
94
- expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
95
- expect(submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
127
+ expect(submenuChanged.withArgs("Two").calledOnce, "submenu changed").to.be.true;
128
+ expect(rootChanged.withArgs("Has submenu").calledOnce, "root changed").to.be.true;
96
129
  });
97
130
  it("closes deep tree on selection", async () => {
98
131
  const rootChanged = spy();
@@ -143,11 +176,10 @@ describe("Submenu", () => {
143
176
  </sp-menu>
144
177
  `
145
178
  );
146
- await elementUpdated(el);
147
179
  const rootItem = el.querySelector(".root");
148
180
  const rootItemBoundingRect = rootItem.getBoundingClientRect();
149
181
  expect(rootItem.open).to.be.false;
150
- const opened = oneEvent(rootItem, "sp-opened");
182
+ let opened = oneEvent(rootItem, "sp-opened");
151
183
  sendMouse({
152
184
  steps: [
153
185
  {
@@ -163,7 +195,7 @@ describe("Submenu", () => {
163
195
  expect(rootItem.open).to.be.true;
164
196
  const item2 = document.querySelector(".submenu-item-2");
165
197
  const item2BoundingRect = item2.getBoundingClientRect();
166
- let closed = oneEvent(item2, "sp-opened");
198
+ opened = oneEvent(item2, "sp-opened");
167
199
  sendMouse({
168
200
  steps: [
169
201
  {
@@ -175,12 +207,11 @@ describe("Submenu", () => {
175
207
  }
176
208
  ]
177
209
  });
178
- await closed;
179
- await nextFrame();
210
+ await opened;
180
211
  expect(item2.open).to.be.true;
181
212
  const itemC = document.querySelector(".sub-submenu-item-3");
182
213
  const itemCBoundingRect = itemC.getBoundingClientRect();
183
- closed = oneEvent(rootItem, "sp-closed");
214
+ const closed = oneEvent(rootItem, "sp-closed");
184
215
  sendMouse({
185
216
  steps: [
186
217
  {
@@ -193,10 +224,9 @@ describe("Submenu", () => {
193
224
  ]
194
225
  });
195
226
  await closed;
196
- await nextFrame();
197
- expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
198
227
  expect(submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
199
228
  expect(subSubmenuChanged.calledWith("C"), "sub submenu changed").to.be.true;
229
+ expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
200
230
  });
201
231
  [
202
232
  {
@@ -211,11 +241,13 @@ describe("Submenu", () => {
211
241
  }
212
242
  ].map((testData) => {
213
243
  it(`selects - keyboard: ${testData.dir}`, async () => {
244
+ var _a, _b;
214
245
  const rootChanged = spy();
215
246
  const submenuChanged = spy();
216
247
  const el = await styledFixture(
217
248
  html`
218
249
  <sp-menu
250
+ id="base"
219
251
  @change=${(event) => {
220
252
  rootChanged(event.target.value);
221
253
  }}
@@ -223,6 +255,7 @@ describe("Submenu", () => {
223
255
  <sp-menu-item class="root">
224
256
  Has submenu
225
257
  <sp-menu
258
+ id="sub"
226
259
  slot="submenu"
227
260
  @change=${(event) => {
228
261
  submenuChanged(event.target.value);
@@ -245,6 +278,7 @@ describe("Submenu", () => {
245
278
  );
246
279
  await elementUpdated(el);
247
280
  const rootItem = el.querySelector(".root");
281
+ const submenu = el.querySelector('[slot="submenu"]');
248
282
  expect(rootItem.open).to.be.false;
249
283
  el.focus();
250
284
  await elementUpdated(el);
@@ -254,12 +288,20 @@ describe("Submenu", () => {
254
288
  });
255
289
  await opened;
256
290
  expect(rootItem.open).to.be.true;
291
+ expect(
292
+ submenu === document.activeElement,
293
+ `${(_a = document.activeElement) == null ? void 0 : _a.id}`
294
+ ).to.be.true;
257
295
  let closed = oneEvent(rootItem, "sp-closed");
258
296
  sendKeys({
259
297
  press: testData.closeKey
260
298
  });
261
299
  await closed;
262
300
  expect(rootItem.open).to.be.false;
301
+ expect(
302
+ el === document.activeElement,
303
+ `${(_b = document.activeElement) == null ? void 0 : _b.id}`
304
+ ).to.be.true;
263
305
  opened = oneEvent(rootItem, "sp-opened");
264
306
  sendKeys({
265
307
  press: testData.openKey
@@ -274,8 +316,12 @@ describe("Submenu", () => {
274
316
  press: "Enter"
275
317
  });
276
318
  await closed;
277
- expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
278
319
  expect(submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
320
+ expect(rootChanged.called, "root has changed").to.be.true;
321
+ expect(
322
+ rootChanged.calledWith("Has submenu"),
323
+ "root specifically changed"
324
+ ).to.be.true;
279
325
  });
280
326
  });
281
327
  it("closes on `pointerleave`", async () => {
@@ -407,7 +453,8 @@ describe("Submenu", () => {
407
453
  });
408
454
  await closed;
409
455
  });
410
- it("stays open when mousing between menu item and submenu", async () => {
456
+ it("continues to open when mousing between menu item and submenu", async () => {
457
+ const clickSpy = spy();
411
458
  const el = await styledFixture(
412
459
  html`
413
460
  <sp-menu>
@@ -417,7 +464,10 @@ describe("Submenu", () => {
417
464
  <sp-menu-item class="submenu-item-1">
418
465
  One
419
466
  </sp-menu-item>
420
- <sp-menu-item class="submenu-item-2">
467
+ <sp-menu-item
468
+ class="submenu-item-2"
469
+ @click=${() => clickSpy()}
470
+ >
421
471
  Two
422
472
  </sp-menu-item>
423
473
  <sp-menu-item class="submenu-item-3">
@@ -430,6 +480,7 @@ describe("Submenu", () => {
430
480
  );
431
481
  await elementUpdated(el);
432
482
  const rootItem = el.querySelector(".root");
483
+ const subItem = el.querySelector(".submenu-item-2");
433
484
  const rootItemBoundingRect = rootItem.getBoundingClientRect();
434
485
  expect(rootItem.open).to.be.false;
435
486
  const opened = oneEvent(rootItem, "sp-opened");
@@ -444,30 +495,114 @@ describe("Submenu", () => {
444
495
  }
445
496
  ]
446
497
  });
498
+ await nextFrame();
499
+ await nextFrame();
500
+ const subItemBoundingRect = subItem.getBoundingClientRect();
447
501
  await sendMouse({
448
502
  steps: [
449
503
  {
450
504
  type: "move",
451
505
  position: [
452
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
453
- rootItemBoundingRect.top + rootItemBoundingRect.height * 2
506
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
507
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
508
+ ]
509
+ }
510
+ ]
511
+ });
512
+ await opened;
513
+ expect(rootItem.open).to.be.true;
514
+ await aTimeout(150);
515
+ expect(rootItem.open).to.be.true;
516
+ const closed = oneEvent(rootItem, "sp-closed");
517
+ sendMouse({
518
+ steps: [
519
+ {
520
+ type: "click",
521
+ position: [
522
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
523
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
454
524
  ]
455
525
  }
456
526
  ]
457
527
  });
528
+ await closed;
529
+ expect(clickSpy.callCount).to.equal(1);
530
+ });
531
+ it("stays open when mousing between menu item and submenu", async () => {
532
+ const clickSpy = spy();
533
+ const el = await styledFixture(
534
+ html`
535
+ <sp-menu>
536
+ <sp-menu-item class="root">
537
+ Has submenu
538
+ <sp-menu slot="submenu">
539
+ <sp-menu-item class="submenu-item-1">
540
+ One
541
+ </sp-menu-item>
542
+ <sp-menu-item
543
+ class="submenu-item-2"
544
+ @click=${() => clickSpy()}
545
+ >
546
+ Two
547
+ </sp-menu-item>
548
+ <sp-menu-item class="submenu-item-3">
549
+ Three
550
+ </sp-menu-item>
551
+ </sp-menu>
552
+ </sp-menu-item>
553
+ </sp-menu>
554
+ `
555
+ );
556
+ await elementUpdated(el);
557
+ const rootItem = el.querySelector(".root");
558
+ const subItem = el.querySelector(".submenu-item-2");
559
+ const rootItemBoundingRect = rootItem.getBoundingClientRect();
560
+ expect(rootItem.open).to.be.false;
561
+ const opened = oneEvent(rootItem, "sp-opened");
458
562
  await sendMouse({
459
563
  steps: [
460
564
  {
461
565
  type: "move",
462
566
  position: [
463
- rootItemBoundingRect.left + rootItemBoundingRect.width * 1.5,
567
+ rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
464
568
  rootItemBoundingRect.top + rootItemBoundingRect.height / 2
465
569
  ]
466
570
  }
467
571
  ]
468
572
  });
469
573
  await opened;
574
+ await nextFrame();
575
+ await nextFrame();
576
+ const subItemBoundingRect = subItem.getBoundingClientRect();
470
577
  expect(rootItem.open).to.be.true;
578
+ await sendMouse({
579
+ steps: [
580
+ {
581
+ type: "move",
582
+ position: [
583
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
584
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
585
+ ]
586
+ }
587
+ ]
588
+ });
589
+ expect(rootItem.open).to.be.true;
590
+ await aTimeout(150);
591
+ expect(rootItem.open).to.be.true;
592
+ const closed = oneEvent(rootItem, "sp-closed");
593
+ sendMouse({
594
+ steps: [
595
+ {
596
+ type: "click",
597
+ position: [
598
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
599
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
600
+ ]
601
+ }
602
+ ]
603
+ });
604
+ await closed;
605
+ expect(clickSpy.callCount).to.equal(1);
471
606
  });
472
607
  it("not opens if disabled", async () => {
473
608
  const el = await styledFixture(
@@ -556,33 +691,34 @@ describe("Submenu", () => {
556
691
  el.click();
557
692
  await opened;
558
693
  expect(el.open).to.be.true;
559
- let activeOverlays = document.querySelectorAll("active-overlay");
560
- expect(activeOverlays.length).to.equal(1);
561
694
  opened = oneEvent(rootMenu1, "sp-opened");
562
695
  rootMenu1.dispatchEvent(
563
696
  new PointerEvent("pointerenter", { bubbles: true })
564
697
  );
565
698
  await opened;
566
- activeOverlays = document.querySelectorAll("active-overlay");
567
- expect(activeOverlays.length).to.equal(2);
568
699
  opened = oneEvent(childMenu2, "sp-opened");
569
700
  childMenu2.dispatchEvent(
570
701
  new PointerEvent("pointerenter", { bubbles: true })
571
702
  );
572
703
  await opened;
573
- activeOverlays = document.querySelectorAll("active-overlay");
574
- expect(activeOverlays.length).to.equal(3);
575
- const overlaysManaged = Promise.all([
576
- oneEvent(childMenu2, "sp-closed"),
577
- oneEvent(rootMenu1, "sp-closed"),
578
- oneEvent(rootMenu2, "sp-opened")
579
- ]);
580
- rootMenu2.dispatchEvent(
581
- new PointerEvent("pointerenter", { bubbles: true })
582
- );
583
- await overlaysManaged;
584
- activeOverlays = document.querySelectorAll("active-overlay");
585
- expect(activeOverlays.length).to.equal(2);
704
+ const childMenu2Closed = oneEvent(childMenu2, "sp-closed");
705
+ const rootMenu1Closed = oneEvent(rootMenu1, "sp-closed");
706
+ const rootMenu2Closed = oneEvent(rootMenu2, "sp-opened");
707
+ const rect = rootMenu2.getBoundingClientRect();
708
+ sendMouse({
709
+ steps: [
710
+ {
711
+ type: "move",
712
+ position: [
713
+ rect.left + rect.width / 2,
714
+ rect.top + rect.height / 2
715
+ ]
716
+ }
717
+ ]
718
+ });
719
+ await childMenu2Closed;
720
+ await rootMenu1Closed;
721
+ await rootMenu2Closed;
586
722
  });
587
723
  it("closes back to the first overlay without a `root` when clicking away", async () => {
588
724
  const el = await styledFixture(html`
@@ -631,31 +767,30 @@ describe("Submenu", () => {
631
767
  el.click();
632
768
  await opened;
633
769
  expect(el.open).to.be.true;
634
- let activeOverlays = document.querySelectorAll("active-overlay");
635
- expect(activeOverlays.length).to.equal(1);
636
770
  opened = oneEvent(rootMenu1, "sp-opened");
637
771
  rootMenu1.dispatchEvent(
638
772
  new PointerEvent("pointerenter", { bubbles: true })
639
773
  );
640
774
  await opened;
641
- activeOverlays = document.querySelectorAll("active-overlay");
642
- expect(activeOverlays.length).to.equal(2);
643
775
  opened = oneEvent(childMenu2, "sp-opened");
644
776
  childMenu2.dispatchEvent(
645
777
  new PointerEvent("pointerenter", { bubbles: true })
646
778
  );
647
779
  await opened;
648
- activeOverlays = document.querySelectorAll("active-overlay");
649
- expect(activeOverlays.length).to.equal(3);
650
780
  const closed = Promise.all([
651
781
  oneEvent(childMenu2, "sp-closed"),
652
782
  oneEvent(rootMenu1, "sp-closed"),
653
783
  oneEvent(el, "sp-closed")
654
784
  ]);
655
- document.body.click();
785
+ sendMouse({
786
+ steps: [
787
+ {
788
+ type: "click",
789
+ position: [600, 5]
790
+ }
791
+ ]
792
+ });
656
793
  await closed;
657
- activeOverlays = document.querySelectorAll("active-overlay");
658
- expect(activeOverlays.length).to.equal(0);
659
794
  });
660
795
  it("closes decendent menus when Menu Item in ancestor without a submenu is pointerentered", async () => {
661
796
  const el = await styledFixture(html`
@@ -694,22 +829,16 @@ describe("Submenu", () => {
694
829
  el.click();
695
830
  await opened;
696
831
  expect(el.open).to.be.true;
697
- let activeOverlays = document.querySelectorAll("active-overlay");
698
- expect(activeOverlays.length).to.equal(1);
699
832
  opened = oneEvent(rootMenu, "sp-opened");
700
833
  rootMenu.dispatchEvent(
701
834
  new PointerEvent("pointerenter", { bubbles: true })
702
835
  );
703
836
  await opened;
704
- activeOverlays = document.querySelectorAll("active-overlay");
705
- expect(activeOverlays.length).to.equal(2);
706
837
  const closed = oneEvent(rootMenu, "sp-closed");
707
838
  noSubmenu.dispatchEvent(
708
839
  new PointerEvent("pointerenter", { bubbles: true })
709
840
  );
710
841
  await closed;
711
- activeOverlays = document.querySelectorAll("active-overlay");
712
- expect(activeOverlays.length).to.equal(1);
713
842
  });
714
843
  it("closes decendent menus when Menu Item in ancestor is clicked", async () => {
715
844
  const el = await styledFixture(html`
@@ -753,6 +882,7 @@ describe("Submenu", () => {
753
882
  </sp-menu-group>
754
883
  </sp-action-menu>
755
884
  `);
885
+ await nextFrame();
756
886
  const rootMenu1 = el.querySelector("#submenu-item-1");
757
887
  const childMenu2 = el.querySelector("#submenu-item-2");
758
888
  const ancestorItem = el.querySelector("#ancestor-item");
@@ -761,33 +891,39 @@ describe("Submenu", () => {
761
891
  el.click();
762
892
  await opened;
763
893
  expect(el.open).to.be.true;
764
- let activeOverlays = document.querySelectorAll("active-overlay");
765
- expect(activeOverlays.length).to.equal(1);
766
894
  opened = oneEvent(rootMenu1, "sp-opened");
767
895
  rootMenu1.dispatchEvent(
768
896
  new PointerEvent("pointerenter", { bubbles: true })
769
897
  );
770
898
  await opened;
771
- activeOverlays = document.querySelectorAll("active-overlay");
772
- expect(activeOverlays.length).to.equal(2);
773
899
  opened = oneEvent(childMenu2, "sp-opened");
774
900
  childMenu2.dispatchEvent(
775
901
  new PointerEvent("pointerenter", { bubbles: true })
776
902
  );
777
903
  await opened;
778
- activeOverlays = document.querySelectorAll("active-overlay");
779
- expect(activeOverlays.length).to.equal(3);
780
904
  const closed = Promise.all([
781
905
  oneEvent(childMenu2, "sp-closed"),
782
906
  oneEvent(rootMenu1, "sp-closed"),
783
907
  oneEvent(el, "sp-closed")
784
908
  ]);
785
- ancestorItem.click();
909
+ const rect = ancestorItem.getBoundingClientRect();
910
+ await sendMouse({
911
+ steps: [
912
+ {
913
+ type: "click",
914
+ position: [
915
+ rect.left + rect.width / 2,
916
+ rect.top + rect.height / 2
917
+ ]
918
+ }
919
+ ]
920
+ });
786
921
  await closed;
787
- activeOverlays = document.querySelectorAll("active-overlay");
788
- expect(activeOverlays.length).to.equal(0);
789
922
  });
790
923
  it('cleans up submenus that close before they are "open"', async () => {
924
+ if ("showPopover" in document.createElement("div")) {
925
+ return;
926
+ }
791
927
  await sendMouse({
792
928
  steps: [
793
929
  {
@@ -837,7 +973,6 @@ describe("Submenu", () => {
837
973
  expect(rootItem2.open, "initially closed 2").to.be.false;
838
974
  const rootItemBoundingRect1 = rootItem1.getBoundingClientRect();
839
975
  const rootItemBoundingRect2 = rootItem2.getBoundingClientRect();
840
- let activeOverlay;
841
976
  await sendMouse({
842
977
  steps: [
843
978
  {
@@ -882,6 +1017,12 @@ describe("Submenu", () => {
882
1017
  }
883
1018
  ]
884
1019
  });
1020
+ await nextFrame();
1021
+ await nextFrame();
1022
+ await nextFrame();
1023
+ await nextFrame();
1024
+ await nextFrame();
1025
+ await nextFrame();
885
1026
  const closed = oneEvent(rootItem2, "sp-closed");
886
1027
  await sendMouse({
887
1028
  steps: [
@@ -889,20 +1030,12 @@ describe("Submenu", () => {
889
1030
  type: "move",
890
1031
  position: [
891
1032
  rootItemBoundingRect2.left + rootItemBoundingRect2.width / 2,
892
- rootItemBoundingRect2.top + rootItemBoundingRect2.top + rootItemBoundingRect2.height / 2
1033
+ rootItemBoundingRect2.top + rootItemBoundingRect2.height * 2
893
1034
  ]
894
1035
  }
895
1036
  ]
896
1037
  });
897
- activeOverlay = document.querySelector(
898
- "active-overlay"
899
- );
900
- expect(activeOverlay).to.not.be.null;
901
1038
  await closed;
902
- activeOverlay = document.querySelector(
903
- "active-overlay"
904
- );
905
- expect(activeOverlay).to.be.null;
906
1039
  expect(rootItem1.open, "finally closed 1").to.be.false;
907
1040
  expect(rootItem2.open, "finally closed 2").to.be.false;
908
1041
  });