Skip to content

Commit fdeb60b

Browse files
committed
fix: split-button tests & lots of cleanup based on review feedback
I'd do more on the manageSelection changes here, but I think we can remove a lot of this by using new options from #1189
1 parent 7f8011e commit fdeb60b

File tree

5 files changed

+98
-161
lines changed

5 files changed

+98
-161
lines changed

packages/picker/src/Picker.ts

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import pickerStyles from './picker.css.js';
2727
import chevronStyles from '@spectrum-web-components/icon/src/spectrum-icon-chevron.css.js';
2828

2929
import { Focusable } from '@spectrum-web-components/shared/src/focusable.js';
30-
import reparentChildren from '@spectrum-web-components/shared/src/reparent-children.js';
30+
import { reparentChildren } from '@spectrum-web-components/shared/src/reparent-children.js';
3131
import '@spectrum-web-components/icon/sp-icon.js';
3232
import { Chevron100Icon } from '@spectrum-web-components/icons-ui';
3333
import '@spectrum-web-components/icons-workflow/icons/sp-icon-alert.js';
@@ -39,6 +39,7 @@ import {
3939
MenuQueryRoleEventDetail,
4040
} from '@spectrum-web-components/menu';
4141
import '@spectrum-web-components/popover/sp-popover.js';
42+
import { Popover } from '@spectrum-web-components/popover/src/popover.js';
4243
import {
4344
Placement,
4445
openOverlay,
@@ -95,9 +96,10 @@ export class PickerBase extends SizedMixin(Focusable) {
9596
@property({ type: Boolean, reflect: true })
9697
public open = false;
9798

98-
private reparentableChildren?: Element[];
99+
public menuItems: MenuItem[] = [];
99100
private restoreChildren?: Function;
100-
public optionsMenu?: Menu;
101+
102+
public optionsMenu!: Menu;
101103

102104
/**
103105
* @type {"auto" | "auto-start" | "auto-end" | "top" | "bottom" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end" | "none"}
@@ -119,7 +121,7 @@ export class PickerBase extends SizedMixin(Focusable) {
119121
private closeOverlay?: () => void;
120122

121123
@query('sp-popover')
122-
private popover?: HTMLElement;
124+
private popover!: Popover;
123125

124126
protected listRole = 'listbox';
125127
protected itemRole = 'option';
@@ -145,7 +147,7 @@ export class PickerBase extends SizedMixin(Focusable) {
145147
}
146148

147149
public get focusElement(): HTMLElement {
148-
if (this.open && this.optionsMenu) {
150+
if (this.open) {
149151
return this.optionsMenu;
150152
}
151153
return this.button;
@@ -193,10 +195,6 @@ export class PickerBase extends SizedMixin(Focusable) {
193195
return;
194196
}
195197
event.preventDefault();
196-
/* c8 ignore next 3 */
197-
if (!this.optionsMenu) {
198-
return;
199-
}
200198
this.open = true;
201199
};
202200

@@ -249,18 +247,26 @@ export class PickerBase extends SizedMixin(Focusable) {
249247

250248
private async openMenu(): Promise<void> {
251249
/* c8 ignore next 9 */
252-
if (
253-
!this.popover ||
254-
!this.optionsMenu ||
255-
!this.reparentableChildren ||
256-
this.reparentableChildren.length === 0
257-
) {
250+
let reparentableChildren: Element[] = [];
251+
252+
const deprecatedMenu = this.querySelector('sp-menu');
253+
if (deprecatedMenu) {
254+
reparentableChildren = Array.from(deprecatedMenu.children);
255+
} else {
256+
reparentableChildren = Array.from(this.children).filter(
257+
(element) => {
258+
return !element.hasAttribute('slot');
259+
}
260+
);
261+
}
262+
263+
if (reparentableChildren.length === 0) {
258264
this.menuStateResolver();
259265
return;
260266
}
261267

262268
this.restoreChildren = reparentChildren(
263-
this.reparentableChildren,
269+
reparentableChildren,
264270
this.optionsMenu
265271
);
266272

@@ -339,21 +345,27 @@ export class PickerBase extends SizedMixin(Focusable) {
339345

340346
protected render(): TemplateResult {
341347
return html`
342-
${this.renderButton}
348+
${this.renderButton} ${this.renderPopover}
349+
`;
350+
}
351+
352+
protected get renderPopover(): TemplateResult {
353+
return html`
343354
<sp-popover
344355
open
345356
id="popover"
346357
@click=${this.onClick}
347358
@sp-overlay-closed=${this.onOverlayClosed}
348359
>
349-
<sp-menu id="menu" role="listbox"></sp-menu>
360+
<sp-menu id="menu" role="${this.listRole}"></sp-menu>
350361
</sp-popover>
351362
`;
352363
}
353364

354365
protected firstUpdated(changedProperties: PropertyValues): void {
355366
super.firstUpdated(changedProperties);
356367

368+
// Since the sp-menu gets reparented by the popover, initialize it here
357369
this.optionsMenu = this.shadowRoot.querySelector('sp-menu') as Menu;
358370

359371
const deprecatedMenu = this.querySelector('sp-menu');
@@ -362,14 +374,14 @@ export class PickerBase extends SizedMixin(Focusable) {
362374
`Deprecation Notice: You no longer need to provide an sp-menu child to ${this.tagName.toLowerCase()}. Any styling or attributes on the sp-menu will be ignored.`
363375
);
364376
}
365-
this.reparentableChildren = Array.from(
366-
(deprecatedMenu || this).children
367-
);
377+
this.menuItems = [
378+
...this.querySelectorAll(`sp-menu-item`),
379+
] as MenuItem[];
368380
}
369381

370382
protected updated(changedProperties: PropertyValues): void {
371383
super.updated(changedProperties);
372-
if (changedProperties.has('value') && this.reparentableChildren) {
384+
if (changedProperties.has('value')) {
373385
this.manageSelection();
374386
}
375387
if (changedProperties.has('disabled') && this.disabled) {
@@ -390,20 +402,15 @@ export class PickerBase extends SizedMixin(Focusable) {
390402
}
391403
}
392404

393-
private async manageSelection(): Promise<void> {
405+
protected async manageSelection(): Promise<void> {
394406
/* c8 ignore next 3 */
395-
if (!this.reparentableChildren) {
396-
return;
397-
}
398-
if (this.reparentableChildren.length) {
407+
if (this.menuItems.length > 0) {
399408
let selectedItem: MenuItem | undefined;
400-
this.reparentableChildren.map((item) => {
401-
if (item instanceof MenuItem) {
402-
if (this.value === item.value && !item.disabled) {
403-
selectedItem = item;
404-
} else {
405-
item.selected = false;
406-
}
409+
this.menuItems.forEach((item) => {
410+
if (this.value === item.value && !item.disabled) {
411+
selectedItem = item;
412+
} else {
413+
item.selected = false;
407414
}
408415
});
409416
if (selectedItem) {
@@ -413,12 +420,12 @@ export class PickerBase extends SizedMixin(Focusable) {
413420
this.value = '';
414421
this.selectedItemText = '';
415422
}
416-
if (this.open && this.optionsMenu) {
423+
if (this.open) {
417424
this.optionsMenu.updateSelectedItemIndex();
418425
}
419426
return;
420427
}
421-
if (this.open && this.optionsMenu) {
428+
if (this.open) {
422429
await this.optionsMenu.updateComplete;
423430
if (this.optionsMenu.menuItems.length) {
424431
this.manageSelection();

packages/picker/test/picker.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -430,11 +430,9 @@ describe('Picker', () => {
430430
expect(el.open).to.be.true;
431431
expect(isMenuActiveElement()).to.be.true;
432432

433-
const menu = document.activeElement;
434-
if (menu) {
435-
// we know this is defined, but typescript doesn't
436-
menu.dispatchEvent(tabEvent);
437-
}
433+
const menu = document.activeElement as Menu;
434+
menu.dispatchEvent(tabEvent);
435+
438436
await elementUpdated(el);
439437
await waitUntil(() => !el.open);
440438

packages/shared/src/reparent-children.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ function restoreChildren(
22
placeholderItems: Comment[],
33
srcElements: Element[]
44
): void {
5-
if (srcElements.length != placeholderItems.length) {
6-
throw new Error(
7-
'Unexpected length mismatch attempting to restore parent elements'
8-
);
9-
}
105
for (let index = 0; index < srcElements.length; ++index) {
116
const srcElement = srcElements[index];
127
const placeholderItem = placeholderItems[index];
@@ -17,7 +12,10 @@ function restoreChildren(
1712
}
1813
}
1914

20-
export default function (srcElements: Element[], newParent: Element): Function {
15+
export const reparentChildren = (
16+
srcElements: Element[],
17+
newParent: Element
18+
): Function => {
2119
let placeholderItems: Comment[] = [];
2220

2321
for (let index = 0; index < srcElements.length; ++index) {
@@ -36,4 +34,4 @@ export default function (srcElements: Element[], newParent: Element): Function {
3634
return function () {
3735
restoreChildren(placeholderItems, srcElements);
3836
};
39-
}
37+
};

0 commit comments

Comments
 (0)