Skip to content

Commit f6ba852

Browse files
committed
simplify ignoreWhenEditable guard for shortcuts
1 parent 15b223e commit f6ba852

4 files changed

Lines changed: 4 additions & 128 deletions

File tree

src/shared/shortcut.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,29 +75,10 @@ export type ShortcutOptions = {
7575
};
7676

7777
function isEditableTarget(target: EventTarget | null): boolean {
78-
if (!(target instanceof HTMLElement)) {
79-
return false;
80-
}
81-
if (target.isContentEditable) {
82-
return true;
83-
}
84-
if (
85-
target.closest('[role="textbox"], [role="searchbox"]') instanceof
86-
HTMLElement
87-
) {
88-
return true;
89-
}
90-
if (target instanceof HTMLTextAreaElement) {
91-
return true;
92-
}
93-
if (target instanceof HTMLInputElement) {
94-
try {
95-
return target.selectionStart !== null;
96-
} catch {
97-
return false;
98-
}
99-
}
100-
return false;
78+
return (
79+
target instanceof HTMLElement &&
80+
(target.isContentEditable || ['INPUT', 'TEXTAREA'].includes(target.tagName))
81+
);
10182
}
10283

10384
/**

src/shared/test/shortcut-test.js

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -202,67 +202,6 @@ describe('shared/shortcut', () => {
202202

203203
assert.called(onPress);
204204
});
205-
206-
it('fires shortcut when input selectionStart cannot be read', () => {
207-
const onPress = sinon.stub();
208-
const removeShortcut = installShortcut('a', onPress, {
209-
ignoreWhenEditable: true,
210-
});
211-
212-
const input = document.createElement('input');
213-
Object.defineProperty(input, 'selectionStart', {
214-
get() {
215-
throw new Error('no selectionStart');
216-
},
217-
});
218-
const event = new KeyboardEvent('keydown', { key: 'a', bubbles: true });
219-
Object.defineProperty(event, 'target', { value: input });
220-
221-
document.documentElement.dispatchEvent(event);
222-
removeShortcut();
223-
224-
assert.called(onPress);
225-
});
226-
227-
it('does not trigger when target has role="textbox" if ignoreWhenEditable is set', () => {
228-
const onPress = sinon.stub();
229-
const textbox = document.createElement('div');
230-
textbox.setAttribute('role', 'textbox');
231-
document.body.appendChild(textbox);
232-
233-
const removeShortcut = installShortcut('a', onPress, {
234-
ignoreWhenEditable: true,
235-
});
236-
237-
const event = new KeyboardEvent('keydown', { key: 'a', bubbles: true });
238-
Object.defineProperty(event, 'target', { value: textbox });
239-
document.documentElement.dispatchEvent(event);
240-
241-
removeShortcut();
242-
document.body.removeChild(textbox);
243-
244-
assert.notCalled(onPress);
245-
});
246-
247-
it('still triggers when target has a non-editable ARIA role if ignoreWhenEditable is set', () => {
248-
const onPress = sinon.stub();
249-
const nonEditable = document.createElement('div');
250-
nonEditable.setAttribute('role', 'button');
251-
document.body.appendChild(nonEditable);
252-
253-
const removeShortcut = installShortcut('a', onPress, {
254-
ignoreWhenEditable: true,
255-
});
256-
257-
const event = new KeyboardEvent('keydown', { key: 'a', bubbles: true });
258-
Object.defineProperty(event, 'target', { value: nonEditable });
259-
document.documentElement.dispatchEvent(event);
260-
261-
removeShortcut();
262-
document.body.removeChild(nonEditable);
263-
264-
assert.called(onPress);
265-
});
266205
});
267206

268207
describe('useShortcut', () => {

src/sidebar/components/search/SearchIconButton.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,6 @@ function useSearchKeyboardShortcuts(store: SidebarStore) {
2222

2323
const openSearch = useCallback(
2424
(event: KeyboardEvent) => {
25-
// When user is in an input field, respond to CMD-/CTRL-K keypresses,
26-
// but ignore '/' keypresses
27-
if (
28-
!event.metaKey &&
29-
!event.ctrlKey &&
30-
event.target instanceof HTMLElement &&
31-
['INPUT', 'TEXTAREA'].includes(event.target.tagName)
32-
) {
33-
return;
34-
}
3525
prevFocusRef.current = document.activeElement as HTMLOrSVGElement | null;
3626
if (!store.isSidebarPanelOpen('searchAnnotations')) {
3727
store.openSidebarPanel('searchAnnotations');

src/sidebar/components/search/test/SearchIconButton-test.js

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -155,40 +155,6 @@ describe('SearchIconButton', () => {
155155
assert.notCalled(fakeStore.openSidebarPanel);
156156
});
157157

158-
it('returns early when "/" shortcut handler is invoked while focus is in an input', () => {
159-
const handlers = [];
160-
161-
$imports.$mock({
162-
'../../../shared/shortcut': {
163-
useShortcut: (shortcut, handler) =>
164-
handlers.push({ shortcut, handler }),
165-
},
166-
});
167-
168-
const input = document.createElement('input');
169-
document.body.append(input);
170-
171-
try {
172-
createSearchIconButton();
173-
174-
const openSearchHandler = handlers.find(
175-
h => h.shortcut === '/',
176-
)?.handler;
177-
assert.ok(openSearchHandler, 'handler for "/" should be registered');
178-
179-
openSearchHandler({
180-
key: '/',
181-
metaKey: false,
182-
ctrlKey: false,
183-
target: input,
184-
});
185-
186-
assert.notCalled(fakeStore.openSidebarPanel);
187-
} finally {
188-
input.remove();
189-
}
190-
});
191-
192158
it('opens search panel for macOS when "Cmd-K" is pressed outside of the component element', () => {
193159
fakeIsMacOS.returns(true);
194160
createSearchIconButton();

0 commit comments

Comments
 (0)