Skip to content

Commit

Permalink
APP-3122: make floating menu controlled, add aria props
Browse files Browse the repository at this point in the history
  • Loading branch information
mcous committed Nov 29, 2023
1 parent 92734ad commit 4906e5f
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 39 deletions.
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@viamrobotics/prime-core",
"version": "0.0.66",
"version": "0.0.67",
"publishConfig": {
"access": "public"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<script lang="ts">
import FloatingMenu from '../floating-menu.svelte';
import ContextMenuItem from '../context-menu-item.svelte';
let isOpen = false;
const handleChange = (nextIsOpen: boolean) => (isOpen = nextIsOpen);
</script>

<FloatingMenu>
<span
slot="control"
let:isOpen
>
<FloatingMenu
{isOpen}
onChange={handleChange}
>
<span slot="control">
{isOpen ? 'close' : 'open'}
</span>
<svelte:fragment
slot="items"
let:closeMenu
>
<ContextMenuItem on:click={closeMenu}>item</ContextMenuItem>
<svelte:fragment slot="items">
<ContextMenuItem on:click={() => (isOpen = false)}>item</ContextMenuItem>
</svelte:fragment>
</FloatingMenu>
<span data-testid="outside-element" />
24 changes: 11 additions & 13 deletions packages/core/src/lib/context-menu/floating-menu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ import { clickOutside } from '$lib/click-outside';
import { floatingStyle, type FloatingMenuPlacement } from './floating-style';
import ContextMenu from './context-menu.svelte';
export let isOpen: boolean;
export let placement: FloatingMenuPlacement = 'bottom-start';
export let offset = 0;
export let buttonCX: cx.Argument = '';
export let menuCX: cx.Argument = '';
export let label: string | undefined = undefined;
export let describedBy: string | undefined = undefined;
export let onChange: (isOpen: boolean) => unknown;
const menuID = uniqueId('floating-menu');
const style = floatingStyle();
const openMenu = () => onChange(true);
const closeMenu = () => onChange(false);
let isOpen = false;
let controlElement: HTMLElement | undefined;
let menuElement: HTMLElement | undefined;
const openMenu = () => (isOpen = true);
const closeMenu = () => (isOpen = false);
const handleClickOutside = (element: Element) => {
if (!controlElement?.contains(element)) {
closeMenu();
Expand All @@ -36,20 +38,19 @@ const handleEscape = (event: KeyboardEvent) => {
$: style.register({ controlElement, menuElement, placement, offset });
</script>

<svelte:document on:keydown={isOpen ? handleEscape : undefined} />
<svelte:window on:keydown={isOpen ? handleEscape : undefined} />

<button
class={cx(buttonCX)}
aria-haspopup="menu"
aria-controls={menuID}
aria-expanded={isOpen}
aria-label={label}
aria-describedby={describedBy}
on:click={isOpen ? closeMenu : openMenu}
bind:this={controlElement}
>
<slot
name="control"
{isOpen}
/>
<slot name="control" />
</button>

{#if isOpen}
Expand All @@ -65,10 +66,7 @@ $: style.register({ controlElement, menuElement, placement, offset });
id={menuID}
cx={menuCX}
>
<slot
name="items"
{closeMenu}
/>
<slot name="items" />
</ContextMenu>
</div>
{/if}
14 changes: 9 additions & 5 deletions packages/core/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ provideNotify();
let buttonClickedTimes = 0;
let preventHandlerDisabled = true;
let modalOpen = false;
let floatingMenuOpen = false;
const handleTogglePreventHandler = (event: CustomEvent<boolean>) => {
preventHandlerDisabled = event.detail;
Expand All @@ -61,6 +62,10 @@ const handleOpenModal = () => {
modalOpen = true;
};
const handleFloatingMenuChange = (isOpen: boolean) => {
floatingMenuOpen = isOpen;
};
const notify = useNotify();
let restrictedValue = '';
Expand Down Expand Up @@ -699,14 +704,13 @@ const htmlSnippet = `
</ContextMenu>

<FloatingMenu
isOpen={floatingMenuOpen}
placement="top-start"
offset={4}
onChange={handleFloatingMenuChange}
>
<svelte:fragment
slot="control"
let:isOpen
>
{isOpen ? 'Close menu' : 'Open menu'}
<svelte:fragment slot="control">
{floatingMenuOpen ? 'Close menu' : 'Open menu'}
</svelte:fragment>
<svelte:fragment slot="items">
<ContextMenuItem>label 1</ContextMenuItem>
Expand Down
22 changes: 12 additions & 10 deletions packages/storybook/src/stories/context-menu.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import {
} from '@viamrobotics/prime-core';
const menuID = uniqueId('context-menu');
let floatingMenuOpen = false;
const setFloatingMenuOpen = (isOpen: boolean) => {
floatingMenuOpen = isOpen;
};
</script>

<Meta title="Elements/Context menu" />
Expand All @@ -32,25 +38,21 @@ const menuID = uniqueId('context-menu');
<FloatingMenu
placement="bottom-start"
offset={4}
isOpen={floatingMenuOpen}
onChange={setFloatingMenuOpen}
>
<svelte:fragment
slot="control"
let:isOpen
>
{isOpen ? 'Close menu' : 'Open menu'}
<svelte:fragment slot="control">
{floatingMenuOpen ? 'Close menu' : 'Open menu'}
</svelte:fragment>
<svelte:fragment
slot="items"
let:closeMenu
>
<svelte:fragment slot="items">
<ContextMenuItem>Just a label</ContextMenuItem>
<ContextMenuItem icon="trash-can-outline">With icon</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuItem variant="primary">Primary</ContextMenuItem>
<ContextMenuItem
icon="close"
variant="danger"
on:click={closeMenu}
on:click={() => setFloatingMenuOpen(false)}
>
Danger
</ContextMenuItem>
Expand Down

0 comments on commit 4906e5f

Please sign in to comment.