mirror of https://github.com/immich-app/immich.git
feat(web): Add keyboard shortcut selection on grid (#16713)
* 15712: Added keyboard shortcuts for opening add to album modal and highlighting/selecting an album to add to. * 15712: Re-factored logic from template code into script. Extracted new album button into separate cmponent. * 15712: Document new keyboard shortucts now that they work everywhere. * 15712: Extract some constants/helper functions. * 15712: Missing comma. * 15712: Pulled logic out into separate unit testable class. * 15712: Added a unit test. * 15712: Move the modal back up to keep the github PR happy. * 15712: PR feedback - renamed typescript files and switch to class bind directive. * 15712:Move selection modal into correct package. * 15712: Better naming of module and files. * 15712: Add asset highlight using arrow keys. * 15172: Add escape behaviour everywhere. * 15712: Don't allow highlighting past start or end. * 15712: Clear the highlight on changes to the component state. * 15712: Use focus to track highlighted element. * 15712: Rename highlight -> focussed. * 15712: Better naming. * 15712: Cleanup. * 15712: Cleanup & simplify. * 15712: bugfix for clicking on button. * 15712: Cleanup. * 15712: Rollback unnecessary changes. * 15712: Add unit test. * 15712: Add thumbnail unit test. * 15712: Prettier. * 15712: Fix merge issue. * 15712: Add shortcut info. * 15712: Fix linter.pull/16811/head
parent
c80afea468
commit
b8acae2f21
@ -0,0 +1,63 @@
|
||||
import { getIntersectionObserverMock } from '$lib/__mocks__/intersection-observer.mock';
|
||||
import Thumbnail from '$lib/components/assets/thumbnail/thumbnail.svelte';
|
||||
import { assetFactory } from '@test-data/factories/asset-factory';
|
||||
import { fireEvent, render, screen } from '@testing-library/svelte';
|
||||
|
||||
describe('Thumbnail component', () => {
|
||||
beforeAll(() => {
|
||||
vi.stubGlobal('IntersectionObserver', getIntersectionObserverMock());
|
||||
});
|
||||
|
||||
it('should only contain a single tabbable element (the container)', () => {
|
||||
const asset = assetFactory.build({ originalPath: 'image.jpg', originalMimeType: 'image/jpeg' });
|
||||
render(Thumbnail, {
|
||||
asset,
|
||||
focussed: false,
|
||||
overrideDisplayForTest: true,
|
||||
selected: true,
|
||||
});
|
||||
|
||||
const container = screen.getByTestId('container-with-tabindex');
|
||||
expect(container.getAttribute('tabindex')).toBe('0');
|
||||
|
||||
// This isn't capturing all tabbable elements, but should be the most likely ones. Mainly guarding against
|
||||
// inserting extra tabbable elments in future in <Thumbnail/>
|
||||
let allTabbableElements = screen.queryAllByRole('link');
|
||||
allTabbableElements = allTabbableElements.concat(screen.queryAllByRole('checkbox'));
|
||||
expect(allTabbableElements.length).toBeGreaterThan(0);
|
||||
for (const tabbableElement of allTabbableElements) {
|
||||
const testIdValue = tabbableElement.dataset.testid;
|
||||
if (testIdValue === null || testIdValue !== 'container-with-tabindex') {
|
||||
expect(tabbableElement.getAttribute('tabindex')).toBe('-1');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('handleFocus should be called on focus of container', async () => {
|
||||
const asset = assetFactory.build({ originalPath: 'image.jpg', originalMimeType: 'image/jpeg' });
|
||||
const handleFocusSpy = vi.fn();
|
||||
render(Thumbnail, {
|
||||
asset,
|
||||
overrideDisplayForTest: true,
|
||||
handleFocus: handleFocusSpy,
|
||||
});
|
||||
|
||||
const container = screen.getByTestId('container-with-tabindex');
|
||||
await fireEvent(container, new FocusEvent('focus'));
|
||||
|
||||
expect(handleFocusSpy).toBeCalled();
|
||||
});
|
||||
|
||||
it('element will be focussed if not already', () => {
|
||||
const asset = assetFactory.build({ originalPath: 'image.jpg', originalMimeType: 'image/jpeg' });
|
||||
const handleFocusSpy = vi.fn();
|
||||
render(Thumbnail, {
|
||||
asset,
|
||||
overrideDisplayForTest: true,
|
||||
focussed: true,
|
||||
handleFocus: handleFocusSpy,
|
||||
});
|
||||
|
||||
expect(handleFocusSpy).toBeCalled();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue