Add action forwarding and add to Menu
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
>
|
>
|
||||||
|
|||||||
82
src/lib/hooks/use-actions.ts
Normal file
82
src/lib/hooks/use-actions.ts
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user