Skip to content

Commit f905d4d

Browse files
committed
correction of selectableMixin for keyboard navigation
1 parent 976b568 commit f905d4d

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

packages/uui-base/lib/mixins/SelectableMixin.ts

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ export const SelectableMixin = <T extends Constructor<LitElement>>(
5252
}
5353
set selectable(newVal) {
5454
const oldVal = this._selectable;
55+
if (oldVal === newVal) return;
5556
this._selectable = newVal;
57+
5658
// Potentially problematic as a component might need focus for another feature when not selectable:
57-
if (this.selectableTarget === this) {
58-
// If the selectable target, then make it self selectable. (A different selectable target should be made focusable by the component itself)
59-
this.setAttribute('tabindex', `${newVal ? '0' : '-1'}`);
60-
}
59+
//if (this.#selectableTarget === this) {
60+
// If the selectable target, then make it self selectable. (A different selectable target should be made focusable by the component itself)
61+
this.#selectableTarget.setAttribute('tabindex', `${newVal ? '0' : '-1'}`);
62+
//}
6163
this.requestUpdate('selectable', oldVal);
6264
}
6365

@@ -71,7 +73,28 @@ export const SelectableMixin = <T extends Constructor<LitElement>>(
7173
@property({ type: Boolean, reflect: true })
7274
public selected = false;
7375

74-
protected selectableTarget: EventTarget = this;
76+
#selectableTarget: Element = this;
77+
protected get selectableTarget(): EventTarget {
78+
return this.#selectableTarget;
79+
}
80+
protected set selectableTarget(target: EventTarget) {
81+
const oldTarget = this.#selectableTarget;
82+
83+
oldTarget.removeAttribute('tabindex');
84+
oldTarget.removeEventListener('click', this.#onClick);
85+
oldTarget.removeEventListener(
86+
'keydown',
87+
this.#onKeydown as EventListener,
88+
);
89+
90+
this.#selectableTarget = target as Element;
91+
this.#selectableTarget.setAttribute(
92+
'tabindex',
93+
this._selectable ? '0' : '-1',
94+
);
95+
target.addEventListener('click', this.#onClick);
96+
target.addEventListener('keydown', this.#onKeydown as EventListener);
97+
}
7598

7699
constructor(...args: any[]) {
77100
super(...args);
@@ -80,17 +103,8 @@ export const SelectableMixin = <T extends Constructor<LitElement>>(
80103
}
81104

82105
readonly #onKeydown = (e: KeyboardEvent) => {
83-
const composePath = e.composedPath();
84-
if (
85-
(this._selectable || (this.deselectable && this.selected)) &&
86-
composePath.indexOf(this.selectableTarget) === 0
87-
) {
88-
if (this.selectableTarget === this) {
89-
if (e.code !== 'Space' && e.code !== 'Enter') return;
90-
this.#toggleSelect();
91-
e.preventDefault();
92-
}
93-
}
106+
if (e.code !== 'Space' && e.code !== 'Enter') return;
107+
this.#onClick(e);
94108
};
95109

96110
readonly #onClick = (e: Event) => {
@@ -99,12 +113,18 @@ export const SelectableMixin = <T extends Constructor<LitElement>>(
99113

100114
if (isSelectable === false) return;
101115

102-
if (this.selectableTarget === this) {
116+
if (this.#selectableTarget === this) {
103117
// If target is this, then only allow selection if the click is on the element itself.
104-
if (e.composedPath().indexOf(this.selectableTarget) === 0) {
118+
if (e.composedPath().indexOf(this.#selectableTarget) === 0) {
119+
if (e.type === 'keydown') {
120+
e.preventDefault(); // Do not want the space key to trigger a page scroll.
121+
}
105122
this.#toggleSelect();
106123
}
107-
} else if (e.composedPath().indexOf(this.selectableTarget) !== -1) {
124+
} else if (e.composedPath().indexOf(this.#selectableTarget) !== -1) {
125+
if (e.type === 'keydown') {
126+
e.preventDefault(); // Do not want the space key to trigger a page scroll.
127+
}
108128
this.#toggleSelect();
109129
}
110130
};

0 commit comments

Comments
 (0)