@spectrum-web-components/menu 0.31.1-react.3 → 0.32.1-overlay.33

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,12 @@ 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();
181
+ const item2 = document.querySelector(".submenu-item-2");
182
+ const itemC = document.querySelector(".sub-submenu-item-3");
149
183
  expect(rootItem.open).to.be.false;
150
- const opened = oneEvent(rootItem, "sp-opened");
184
+ let opened = oneEvent(rootItem, "sp-opened");
151
185
  sendMouse({
152
186
  steps: [
153
187
  {
@@ -161,9 +195,8 @@ describe("Submenu", () => {
161
195
  });
162
196
  await opened;
163
197
  expect(rootItem.open).to.be.true;
164
- const item2 = document.querySelector(".submenu-item-2");
165
198
  const item2BoundingRect = item2.getBoundingClientRect();
166
- let closed = oneEvent(item2, "sp-opened");
199
+ opened = oneEvent(item2, "sp-opened");
167
200
  sendMouse({
168
201
  steps: [
169
202
  {
@@ -175,25 +208,11 @@ describe("Submenu", () => {
175
208
  }
176
209
  ]
177
210
  });
178
- await closed;
179
- await nextFrame();
211
+ await opened;
180
212
  expect(item2.open).to.be.true;
181
- const itemC = document.querySelector(".sub-submenu-item-3");
182
- const itemCBoundingRect = itemC.getBoundingClientRect();
183
- closed = oneEvent(rootItem, "sp-closed");
184
- sendMouse({
185
- steps: [
186
- {
187
- type: "click",
188
- position: [
189
- itemCBoundingRect.left + itemCBoundingRect.width / 2,
190
- itemCBoundingRect.top + itemCBoundingRect.height / 2
191
- ]
192
- }
193
- ]
194
- });
213
+ const closed = oneEvent(rootItem, "sp-closed");
214
+ itemC.click();
195
215
  await closed;
196
- await nextFrame();
197
216
  expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
198
217
  expect(submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
199
218
  expect(subSubmenuChanged.calledWith("C"), "sub submenu changed").to.be.true;
@@ -211,11 +230,13 @@ describe("Submenu", () => {
211
230
  }
212
231
  ].map((testData) => {
213
232
  it(`selects - keyboard: ${testData.dir}`, async () => {
233
+ var _a, _b;
214
234
  const rootChanged = spy();
215
235
  const submenuChanged = spy();
216
236
  const el = await styledFixture(
217
237
  html`
218
238
  <sp-menu
239
+ id="base"
219
240
  @change=${(event) => {
220
241
  rootChanged(event.target.value);
221
242
  }}
@@ -223,6 +244,7 @@ describe("Submenu", () => {
223
244
  <sp-menu-item class="root">
224
245
  Has submenu
225
246
  <sp-menu
247
+ id="sub"
226
248
  slot="submenu"
227
249
  @change=${(event) => {
228
250
  submenuChanged(event.target.value);
@@ -245,6 +267,7 @@ describe("Submenu", () => {
245
267
  );
246
268
  await elementUpdated(el);
247
269
  const rootItem = el.querySelector(".root");
270
+ const submenu = el.querySelector('[slot="submenu"]');
248
271
  expect(rootItem.open).to.be.false;
249
272
  el.focus();
250
273
  await elementUpdated(el);
@@ -254,12 +277,20 @@ describe("Submenu", () => {
254
277
  });
255
278
  await opened;
256
279
  expect(rootItem.open).to.be.true;
280
+ expect(
281
+ submenu === document.activeElement,
282
+ `${(_a = document.activeElement) == null ? void 0 : _a.id}`
283
+ ).to.be.true;
257
284
  let closed = oneEvent(rootItem, "sp-closed");
258
285
  sendKeys({
259
286
  press: testData.closeKey
260
287
  });
261
288
  await closed;
262
289
  expect(rootItem.open).to.be.false;
290
+ expect(
291
+ el === document.activeElement,
292
+ `${(_b = document.activeElement) == null ? void 0 : _b.id}`
293
+ ).to.be.true;
263
294
  opened = oneEvent(rootItem, "sp-opened");
264
295
  sendKeys({
265
296
  press: testData.openKey
@@ -274,8 +305,12 @@ describe("Submenu", () => {
274
305
  press: "Enter"
275
306
  });
276
307
  await closed;
277
- expect(rootChanged.calledWith("Has submenu"), "root changed").to.be.true;
278
308
  expect(submenuChanged.calledWith("Two"), "submenu changed").to.be.true;
309
+ expect(rootChanged.called, "root has changed").to.be.true;
310
+ expect(
311
+ rootChanged.calledWith("Has submenu"),
312
+ "root specifically changed"
313
+ ).to.be.true;
279
314
  });
280
315
  });
281
316
  it("closes on `pointerleave`", async () => {
@@ -407,7 +442,8 @@ describe("Submenu", () => {
407
442
  });
408
443
  await closed;
409
444
  });
410
- it("stays open when mousing between menu item and submenu", async () => {
445
+ it("continues to open when mousing between menu item and submenu", async () => {
446
+ const clickSpy = spy();
411
447
  const el = await styledFixture(
412
448
  html`
413
449
  <sp-menu>
@@ -417,7 +453,10 @@ describe("Submenu", () => {
417
453
  <sp-menu-item class="submenu-item-1">
418
454
  One
419
455
  </sp-menu-item>
420
- <sp-menu-item class="submenu-item-2">
456
+ <sp-menu-item
457
+ class="submenu-item-2"
458
+ @click=${() => clickSpy()}
459
+ >
421
460
  Two
422
461
  </sp-menu-item>
423
462
  <sp-menu-item class="submenu-item-3">
@@ -430,6 +469,7 @@ describe("Submenu", () => {
430
469
  );
431
470
  await elementUpdated(el);
432
471
  const rootItem = el.querySelector(".root");
472
+ const subItem = el.querySelector(".submenu-item-2");
433
473
  const rootItemBoundingRect = rootItem.getBoundingClientRect();
434
474
  expect(rootItem.open).to.be.false;
435
475
  const opened = oneEvent(rootItem, "sp-opened");
@@ -444,30 +484,114 @@ describe("Submenu", () => {
444
484
  }
445
485
  ]
446
486
  });
487
+ await nextFrame();
488
+ await nextFrame();
489
+ const subItemBoundingRect = subItem.getBoundingClientRect();
447
490
  await sendMouse({
448
491
  steps: [
449
492
  {
450
493
  type: "move",
451
494
  position: [
452
- rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
453
- rootItemBoundingRect.top + rootItemBoundingRect.height * 2
495
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
496
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
454
497
  ]
455
498
  }
456
499
  ]
457
500
  });
501
+ await opened;
502
+ expect(rootItem.open).to.be.true;
503
+ await aTimeout(150);
504
+ expect(rootItem.open).to.be.true;
505
+ const closed = oneEvent(rootItem, "sp-closed");
506
+ sendMouse({
507
+ steps: [
508
+ {
509
+ type: "click",
510
+ position: [
511
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
512
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
513
+ ]
514
+ }
515
+ ]
516
+ });
517
+ await closed;
518
+ expect(clickSpy.callCount).to.equal(1);
519
+ });
520
+ it("stays open when mousing between menu item and submenu", async () => {
521
+ const clickSpy = spy();
522
+ const el = await styledFixture(
523
+ html`
524
+ <sp-menu>
525
+ <sp-menu-item class="root">
526
+ Has submenu
527
+ <sp-menu slot="submenu">
528
+ <sp-menu-item class="submenu-item-1">
529
+ One
530
+ </sp-menu-item>
531
+ <sp-menu-item
532
+ class="submenu-item-2"
533
+ @click=${() => clickSpy()}
534
+ >
535
+ Two
536
+ </sp-menu-item>
537
+ <sp-menu-item class="submenu-item-3">
538
+ Three
539
+ </sp-menu-item>
540
+ </sp-menu>
541
+ </sp-menu-item>
542
+ </sp-menu>
543
+ `
544
+ );
545
+ await elementUpdated(el);
546
+ const rootItem = el.querySelector(".root");
547
+ const subItem = el.querySelector(".submenu-item-2");
548
+ const rootItemBoundingRect = rootItem.getBoundingClientRect();
549
+ expect(rootItem.open).to.be.false;
550
+ const opened = oneEvent(rootItem, "sp-opened");
458
551
  await sendMouse({
459
552
  steps: [
460
553
  {
461
554
  type: "move",
462
555
  position: [
463
- rootItemBoundingRect.left + rootItemBoundingRect.width * 1.5,
556
+ rootItemBoundingRect.left + rootItemBoundingRect.width / 2,
464
557
  rootItemBoundingRect.top + rootItemBoundingRect.height / 2
465
558
  ]
466
559
  }
467
560
  ]
468
561
  });
469
562
  await opened;
563
+ await nextFrame();
564
+ await nextFrame();
565
+ const subItemBoundingRect = subItem.getBoundingClientRect();
566
+ expect(rootItem.open).to.be.true;
567
+ await sendMouse({
568
+ steps: [
569
+ {
570
+ type: "move",
571
+ position: [
572
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
573
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
574
+ ]
575
+ }
576
+ ]
577
+ });
578
+ expect(rootItem.open).to.be.true;
579
+ await aTimeout(150);
470
580
  expect(rootItem.open).to.be.true;
581
+ const closed = oneEvent(rootItem, "sp-closed");
582
+ sendMouse({
583
+ steps: [
584
+ {
585
+ type: "click",
586
+ position: [
587
+ subItemBoundingRect.left + subItemBoundingRect.width / 2,
588
+ subItemBoundingRect.top + subItemBoundingRect.height / 2
589
+ ]
590
+ }
591
+ ]
592
+ });
593
+ await closed;
594
+ expect(clickSpy.callCount).to.equal(1);
471
595
  });
472
596
  it("not opens if disabled", async () => {
473
597
  const el = await styledFixture(
@@ -512,15 +636,15 @@ describe("Submenu", () => {
512
636
  const el = await styledFixture(html`
513
637
  <sp-action-menu>
514
638
  <sp-icon-show-menu slot="icon"></sp-icon-show-menu>
515
- <sp-menu-group role="none">
639
+ <sp-menu-group role="none" id="group">
516
640
  <span slot="header">New York</span>
517
641
  <sp-menu-item>Bronx</sp-menu-item>
518
642
  <sp-menu-item id="submenu-item-1">
519
643
  Brooklyn
520
- <sp-menu slot="submenu">
644
+ <sp-menu slot="submenu" id="submenu-1">
521
645
  <sp-menu-item id="submenu-item-2">
522
646
  Ft. Greene
523
- <sp-menu slot="submenu">
647
+ <sp-menu slot="submenu" id="submenu-2">
524
648
  <sp-menu-item>S. Oxford St</sp-menu-item>
525
649
  <sp-menu-item>S. Portland Ave</sp-menu-item>
526
650
  <sp-menu-item>S. Elliot Pl</sp-menu-item>
@@ -532,7 +656,7 @@ describe("Submenu", () => {
532
656
  </sp-menu-item>
533
657
  <sp-menu-item id="submenu-item-3">
534
658
  Manhattan
535
- <sp-menu slot="submenu">
659
+ <sp-menu slot="submenu" id="submenu-3">
536
660
  <sp-menu-item disabled>SoHo</sp-menu-item>
537
661
  <sp-menu-item>
538
662
  Union Square
@@ -556,33 +680,27 @@ describe("Submenu", () => {
556
680
  el.click();
557
681
  await opened;
558
682
  expect(el.open).to.be.true;
559
- let activeOverlays = document.querySelectorAll("active-overlay");
560
- expect(activeOverlays.length).to.equal(1);
561
683
  opened = oneEvent(rootMenu1, "sp-opened");
562
684
  rootMenu1.dispatchEvent(
563
685
  new PointerEvent("pointerenter", { bubbles: true })
564
686
  );
565
687
  await opened;
566
- activeOverlays = document.querySelectorAll("active-overlay");
567
- expect(activeOverlays.length).to.equal(2);
688
+ expect(rootMenu1.open).to.be.true;
568
689
  opened = oneEvent(childMenu2, "sp-opened");
569
690
  childMenu2.dispatchEvent(
570
691
  new PointerEvent("pointerenter", { bubbles: true })
571
692
  );
572
693
  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
- ]);
694
+ expect(childMenu2.open).to.be.true;
695
+ const childMenu2Closed = oneEvent(childMenu2, "sp-closed");
696
+ const rootMenu1Closed = oneEvent(rootMenu1, "sp-closed");
697
+ const rootMenu2Opened = oneEvent(rootMenu2, "sp-opened");
580
698
  rootMenu2.dispatchEvent(
581
699
  new PointerEvent("pointerenter", { bubbles: true })
582
700
  );
583
- await overlaysManaged;
584
- activeOverlays = document.querySelectorAll("active-overlay");
585
- expect(activeOverlays.length).to.equal(2);
701
+ await childMenu2Closed;
702
+ await rootMenu1Closed;
703
+ await rootMenu2Opened;
586
704
  });
587
705
  it("closes back to the first overlay without a `root` when clicking away", async () => {
588
706
  const el = await styledFixture(html`
@@ -631,31 +749,30 @@ describe("Submenu", () => {
631
749
  el.click();
632
750
  await opened;
633
751
  expect(el.open).to.be.true;
634
- let activeOverlays = document.querySelectorAll("active-overlay");
635
- expect(activeOverlays.length).to.equal(1);
636
752
  opened = oneEvent(rootMenu1, "sp-opened");
637
753
  rootMenu1.dispatchEvent(
638
754
  new PointerEvent("pointerenter", { bubbles: true })
639
755
  );
640
756
  await opened;
641
- activeOverlays = document.querySelectorAll("active-overlay");
642
- expect(activeOverlays.length).to.equal(2);
643
757
  opened = oneEvent(childMenu2, "sp-opened");
644
758
  childMenu2.dispatchEvent(
645
759
  new PointerEvent("pointerenter", { bubbles: true })
646
760
  );
647
761
  await opened;
648
- activeOverlays = document.querySelectorAll("active-overlay");
649
- expect(activeOverlays.length).to.equal(3);
650
762
  const closed = Promise.all([
651
763
  oneEvent(childMenu2, "sp-closed"),
652
764
  oneEvent(rootMenu1, "sp-closed"),
653
765
  oneEvent(el, "sp-closed")
654
766
  ]);
655
- document.body.click();
767
+ sendMouse({
768
+ steps: [
769
+ {
770
+ type: "click",
771
+ position: [600, 5]
772
+ }
773
+ ]
774
+ });
656
775
  await closed;
657
- activeOverlays = document.querySelectorAll("active-overlay");
658
- expect(activeOverlays.length).to.equal(0);
659
776
  });
660
777
  it("closes decendent menus when Menu Item in ancestor without a submenu is pointerentered", async () => {
661
778
  const el = await styledFixture(html`
@@ -694,22 +811,16 @@ describe("Submenu", () => {
694
811
  el.click();
695
812
  await opened;
696
813
  expect(el.open).to.be.true;
697
- let activeOverlays = document.querySelectorAll("active-overlay");
698
- expect(activeOverlays.length).to.equal(1);
699
814
  opened = oneEvent(rootMenu, "sp-opened");
700
815
  rootMenu.dispatchEvent(
701
816
  new PointerEvent("pointerenter", { bubbles: true })
702
817
  );
703
818
  await opened;
704
- activeOverlays = document.querySelectorAll("active-overlay");
705
- expect(activeOverlays.length).to.equal(2);
706
819
  const closed = oneEvent(rootMenu, "sp-closed");
707
820
  noSubmenu.dispatchEvent(
708
821
  new PointerEvent("pointerenter", { bubbles: true })
709
822
  );
710
823
  await closed;
711
- activeOverlays = document.querySelectorAll("active-overlay");
712
- expect(activeOverlays.length).to.equal(1);
713
824
  });
714
825
  it("closes decendent menus when Menu Item in ancestor is clicked", async () => {
715
826
  const el = await styledFixture(html`
@@ -753,6 +864,7 @@ describe("Submenu", () => {
753
864
  </sp-menu-group>
754
865
  </sp-action-menu>
755
866
  `);
867
+ await nextFrame();
756
868
  const rootMenu1 = el.querySelector("#submenu-item-1");
757
869
  const childMenu2 = el.querySelector("#submenu-item-2");
758
870
  const ancestorItem = el.querySelector("#ancestor-item");
@@ -761,33 +873,39 @@ describe("Submenu", () => {
761
873
  el.click();
762
874
  await opened;
763
875
  expect(el.open).to.be.true;
764
- let activeOverlays = document.querySelectorAll("active-overlay");
765
- expect(activeOverlays.length).to.equal(1);
766
876
  opened = oneEvent(rootMenu1, "sp-opened");
767
877
  rootMenu1.dispatchEvent(
768
878
  new PointerEvent("pointerenter", { bubbles: true })
769
879
  );
770
880
  await opened;
771
- activeOverlays = document.querySelectorAll("active-overlay");
772
- expect(activeOverlays.length).to.equal(2);
773
881
  opened = oneEvent(childMenu2, "sp-opened");
774
882
  childMenu2.dispatchEvent(
775
883
  new PointerEvent("pointerenter", { bubbles: true })
776
884
  );
777
885
  await opened;
778
- activeOverlays = document.querySelectorAll("active-overlay");
779
- expect(activeOverlays.length).to.equal(3);
780
886
  const closed = Promise.all([
781
887
  oneEvent(childMenu2, "sp-closed"),
782
888
  oneEvent(rootMenu1, "sp-closed"),
783
889
  oneEvent(el, "sp-closed")
784
890
  ]);
785
- ancestorItem.click();
891
+ const rect = ancestorItem.getBoundingClientRect();
892
+ await sendMouse({
893
+ steps: [
894
+ {
895
+ type: "click",
896
+ position: [
897
+ rect.left + rect.width / 2,
898
+ rect.top + rect.height / 2
899
+ ]
900
+ }
901
+ ]
902
+ });
786
903
  await closed;
787
- activeOverlays = document.querySelectorAll("active-overlay");
788
- expect(activeOverlays.length).to.equal(0);
789
904
  });
790
905
  it('cleans up submenus that close before they are "open"', async () => {
906
+ if ("showPopover" in document.createElement("div")) {
907
+ return;
908
+ }
791
909
  await sendMouse({
792
910
  steps: [
793
911
  {
@@ -837,7 +955,6 @@ describe("Submenu", () => {
837
955
  expect(rootItem2.open, "initially closed 2").to.be.false;
838
956
  const rootItemBoundingRect1 = rootItem1.getBoundingClientRect();
839
957
  const rootItemBoundingRect2 = rootItem2.getBoundingClientRect();
840
- let activeOverlay;
841
958
  await sendMouse({
842
959
  steps: [
843
960
  {
@@ -882,6 +999,12 @@ describe("Submenu", () => {
882
999
  }
883
1000
  ]
884
1001
  });
1002
+ await nextFrame();
1003
+ await nextFrame();
1004
+ await nextFrame();
1005
+ await nextFrame();
1006
+ await nextFrame();
1007
+ await nextFrame();
885
1008
  const closed = oneEvent(rootItem2, "sp-closed");
886
1009
  await sendMouse({
887
1010
  steps: [
@@ -889,20 +1012,12 @@ describe("Submenu", () => {
889
1012
  type: "move",
890
1013
  position: [
891
1014
  rootItemBoundingRect2.left + rootItemBoundingRect2.width / 2,
892
- rootItemBoundingRect2.top + rootItemBoundingRect2.top + rootItemBoundingRect2.height / 2
1015
+ rootItemBoundingRect2.top + rootItemBoundingRect2.height * 2
893
1016
  ]
894
1017
  }
895
1018
  ]
896
1019
  });
897
- activeOverlay = document.querySelector(
898
- "active-overlay"
899
- );
900
- expect(activeOverlay).to.not.be.null;
901
1020
  await closed;
902
- activeOverlay = document.querySelector(
903
- "active-overlay"
904
- );
905
- expect(activeOverlay).to.be.null;
906
1021
  expect(rootItem1.open, "finally closed 1").to.be.false;
907
1022
  expect(rootItem2.open, "finally closed 2").to.be.false;
908
1023
  });