diff --git a/src/lib/PeriodicTable.svelte b/src/lib/PeriodicTable.svelte index 9078baf..fa74690 100644 --- a/src/lib/PeriodicTable.svelte +++ b/src/lib/PeriodicTable.svelte @@ -134,6 +134,8 @@ {...tile_props} on:mouseenter={set_active_element(element)} on:mouseleave={set_active_element(null)} + on:focus={set_active_element(element)} + on:blur={set_active_element(null)} on:click on:mouseenter on:mouseleave diff --git a/src/lib/index.ts b/src/lib/index.ts index c3004a1..231633d 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -82,4 +82,6 @@ export type PeriodicTableEvents = { mouseleave: DispatchPayload keyup: DispatchPayload keydown: DispatchPayload + focus: DispatchPayload + blur: DispatchPayload } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 01ef244..17d4445 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -24,15 +24,15 @@ .filter(({ filename }) => filename.includes(`/(demos)/`)) .map(({ route }) => route) - const actions = element_data - .map(({ name }) => name) - .concat(routes.map(({ route }) => route)) + const actions = routes + .map(({ route }) => route) + .concat(element_data.map(({ name }) => `/${name.toLowerCase()}`)) .map((name) => { - return { label: name, action: () => goto(name.toLowerCase()) } + return { label: name, action: () => goto(name) } }) - + diff --git a/tests/unit/periodic-table.test.ts b/tests/unit/periodic-table.test.ts index ec80e70..684e940 100644 --- a/tests/unit/periodic-table.test.ts +++ b/tests/unit/periodic-table.test.ts @@ -4,6 +4,9 @@ import { tick } from 'svelte' import { describe, expect, test, vi } from 'vitest' import { doc_query } from '.' +const mouseenter = new MouseEvent(`mouseenter`) +const mouseleave = new MouseEvent(`mouseleave`) + describe(`PeriodicTable`, () => { test.each([ [true, 120], @@ -43,11 +46,11 @@ describe(`PeriodicTable`, () => { const element_tile = doc_query(`.element-tile`) - element_tile?.dispatchEvent(new MouseEvent(`mouseenter`)) + element_tile?.dispatchEvent(mouseenter) await tick() expect([...element_tile.classList]).toContain(`active`) - element_tile?.dispatchEvent(new MouseEvent(`mouseleave`)) + element_tile?.dispatchEvent(mouseleave) await tick() expect([...element_tile.classList]).not.toContain(`active`) }) @@ -60,13 +63,13 @@ describe(`PeriodicTable`, () => { const element_tile = document.querySelectorAll(`.element-tile`)[rand_idx] - element_tile?.dispatchEvent(new MouseEvent(`mouseenter`)) + element_tile?.dispatchEvent(mouseenter) await tick() const element_photo = doc_query(`img[alt="${random_element.name}"]`) expect(element_photo?.style.gridArea).toBe(`9/1/span 2/span 2`) - element_tile?.dispatchEvent(new MouseEvent(`mouseleave`)) + element_tile?.dispatchEvent(mouseleave) await tick() expect(document.querySelector(`img`)).toBeNull() }) @@ -129,7 +132,7 @@ describe(`PeriodicTable`, () => { expect(emitted).toBe(true) expected_active = true - element_tile?.dispatchEvent(new MouseEvent(`mouseenter`)) + element_tile?.dispatchEvent(mouseenter) await tick() element_tile?.dispatchEvent(new MouseEvent(`click`)) @@ -190,4 +193,38 @@ describe(`PeriodicTable`, () => { ) } ) + + test(`element tiles are accessible to keyboard users`, async () => { + new PeriodicTable({ target: document.body }) + + const element_tiles = document.querySelectorAll(`.element-tile`) + + // Simulate keyboard navigation of the element tiles + let activeIndex = 0 + element_tiles[activeIndex].dispatchEvent(mouseenter) + await tick() + expect(element_tiles[activeIndex].classList.contains(`active`)).toBe(true) + expect(element_tiles[activeIndex].textContent?.trim()).toBe(`1 H Hydrogen`) + + // Press the down arrow key to move to the next row + window.dispatchEvent(new KeyboardEvent(`keydown`, { key: `ArrowDown` })) + await tick() + activeIndex += 2 + expect(element_tiles[activeIndex].classList.contains(`active`)).toBe(true) + expect(element_tiles[activeIndex].textContent?.trim()).toBe(`3 Li Lithium`) + + // Press the right arrow key to move to the next column + activeIndex += 1 + window.dispatchEvent(new KeyboardEvent(`keydown`, { key: `ArrowRight` })) + await tick() + expect(element_tiles[activeIndex].textContent?.trim()).toBe( + `4 Be Beryllium` + ) + + // Press the left arrow key to move back to the previous column + activeIndex -= 1 + window.dispatchEvent(new KeyboardEvent(`keydown`, { key: `ArrowLeft` })) + await tick() + expect(element_tiles[activeIndex].textContent?.trim()).toBe(`3 Li Lithium`) + }) })