Skip to content

Commit f75d2e2

Browse files
committed
fix(multiple): change aria keyboard manager to only handle repeated events in correct places
1 parent 977004b commit f75d2e2

File tree

12 files changed

+77
-44
lines changed

12 files changed

+77
-44
lines changed

src/aria/private/accordion/accordion.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ export class AccordionGroupPattern {
7474
/** The keydown event manager for the accordion trigger. */
7575
keydown = computed(() => {
7676
return new KeyboardEventManager()
77-
.on(this.prevKey, () => this.navigationBehavior.prev())
78-
.on(this.nextKey, () => this.navigationBehavior.next())
77+
.on(this.prevKey, () => this.navigationBehavior.prev(), {handleRepeat: true})
78+
.on(this.nextKey, () => this.navigationBehavior.next(), {handleRepeat: true})
7979
.on('Home', () => this.navigationBehavior.first())
8080
.on('End', () => this.navigationBehavior.last())
8181
.on(' ', () => this.toggle())

src/aria/private/behaviors/event-manager/event-manager.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface EventWithModifiers extends Event {
2424
* This library has not yet had a need for stopPropagationImmediate.
2525
*/
2626
export interface EventHandlerOptions {
27+
handleRepeat?: boolean;
2728
stopPropagation: boolean;
2829
preventDefault: boolean;
2930
}

src/aria/private/behaviors/event-manager/keyboard-event-manager.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type KeyCode = string | SignalLike<string> | RegExp;
3030
*/
3131
export class KeyboardEventManager<T extends KeyboardEvent> extends EventManager<T> {
3232
options: EventHandlerOptions = {
33+
handleRepeat: false,
3334
preventDefault: true,
3435
stopPropagation: true,
3536
};
@@ -50,7 +51,7 @@ export class KeyboardEventManager<T extends KeyboardEvent> extends EventManager<
5051

5152
this.configs.push({
5253
handler: handler,
53-
matcher: event => this._isMatch(event, key, modifiers),
54+
matcher: event => this._isMatch(event, key, modifiers, options),
5455
...this.options,
5556
...options,
5657
});
@@ -73,11 +74,20 @@ export class KeyboardEventManager<T extends KeyboardEvent> extends EventManager<
7374
};
7475
}
7576

76-
private _isMatch(event: T, key: KeyCode, modifiers: ModifierInputs) {
77+
private _isMatch(
78+
event: T,
79+
key: KeyCode,
80+
modifiers: ModifierInputs,
81+
options?: Partial<EventHandlerOptions>,
82+
): boolean {
7783
if (!hasModifiers(event, modifiers)) {
7884
return false;
7985
}
8086

87+
if (event.repeat && !options?.handleRepeat) {
88+
return false;
89+
}
90+
8191
if (key instanceof RegExp) {
8292
return key.test(event.key);
8393
}

src/aria/private/combobox/combobox.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,8 @@ export class ComboboxPattern<T extends ListItem<V>, V> {
250250
}
251251

252252
manager
253-
.on('ArrowDown', () => this.next())
254-
.on('ArrowUp', () => this.prev())
253+
.on('ArrowDown', () => this.next(), {handleRepeat: true})
254+
.on('ArrowUp', () => this.prev(), {handleRepeat: true})
255255
.on('Home', () => this.first())
256256
.on('End', () => this.last());
257257

src/aria/private/grid/cell.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,15 @@ export class GridCellPattern implements GridCell {
181181
// Start list navigation.
182182
manager
183183
.on('Escape', () => this.stopNavigation())
184-
.on(this.prevKey(), () =>
185-
this._advance(() => this.navigationBehavior.prev({focusElement: false})),
184+
.on(
185+
this.prevKey(),
186+
() => this._advance(() => this.navigationBehavior.prev({focusElement: false})),
187+
{handleRepeat: true},
186188
)
187-
.on(this.nextKey(), () =>
188-
this._advance(() => this.navigationBehavior.next({focusElement: false})),
189+
.on(
190+
this.nextKey(),
191+
() => this._advance(() => this.navigationBehavior.next({focusElement: false})),
192+
{handleRepeat: true},
189193
)
190194
.on('Home', () => this._advance(() => this.navigationBehavior.next({focusElement: false})))
191195
.on('End', () => this._advance(() => this.navigationBehavior.next({focusElement: false})));

src/aria/private/grid/grid.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@ export class GridPattern {
116116
selectOne: this.inputs.enableSelection() && this.inputs.selectionMode() === 'follow',
117117
};
118118
manager
119-
.on('ArrowUp', () => this.gridBehavior.up(opts))
120-
.on('ArrowDown', () => this.gridBehavior.down(opts))
121-
.on(this.prevColKey(), () => this.gridBehavior.left(opts))
122-
.on(this.nextColKey(), () => this.gridBehavior.right(opts))
119+
.on('ArrowUp', () => this.gridBehavior.up(opts), {handleRepeat: true})
120+
.on('ArrowDown', () => this.gridBehavior.down(opts), {handleRepeat: true})
121+
.on(this.prevColKey(), () => this.gridBehavior.left(opts), {handleRepeat: true})
122+
.on(this.nextColKey(), () => this.gridBehavior.right(opts), {handleRepeat: true})
123123
.on('Home', () => this.gridBehavior.firstInRow(opts))
124124
.on('End', () => this.gridBehavior.lastInRow(opts))
125125
.on([Modifier.Ctrl], 'Home', () => this.gridBehavior.first(opts))

src/aria/private/listbox/listbox.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,26 @@ export class ListboxPattern<V> {
7979

8080
if (this.readonly()) {
8181
return manager
82-
.on(this.prevKey, () => this.listBehavior.prev())
83-
.on(this.nextKey, () => this.listBehavior.next())
82+
.on(this.prevKey, () => this.listBehavior.prev(), {handleRepeat: true})
83+
.on(this.nextKey, () => this.listBehavior.next(), {handleRepeat: true})
8484
.on('Home', () => this.listBehavior.first())
8585
.on('End', () => this.listBehavior.last())
8686
.on(this.typeaheadRegexp, e => this.listBehavior.search(e.key));
8787
}
8888

8989
if (!this.followFocus()) {
9090
manager
91-
.on(this.prevKey, () => this.listBehavior.prev())
92-
.on(this.nextKey, () => this.listBehavior.next())
91+
.on(this.prevKey, () => this.listBehavior.prev(), {handleRepeat: true})
92+
.on(this.nextKey, () => this.listBehavior.next(), {handleRepeat: true})
9393
.on('Home', () => this.listBehavior.first())
9494
.on('End', () => this.listBehavior.last())
9595
.on(this.typeaheadRegexp, e => this.listBehavior.search(e.key));
9696
}
9797

9898
if (this.followFocus()) {
9999
manager
100-
.on(this.prevKey, () => this.listBehavior.prev({selectOne: true}))
101-
.on(this.nextKey, () => this.listBehavior.next({selectOne: true}))
100+
.on(this.prevKey, () => this.listBehavior.prev({selectOne: true}), {handleRepeat: true})
101+
.on(this.nextKey, () => this.listBehavior.next({selectOne: true}), {handleRepeat: true})
102102
.on('Home', () => this.listBehavior.first({selectOne: true}))
103103
.on('End', () => this.listBehavior.last({selectOne: true}))
104104
.on(this.typeaheadRegexp, e => this.listBehavior.search(e.key, {selectOne: true}));
@@ -107,8 +107,12 @@ export class ListboxPattern<V> {
107107
if (this.inputs.multi()) {
108108
manager
109109
.on(Modifier.Any, 'Shift', () => this.listBehavior.anchor(this.listBehavior.activeIndex()))
110-
.on(Modifier.Shift, this.prevKey, () => this.listBehavior.prev({selectRange: true}))
111-
.on(Modifier.Shift, this.nextKey, () => this.listBehavior.next({selectRange: true}))
110+
.on(Modifier.Shift, this.prevKey, () => this.listBehavior.prev({selectRange: true}), {
111+
handleRepeat: true,
112+
})
113+
.on(Modifier.Shift, this.nextKey, () => this.listBehavior.next({selectRange: true}), {
114+
handleRepeat: true,
115+
})
112116
.on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'Home', () =>
113117
this.listBehavior.first({selectRange: true, anchor: false}),
114118
)
@@ -137,8 +141,12 @@ export class ListboxPattern<V> {
137141

138142
if (this.inputs.multi() && this.followFocus()) {
139143
manager
140-
.on([Modifier.Ctrl, Modifier.Meta], this.prevKey, () => this.listBehavior.prev())
141-
.on([Modifier.Ctrl, Modifier.Meta], this.nextKey, () => this.listBehavior.next())
144+
.on([Modifier.Ctrl, Modifier.Meta], this.prevKey, () => this.listBehavior.prev(), {
145+
handleRepeat: true,
146+
})
147+
.on([Modifier.Ctrl, Modifier.Meta], this.nextKey, () => this.listBehavior.next(), {
148+
handleRepeat: true,
149+
})
142150
.on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.listBehavior.toggle())
143151
.on([Modifier.Ctrl, Modifier.Meta], 'Enter', () => this.listBehavior.toggle())
144152
.on([Modifier.Ctrl, Modifier.Meta], 'Home', () => this.listBehavior.first())

src/aria/private/menu/menu.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ export class MenuPattern<V> {
158158
/** Handles keyboard events for the menu. */
159159
keydownManager = computed(() => {
160160
return new KeyboardEventManager()
161-
.on('ArrowDown', () => this.next())
162-
.on('ArrowUp', () => this.prev())
161+
.on('ArrowDown', () => this.next(), {handleRepeat: true})
162+
.on('ArrowUp', () => this.prev(), {handleRepeat: true})
163163
.on('Home', () => this.first())
164164
.on('End', () => this.last())
165165
.on('Enter', () => this.trigger())
@@ -485,8 +485,8 @@ export class MenuBarPattern<V> {
485485
/** Handles keyboard events for the menu. */
486486
keydownManager = computed(() => {
487487
return new KeyboardEventManager()
488-
.on(this._nextKey, () => this.next())
489-
.on(this._previousKey, () => this.prev())
488+
.on(this._nextKey, () => this.next(), {handleRepeat: true})
489+
.on(this._previousKey, () => this.prev(), {handleRepeat: true})
490490
.on('End', () => this.listBehavior.last())
491491
.on('Home', () => this.listBehavior.first())
492492
.on('Enter', () => this.inputs.activeItem()?.open({first: true}))

src/aria/private/tabs/tabs.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,15 @@ export class TabListPattern {
184184
/** The keydown event manager for the tablist. */
185185
readonly keydown = computed(() => {
186186
return new KeyboardEventManager()
187-
.on(this.prevKey, () =>
188-
this._navigate(() => this.navigationBehavior.prev(), this.followFocus()),
187+
.on(
188+
this.prevKey,
189+
() => this._navigate(() => this.navigationBehavior.prev(), this.followFocus()),
190+
{handleRepeat: true},
189191
)
190-
.on(this.nextKey, () =>
191-
this._navigate(() => this.navigationBehavior.next(), this.followFocus()),
192+
.on(
193+
this.nextKey,
194+
() => this._navigate(() => this.navigationBehavior.next(), this.followFocus()),
195+
{handleRepeat: true},
192196
)
193197
.on('Home', () => this._navigate(() => this.navigationBehavior.first(), this.followFocus()))
194198
.on('End', () => this._navigate(() => this.navigationBehavior.last(), this.followFocus()))

src/aria/private/toolbar/toolbar.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ export class ToolbarPattern<V> {
8080
const manager = new KeyboardEventManager();
8181

8282
return manager
83-
.on(this._nextKey, () => this.listBehavior.next())
84-
.on(this._prevKey, () => this.listBehavior.prev())
85-
.on(this._altNextKey, () => this._groupNext())
86-
.on(this._altPrevKey, () => this._groupPrev())
83+
.on(this._nextKey, () => this.listBehavior.next(), {handleRepeat: true})
84+
.on(this._prevKey, () => this.listBehavior.prev(), {handleRepeat: true})
85+
.on(this._altNextKey, () => this._groupNext(), {handleRepeat: true})
86+
.on(this._altPrevKey, () => this._groupPrev(), {handleRepeat: true})
8787
.on(' ', () => this.select())
8888
.on('Enter', () => this.select())
8989
.on('Home', () => this.listBehavior.first())
@@ -179,7 +179,7 @@ export class ToolbarPattern<V> {
179179

180180
/** Handles click events for the toolbar. */
181181
onClick(event: MouseEvent) {
182-
if (this.disabled()) return;
182+
if (this.disabled() || (event as PointerEvent).pointerType === '') return;
183183
this._goto(event);
184184
}
185185

0 commit comments

Comments
 (0)