Skip to content

Commit 43dc555

Browse files
committed
move polyfill into base classes
1 parent 0a54e90 commit 43dc555

6 files changed

Lines changed: 57 additions & 134 deletions

File tree

packages/web-components/docs/web-components.api.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -742,10 +742,6 @@ export class BaseMenuList extends FASTElement {
742742
elementInternals: ElementInternals;
743743
focus(): void;
744744
handleChange(source: any, propertyName: string): void;
745-
// @internal
746-
handleFocusOut: (e: FocusEvent) => void;
747-
// @internal (undocumented)
748-
handleMenuKeyDown(e: KeyboardEvent): void | boolean;
749745
protected isMenuItemElement: (el: Element) => el is HTMLElement;
750746
// @internal (undocumented)
751747
readonly isNestedMenu: () => boolean;
@@ -754,7 +750,7 @@ export class BaseMenuList extends FASTElement {
754750
// (undocumented)
755751
protected itemsChanged(oldValue: HTMLElement[], newValue: HTMLElement[]): void;
756752
// (undocumented)
757-
protected menuItems: Element[] | undefined;
753+
protected menuItems: HTMLElement[] | undefined;
758754
// (undocumented)
759755
protected setItems(): void;
760756
}
@@ -811,8 +807,6 @@ export class BaseRadioGroup extends FASTElement {
811807
focus(): void;
812808
// @internal
813809
focusinHandler(e: FocusEvent): boolean | void;
814-
// @internal
815-
focusoutHandler(e: FocusEvent): boolean | void;
816810
static formAssociated: boolean;
817811
// (undocumented)
818812
formResetCallback(): void;
@@ -895,8 +889,6 @@ export class BaseTablist extends FASTElement {
895889
// @internal (undocumented)
896890
protected activeidChanged(oldValue: string, newValue: string): void;
897891
activetab: Tab;
898-
// @internal (undocumented)
899-
connectedCallback(): void;
900892
disabled: boolean;
901893
// @internal (undocumented)
902894
protected disabledChanged(prev: boolean, next: boolean): void;
@@ -1092,8 +1084,6 @@ export class BaseTree extends FASTElement {
10921084
childTreeItemsChanged(): void;
10931085
// @internal
10941086
clickHandler(e: Event): boolean | void;
1095-
// @internal (undocumented)
1096-
connectedCallback(): void;
10971087
currentSelected: HTMLElement | null;
10981088
// @internal (undocumented)
10991089
defaultSlot: HTMLSlotElement;
@@ -3372,7 +3362,7 @@ export const MenuItemTemplate: ElementViewTemplate<MenuItem>;
33723362

33733363
// @public
33743364
export class MenuList extends BaseMenuList {
3375-
// @internal (undocumented)
3365+
// (undocumented)
33763366
connectedCallback(): void;
33773367
}
33783368

@@ -4010,6 +4000,8 @@ export const TabDefinition: FASTElementDefinition<typeof Tab>;
40104000
export class Tablist extends BaseTablist {
40114001
activeidChanged(oldValue: string, newValue: string): void;
40124002
appearance?: TablistAppearance;
4003+
// @internal (undocumented)
4004+
connectedCallback(): void;
40134005
size?: TablistSize;
40144006
tabsChanged(prev: Tab[] | undefined, next: Tab[] | undefined): void;
40154007
}
@@ -4407,6 +4399,8 @@ export class Tree extends BaseTree {
44074399
protected appearanceChanged(): void;
44084400
// @internal
44094401
childTreeItemsChanged(): void;
4402+
// @internal (undocumented)
4403+
connectedCallback(): void;
44104404
size: TreeItemSize;
44114405
// (undocumented)
44124406
protected sizeChanged(): void;

packages/web-components/src/radio-group/radio-group.base.ts

Lines changed: 26 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import { attr, FASTElement, Observable, observable, Updates } from '@microsoft/fast-element';
1+
import { attr, FASTElement, Observable, observable } from '@microsoft/fast-element';
22
import { findLastIndex } from '@microsoft/fast-web-utilities';
33
import { Radio } from '../radio/radio.js';
44
import { isRadio } from '../radio/radio.options.js';
5-
import { getDirection } from '../utils/direction.js';
6-
import { getRootActiveElement } from '../utils/root-active-element.js';
75
import { RadioGroupOrientation } from './radio-group.options.js';
86

97
/**
@@ -64,7 +62,6 @@ export class BaseRadioGroup extends FASTElement {
6462
this.radios?.forEach(radio => {
6563
radio.disabled = !!radio.disabledAttribute || !!this.disabled;
6664
});
67-
this.restrictFocus();
6865
}
6966
}
7067

@@ -170,6 +167,13 @@ export class BaseRadioGroup extends FASTElement {
170167

171168
radio.name = this.name ?? radio.name;
172169
radio.disabled = !!this.disabled || !!radio.disabledAttribute;
170+
171+
if (radio.checked && !radio.disabled) {
172+
// Update.enqueu() would be too soon for this operation.
173+
requestAnimationFrame(() => {
174+
radio.toggleAttribute('focusgroupstart', true);
175+
});
176+
}
173177
});
174178

175179
if (!this.dirtyState && this.initialValue) {
@@ -196,10 +200,6 @@ export class BaseRadioGroup extends FASTElement {
196200
if (radioIds) {
197201
this.setAttribute('aria-owns', radioIds);
198202
}
199-
200-
Updates.enqueue(() => {
201-
this.restrictFocus();
202-
});
203203
}
204204

205205
/**
@@ -422,6 +422,13 @@ export class BaseRadioGroup extends FASTElement {
422422
this.enabledRadios[Math.max(0, this.checkedIndex)]?.focus();
423423
}
424424

425+
formResetCallback(): void {
426+
this.dirtyState = false;
427+
this.checkedIndex = -1;
428+
this.setFormValue(this.value);
429+
this.setValidity();
430+
}
431+
425432
/**
426433
* Enables tabbing through the radio group when the group receives focus.
427434
*
@@ -430,93 +437,35 @@ export class BaseRadioGroup extends FASTElement {
430437
*/
431438
public focusinHandler(e: FocusEvent): boolean | void {
432439
if (!this.disabled) {
433-
this.enabledRadios.forEach(radio => {
434-
radio.tabIndex = 0;
440+
// Uncheck the checked disabled radio, if any.
441+
this.radios?.forEach(radio => {
442+
if (radio.disabled && radio.checked) {
443+
radio.checked = false;
444+
}
435445
});
436-
}
437-
438-
return true;
439-
}
440446

441-
/**
442-
* Sets the tabindex of the radios based on the checked state when the radio group loses focus.
443-
*
444-
* @param e - the focusout event
445-
* @internal
446-
*/
447-
public focusoutHandler(e: FocusEvent): boolean | void {
448-
if (this.radios?.includes(e.relatedTarget as Radio) && this.radios?.some(x => x.checked)) {
449-
this.restrictFocus();
447+
const index = this.enabledRadios.indexOf(e.target as Radio);
448+
if (index > -1) {
449+
this.checkRadio(index, true);
450+
}
450451
}
451452

452453
return true;
453454
}
454455

455-
formResetCallback(): void {
456-
this.dirtyState = false;
457-
this.checkedIndex = -1;
458-
this.setFormValue(this.value);
459-
this.setValidity();
460-
}
461-
462-
private getEnabledIndexInBounds(index: number, upperBound = this.enabledRadios.length): number {
463-
if (upperBound === 0) {
464-
return -1;
465-
}
466-
467-
return (index + upperBound) % upperBound;
468-
}
469-
470456
/**
471457
* Handles keydown events for the radio group.
472458
*
473459
* @param e - the keyboard event
474460
* @internal
475461
*/
476462
public keydownHandler(e: KeyboardEvent): boolean | void {
477-
const isRtl = getDirection(this) === 'rtl';
478-
const checkedIndex = this.enabledRadios.findIndex(x => x === getRootActiveElement(this)) ?? this.checkedIndex;
479-
let increment = 0;
480-
481463
switch (e.key) {
482-
case 'ArrowLeft': {
483-
increment = isRtl ? 1 : -1;
484-
break;
485-
}
486-
487-
case 'ArrowUp': {
488-
increment = -1;
489-
break;
490-
}
491-
492-
case 'ArrowRight': {
493-
increment = isRtl ? -1 : 1;
494-
break;
495-
}
496-
497-
case 'ArrowDown': {
498-
increment = 1;
499-
break;
500-
}
501-
502-
case 'Tab': {
503-
this.restrictFocus();
504-
break;
505-
}
506-
507-
case ' ': {
464+
case ' ':
508465
this.checkRadio();
509466
break;
510-
}
511467
}
512-
513-
if (!increment) {
514-
return true;
515-
}
516-
517-
const nextIndex = checkedIndex + increment;
518-
this.checkRadio(this.getEnabledIndexInBounds(nextIndex), true);
519-
this.enabledRadios[this.checkedIndex]?.focus();
468+
return true;
520469
}
521470

522471
/**
@@ -540,26 +489,6 @@ export class BaseRadioGroup extends FASTElement {
540489
return this.elementInternals.reportValidity();
541490
}
542491

543-
/**
544-
* Resets the `tabIndex` for all child radios when the radio group loses focus.
545-
*
546-
* @internal
547-
*/
548-
private restrictFocus() {
549-
let activeIndex = Math.max(this.checkedIndex, 0);
550-
const focusedRadioIndex = this.enabledRadios.indexOf(getRootActiveElement(this) as Radio);
551-
552-
if (focusedRadioIndex !== -1) {
553-
activeIndex = focusedRadioIndex;
554-
}
555-
556-
activeIndex = this.getEnabledIndexInBounds(activeIndex);
557-
558-
this.enabledRadios.forEach((item, index) => {
559-
item.tabIndex = index === activeIndex ? 0 : -1;
560-
});
561-
}
562-
563492
/**
564493
* Reflects the {@link https://developer.mozilla.org/docs/Web/API/ElementInternals/setFormValue | `ElementInternals.setFormValue()`} method.
565494
*

packages/web-components/src/tablist/tablist.base.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { attr, FASTElement, observable, Updates } from '@microsoft/fast-element';
1+
import { attr, FASTElement, observable } from '@microsoft/fast-element';
22
import { uniqueId } from '@microsoft/fast-web-utilities';
3-
import { polyfill as focusgroupPolyfill } from '@microsoft/focusgroup-polyfill';
43
import type { Tab } from '../tab/tab.js';
54
import { isTab } from '../tab/tab.options.js';
65
import { swapStates, toggleState } from '../utils/element-internals.js';
@@ -101,15 +100,6 @@ export class BaseTablist extends FASTElement {
101100
this.$emit('change', this.activetab);
102101
};
103102

104-
/** @internal */
105-
public connectedCallback(): void {
106-
super.connectedCallback();
107-
108-
Updates.enqueue(() => {
109-
focusgroupPolyfill(this);
110-
});
111-
}
112-
113103
/**
114104
* Function that is invoked whenever the selected tab or the tab collection changes.
115105
*

packages/web-components/src/tablist/tablist.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { attr } from '@microsoft/fast-element';
1+
import { attr, Updates } from '@microsoft/fast-element';
2+
import { polyfill as focusgroupPolyfill } from '@microsoft/focusgroup-polyfill';
23
import type { Tab } from '../tab/tab.js';
34
import { BaseTablist } from './tablist.base.js';
45
import { TablistAppearance, TablistOrientation, TablistSize } from './tablist.options.js';
@@ -49,6 +50,15 @@ export class Tablist extends BaseTablist {
4950
@attr
5051
public size?: TablistSize;
5152

53+
/** @internal */
54+
public connectedCallback(): void {
55+
super.connectedCallback();
56+
57+
Updates.enqueue(() => {
58+
focusgroupPolyfill(this);
59+
});
60+
}
61+
5262
/**
5363
* calculateAnimationProperties
5464
*

packages/web-components/src/tree/tree.base.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { FASTElement, observable, Updates } from '@microsoft/fast-element';
2-
import { isHTMLElement, keyArrowLeft, keyArrowRight, keyEnter, keySpace } from '@microsoft/fast-web-utilities';
3-
import { polyfill as focusgroupPolyfill } from '@microsoft/focusgroup-polyfill';
1+
import { FASTElement, observable } from '@microsoft/fast-element';
2+
import { keyArrowLeft, keyArrowRight, keyEnter, keySpace } from '@microsoft/fast-web-utilities';
43
import type { BaseTreeItem } from '../tree-item/tree-item.base.js';
54
import { isTreeItem } from '../tree-item/tree-item.options.js';
65

@@ -45,15 +44,6 @@ export class BaseTree extends FASTElement {
4544
this.elementInternals.role = 'tree';
4645
}
4746

48-
/** @internal */
49-
connectedCallback() {
50-
super.connectedCallback();
51-
52-
Updates.enqueue(() => {
53-
focusgroupPolyfill(this);
54-
});
55-
}
56-
5747
/** @internal */
5848
@observable
5949
childTreeItems!: BaseTreeItem[];

packages/web-components/src/tree/tree.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { attr } from '@microsoft/fast-element';
1+
import { attr, Updates } from '@microsoft/fast-element';
2+
import { polyfill as focusgroupPolyfill } from '@microsoft/focusgroup-polyfill';
23
import type { TreeItem } from '../tree-item/tree-item.js';
34
import { TreeItemAppearance, TreeItemSize } from '../tree-item/tree-item.options.js';
45
import { BaseTree } from './tree.base.js';
@@ -47,6 +48,15 @@ export class Tree extends BaseTree {
4748
this.updateSizeAndAppearance();
4849
}
4950

51+
/** @internal */
52+
connectedCallback() {
53+
super.connectedCallback();
54+
55+
Updates.enqueue(() => {
56+
focusgroupPolyfill(this);
57+
});
58+
}
59+
5060
/**
5161
* 1. Update the child items' size based on the tree's size
5262
* 2. Update the child items' appearance based on the tree's appearance

0 commit comments

Comments
 (0)