Skip to content

Commit

Permalink
fix: refining the little details
Browse files Browse the repository at this point in the history
- adjust the aria attributes
- intuitive escape key propagation
- extract context into its own file
  • Loading branch information
ben-basten committed Jun 11, 2024
1 parent 84fdc9e commit 13a4598
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 20 deletions.
9 changes: 9 additions & 0 deletions web/src/lib/actions/list-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ interface Options {
* A function that is called when the dropdown should be closed.
*/
closeDropdown: () => void;
/**
* Override the default behavior for the escape key.
*/
onEscape?: (event: KeyboardEvent) => void;
}

export const listNavigation: Action<HTMLElement, Options> = (node, options: Options) => {
Expand Down Expand Up @@ -80,6 +84,11 @@ export const listNavigation: Action<HTMLElement, Options> = (node, options: Opti
};

const onEscape = (event: KeyboardEvent) => {
const { onEscape } = options;
if (onEscape) {
onEscape(event);
return;
}
event.stopPropagation();
close();
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
<script lang="ts" context="module">
import { clickOutside } from '$lib/actions/click-outside';
import { createContext } from '$lib/utils/context';
const { get: getMenuContext, set: setContext } = createContext<() => void>('context-menu');
export { getMenuContext };
</script>

<script lang="ts">
import CircleIconButton, { type Color } from '$lib/components/elements/buttons/circle-icon-button.svelte';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import { setMenuContext } from '$lib/components/shared-components/context-menu/menu.context';
import { getContextMenuPosition, type Align } from '$lib/utils/context-menu';
import { shortcuts } from '$lib/actions/shortcut';
import { focusOutside } from '$lib/actions/focus-outside';
import { listNavigation } from '$lib/actions/list-navigation';
import { clickOutside } from '$lib/actions/click-outside';
import { generateId } from '$lib/utils/generate-id';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
Expand Down Expand Up @@ -43,10 +37,10 @@
let menuContainer: HTMLUListElement;
let buttonContainer: HTMLDivElement;
let selectedId: string | undefined = undefined;
let id = generateId();
$: buttonId = `context-menu-button-${id}`;
$: menuId = `context-menu-${id}`;
const id = generateId();
const buttonId = `context-menu-button-${id}`;
const menuId = `context-menu-${id}`;
const openDropdown = (event: KeyboardEvent) => {
contextMenuPosition = getContextMenuPosition(event, align);
Expand All @@ -67,12 +61,20 @@
}
};
const onEscape = (event: KeyboardEvent) => {
if (showContextMenu) {
// if the dropdown is open, stop the event from propagating
event.stopPropagation();
}
closeDropdown();
};
const closeDropdown = () => {
selectedId = undefined;
showContextMenu = false;
};
setContext(() => {
setMenuContext(() => {
showContextMenu = false;
const button: HTMLButtonElement | null = buttonContainer.querySelector(`#${buttonId}`);
button?.focus();
Expand All @@ -95,6 +97,7 @@
openDropdown,
closeDropdown,
selectionChanged: (node) => (selectedId = node?.id),
onEscape,
}}
bind:this={buttonContainer}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
</script>

<div
aria-labelledby={ariaLabelledBy}
bind:clientHeight={height}
class="absolute z-10 min-w-[200px] w-max max-w-[300px] overflow-hidden rounded-lg shadow-lg"
style:left="{left}px"
Expand All @@ -45,6 +44,7 @@
<ul
{id}
aria-activedescendant={ariaActiveDescendant}
aria-labelledby={ariaLabelledBy}
bind:this={menuElement}
class:max-h-[100vh]={isVisible}
class:max-h-0={!isVisible}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import { generateId } from '$lib/utils/generate-id';
import { getMenuContext } from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import { getMenuContext } from '$lib/components/shared-components/context-menu/menu.context';
import { createEventDispatcher } from 'svelte';
export let text = '';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createContext } from '$lib/utils/context';

const { get: getMenuContext, set: setMenuContext } = createContext<() => void>();

export { getMenuContext, setMenuContext };
3 changes: 0 additions & 3 deletions web/src/lib/components/shared-components/context-menu/menu.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<script lang="ts">
import { setContext, tick } from 'svelte';
import { tick } from 'svelte';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import { shortcuts } from '$lib/actions/shortcut';
import { listNavigation } from '$lib/actions/list-navigation';
import { generateId } from '$lib/utils/generate-id';
import { setMenuContext } from '$lib/components/shared-components/context-menu/menu.context';
export let title: string;
export let direction: 'left' | 'right' = 'right';
Expand All @@ -17,6 +19,10 @@
let triggerElement: HTMLElement | undefined = undefined;
let buttonElement: HTMLButtonElement;
const id = generateId();
const buttonId = `context-menu-button-${id}`;
const menuId = `context-menu-${id}`;
$: {
if (isOpen && buttonElement) {
triggerElement = document.activeElement as HTMLElement;
Expand Down Expand Up @@ -63,12 +69,16 @@
}
};
setContext('context-menu', closeContextMenu);
setMenuContext(closeContextMenu);
</script>

{#key uniqueKey}
{#if isOpen}
<button
aria-controls={menuId}
aria-haspopup={true}
aria-expanded={isOpen}
id={buttonId}
bind:this={buttonElement}
type="button"
class="sr-only"
Expand Down Expand Up @@ -102,7 +112,17 @@
on:contextmenu|preventDefault={reopenContextMenu}
role="presentation"
>
<ContextMenu {x} {y} {direction} onClose={closeContextMenu} bind:menuElement={contextMenuElement} isVisible>
<ContextMenu
{direction}
{x}
{y}
ariaActiveDescendant={selectedId}
ariaLabelledBy={buttonId}
bind:menuElement={contextMenuElement}
id={menuId}
isVisible
onClose={closeContextMenu}
>
<slot />
</ContextMenu>
</section>
Expand Down

0 comments on commit 13a4598

Please sign in to comment.