Add action forwarding and add to Menu

This commit is contained in:
Ryan Gossiaux
2021-12-13 22:08:22 -08:00
parent 48ae497beb
commit 0fe7b0ea04
5 changed files with 94 additions and 1 deletions

View File

@@ -7,6 +7,7 @@
import { writable, Writable } from "svelte/store"; import { writable, Writable } from "svelte/store";
import { State } from "$lib/internal/open-closed"; import { State } from "$lib/internal/open-closed";
import { match } from "$lib/utils/match"; import { match } from "$lib/utils/match";
import { ActionArray, useActions } from "$lib/hooks/use-actions";
export enum MenuStates { export enum MenuStates {
Open, Open,
Closed, Closed,
@@ -49,6 +50,7 @@
</script> </script>
<script lang="ts"> <script lang="ts">
export let use: ActionArray = [];
let menuState: StateDefinition["menuState"] = MenuStates.Closed; let menuState: StateDefinition["menuState"] = MenuStates.Closed;
let buttonStore: StateDefinition["buttonStore"] = writable(null); let buttonStore: StateDefinition["buttonStore"] = writable(null);
let itemsStore: StateDefinition["itemsStore"] = writable(null); let itemsStore: StateDefinition["itemsStore"] = writable(null);
@@ -146,6 +148,6 @@
</script> </script>
<svelte:window on:mousedown={handleWindowMousedown} /> <svelte:window on:mousedown={handleWindowMousedown} />
<div {...$$restProps}> <div use:useActions={use} {...$$restProps}>
<slot /> <slot />
</div> </div>

View File

@@ -4,6 +4,8 @@
import { Keys } from "$lib/utils/keyboard"; import { Keys } from "$lib/utils/keyboard";
import { Focus } from "$lib/utils/calculate-active-index"; import { Focus } from "$lib/utils/calculate-active-index";
import { tick } from "svelte"; import { tick } from "svelte";
import { ActionArray, useActions } from "$lib/hooks/use-actions";
export let use: ActionArray = [];
export let disabled = false; export let disabled = false;
const api = useMenuContext("MenuButton"); const api = useMenuContext("MenuButton");
const id = `headlessui-menu-button-${useId()}`; const id = `headlessui-menu-button-${useId()}`;
@@ -73,6 +75,7 @@
<button <button
{...{ ...$$restProps, ...propsWeControl }} {...{ ...$$restProps, ...propsWeControl }}
bind:this={$buttonStore} bind:this={$buttonStore}
use:useActions={use}
on:click={handleClick} on:click={handleClick}
on:keydown={handleKeyDown} on:keydown={handleKeyDown}
on:keyup={handleKeyUp} on:keyup={handleKeyUp}

View File

@@ -3,6 +3,8 @@
import { useId } from "$lib/hooks/use-id"; import { useId } from "$lib/hooks/use-id";
import { Focus } from "$lib/utils/calculate-active-index"; import { Focus } from "$lib/utils/calculate-active-index";
import { afterUpdate, onDestroy, onMount, tick } from "svelte"; import { afterUpdate, onDestroy, onMount, tick } from "svelte";
import { ActionArray, useActions } from "$lib/hooks/use-actions";
export let use: ActionArray = [];
export let disabled = false; export let disabled = false;
const api = useMenuContext("MenuItem"); const api = useMenuContext("MenuItem");
const id = `headlessui-menu-item-${useId()}`; const id = `headlessui-menu-item-${useId()}`;
@@ -68,6 +70,7 @@
<div <div
{...{ ...$$restProps, ...propsWeControl }} {...{ ...$$restProps, ...propsWeControl }}
bind:this={elementRef} bind:this={elementRef}
use:useActions={use}
on:click={handleClick} on:click={handleClick}
on:focus={handleFocus} on:focus={handleFocus}
on:pointermove={handleMove} on:pointermove={handleMove}

View File

@@ -7,6 +7,8 @@
import { State } from "$lib/internal/open-closed"; import { State } from "$lib/internal/open-closed";
import { getContext, tick } from "svelte"; import { getContext, tick } from "svelte";
import type { Writable } from "svelte/store"; import type { Writable } from "svelte/store";
import { ActionArray, useActions } from "$lib/hooks/use-actions";
export let use: ActionArray = [];
const api = useMenuContext("MenuButton"); const api = useMenuContext("MenuButton");
const id = `headlessui-menu-items-${useId()}`; const id = `headlessui-menu-items-${useId()}`;
let searchDebounce: ReturnType<typeof setTimeout> | null = null; let searchDebounce: ReturnType<typeof setTimeout> | null = null;
@@ -131,6 +133,7 @@
<div <div
{...{ ...$$restProps, ...propsWeControl }} {...{ ...$$restProps, ...propsWeControl }}
bind:this={$itemsStore} bind:this={$itemsStore}
use:useActions={use}
on:keydown={handleKeyDown} on:keydown={handleKeyDown}
on:keyup={handleKeyUp} on:keyup={handleKeyUp}
> >

View File

@@ -0,0 +1,82 @@
// This file taken from hperrin/svelte-material-ui
// Copyright 2020-present Hunter Perrin
export type SvelteActionReturnType<P> = {
update?: (newParams?: P) => void;
destroy?: () => void;
} | void;
export type SvelteHTMLActionType<P> = (
node: HTMLElement,
params?: P
) => SvelteActionReturnType<P>;
export type HTMLActionEntry<P extends any = any> =
| SvelteHTMLActionType<P>
| [SvelteHTMLActionType<P>, P];
export type HTMLActionArray = HTMLActionEntry[];
export type SvelteSVGActionType<P> = (
node: SVGElement,
params?: P
) => SvelteActionReturnType<P>;
export type SVGActionEntry<P extends any = any> =
| SvelteSVGActionType<P>
| [SvelteSVGActionType<P>, P];
export type SVGActionArray = SVGActionEntry[];
export type ActionArray = HTMLActionArray | SVGActionArray;
export function useActions(
node: HTMLElement | SVGElement,
actions: ActionArray
) {
let actionReturns: SvelteActionReturnType<any>[] = [];
if (actions) {
for (let i = 0; i < actions.length; i++) {
const actionEntry = actions[i];
const action = Array.isArray(actionEntry) ? actionEntry[0] : actionEntry;
if (Array.isArray(actionEntry) && actionEntry.length > 1) {
actionReturns.push(
action(node as HTMLElement & SVGElement, actionEntry[1])
);
} else {
actionReturns.push(action(node as HTMLElement & SVGElement));
}
}
}
return {
update(actions: ActionArray) {
if (((actions && actions.length) || 0) != actionReturns.length) {
throw new Error('You must not change the length of an actions array.');
}
if (actions) {
for (let i = 0; i < actions.length; i++) {
const returnEntry = actionReturns[i];
if (returnEntry && returnEntry.update) {
const actionEntry = actions[i];
if (Array.isArray(actionEntry) && actionEntry.length > 1) {
returnEntry.update(actionEntry[1]);
} else {
returnEntry.update();
}
}
}
}
},
destroy() {
for (let i = 0; i < actionReturns.length; i++) {
const returnEntry = actionReturns[i];
if (returnEntry && returnEntry.destroy) {
returnEntry.destroy();
}
}
},
};
}