From a7e8be2c14df12d24999f8330dffc3143409503e Mon Sep 17 00:00:00 2001 From: Ryan Gossiaux Date: Wed, 22 Dec 2021 13:07:16 -0800 Subject: [PATCH] Add type=button handling Fixes #22 --- .../components/disclosure/DisclosureButton.svelte | 12 ++++++++++-- src/lib/components/listbox/ListboxButton.svelte | 2 ++ src/lib/components/menu/MenuButton.svelte | 2 ++ src/lib/components/popover/PopoverButton.svelte | 5 ++++- src/lib/components/switch/Switch.svelte | 3 ++- src/lib/components/tabs/Tab.svelte | 2 ++ src/lib/utils/resolve-button-type.ts | 8 ++++++++ 7 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 src/lib/utils/resolve-button-type.ts diff --git a/src/lib/components/disclosure/DisclosureButton.svelte b/src/lib/components/disclosure/DisclosureButton.svelte index 0844859..ef1c822 100644 --- a/src/lib/components/disclosure/DisclosureButton.svelte +++ b/src/lib/components/disclosure/DisclosureButton.svelte @@ -8,6 +8,8 @@ import type { SupportedAs } from "$lib/internal/elements"; import type { HTMLActionArray } from "$lib/hooks/use-actions"; import Render from "$lib/utils/Render.svelte"; + import { Writable, writable } from "svelte/store"; + import { resolveButtonType } from "$lib/utils/resolve-button-type"; const forwardEvents = forwardEventsBuilder(get_current_component()); export let as: SupportedAs = "button"; @@ -24,6 +26,9 @@ $: isWithinPanel = panelContext === null ? false : panelContext === $api.panelId; + let ourStore: Writable = writable(null); + $: if (!isWithinPanel) ourStore = buttonStore; + function handleClick() { if (disabled) return; @@ -73,10 +78,12 @@ } } + $: type = resolveButtonType({ type: $$props.type, as }, $ourStore); $: propsWeControl = isWithinPanel - ? {} + ? { type } : { id, + type, "aria-expanded": disabled ? undefined : $api.disclosureState === DisclosureStates.Open, @@ -97,6 +104,7 @@ {slotProps} use={[...use, forwardEvents]} name={"DisclosureButton"} + bind:el={$ourStore} on:click={handleClick} on:keydown={handleKeyDown} > @@ -109,7 +117,7 @@ {slotProps} use={[...use, forwardEvents]} name={"DisclosureButton"} - bind:el={$buttonStore} + bind:el={$ourStore} on:click={handleClick} on:keydown={handleKeyDown} on:keyup={handleKeyUp} diff --git a/src/lib/components/listbox/ListboxButton.svelte b/src/lib/components/listbox/ListboxButton.svelte index f1e9deb..c0db0e4 100644 --- a/src/lib/components/listbox/ListboxButton.svelte +++ b/src/lib/components/listbox/ListboxButton.svelte @@ -9,6 +9,7 @@ import type { HTMLActionArray } from "$lib/hooks/use-actions"; import { get_current_component } from "svelte/internal"; import Render from "$lib/utils/Render.svelte"; + import { resolveButtonType } from "$lib/utils/resolve-button-type"; const forwardEvents = forwardEventsBuilder(get_current_component()); export let as: SupportedAs = "button"; @@ -73,6 +74,7 @@ $: propsWeControl = { id, + type: resolveButtonType({ type: $$props.type, as }, $buttonRef), "aria-haspopup": true, "aria-controls": $optionsRef?.id, "aria-expanded": $api.disabled diff --git a/src/lib/components/menu/MenuButton.svelte b/src/lib/components/menu/MenuButton.svelte index 169de91..d72b566 100644 --- a/src/lib/components/menu/MenuButton.svelte +++ b/src/lib/components/menu/MenuButton.svelte @@ -9,6 +9,7 @@ import type { SupportedAs } from "$lib/internal/elements"; import { forwardEventsBuilder } from "$lib/internal/forwardEventsBuilder"; import { get_current_component } from "svelte/internal"; + import { resolveButtonType } from "$lib/utils/resolve-button-type"; const forwardEvents = forwardEventsBuilder(get_current_component()); export let as: SupportedAs = "button"; export let use: HTMLActionArray = []; @@ -76,6 +77,7 @@ $: propsWeControl = { id, + type: resolveButtonType({ type: $$props.type, as }, $buttonStore), "aria-haspopup": true, "aria-controls": $itemsStore?.id, "aria-expanded": disabled ? undefined : $api.menuState === MenuStates.Open, diff --git a/src/lib/components/popover/PopoverButton.svelte b/src/lib/components/popover/PopoverButton.svelte index 11348b1..0af9433 100644 --- a/src/lib/components/popover/PopoverButton.svelte +++ b/src/lib/components/popover/PopoverButton.svelte @@ -14,6 +14,7 @@ import type { SupportedAs } from "$lib/internal/elements"; import type { HTMLActionArray } from "$lib/hooks/use-actions"; import Render from "$lib/utils/Render.svelte"; + import { resolveButtonType } from "$lib/utils/resolve-button-type"; const forwardEvents = forwardEventsBuilder(get_current_component()); export let as: SupportedAs = "button"; @@ -163,10 +164,12 @@ } } + $: type = resolveButtonType({ type: $$props.type, as }, $ourStore); $: propsWeControl = isWithinPanel - ? {} + ? { type } : { id: $api.buttonId, + type, "aria-expanded": disabled ? undefined : $api.popoverState === PopoverStates.Open, diff --git a/src/lib/components/switch/Switch.svelte b/src/lib/components/switch/Switch.svelte index 52dc2cd..71f3bec 100644 --- a/src/lib/components/switch/Switch.svelte +++ b/src/lib/components/switch/Switch.svelte @@ -10,6 +10,7 @@ import type { SupportedAs } from "$lib/internal/elements"; import type { HTMLActionArray } from "$lib/hooks/use-actions"; import Render from "$lib/utils/Render.svelte"; + import { resolveButtonType } from "$lib/utils/resolve-button-type"; const forwardEvents = forwardEventsBuilder(get_current_component(), [ "change", ]); @@ -49,6 +50,7 @@ $: propsWeControl = { id, role: "switch", + type: resolveButtonType({ type: $$props.type, as }, $switchStore), tabIndex: 0, "aria-checked": checked, "aria-labelledby": $labelContext?.labelIds, @@ -80,7 +82,6 @@ {slotProps} use={[...use, forwardEvents]} name={"Switch"} - bind:el={$switchStore} on:click={handleClick} on:keyup={handleKeyUp} on:keypress={handleKeyPress} diff --git a/src/lib/components/tabs/Tab.svelte b/src/lib/components/tabs/Tab.svelte index 96ce62e..7f49012 100644 --- a/src/lib/components/tabs/Tab.svelte +++ b/src/lib/components/tabs/Tab.svelte @@ -10,6 +10,7 @@ import type { SupportedAs } from "$lib/internal/elements"; import type { HTMLActionArray } from "$lib/hooks/use-actions"; import Render from "$lib/utils/Render.svelte"; + import { resolveButtonType } from "$lib/utils/resolve-button-type"; const forwardEvents = forwardEventsBuilder(get_current_component()); export let as: SupportedAs = "button"; @@ -89,6 +90,7 @@ $: propsWeControl = { id, role: "tab", + type: resolveButtonType({ type: $$props.type, as }, tabRef), "aria-controls": $api.panels[myIndex], "aria-selected": selected, tabIndex: selected ? 0 : -1, diff --git a/src/lib/utils/resolve-button-type.ts b/src/lib/utils/resolve-button-type.ts new file mode 100644 index 0000000..51d3c5d --- /dev/null +++ b/src/lib/utils/resolve-button-type.ts @@ -0,0 +1,8 @@ +import type { SupportedAs } from "$lib/internal/elements"; +export function resolveButtonType(props: { type?: string, as?: SupportedAs }, ref: HTMLElement | null | undefined): string | undefined { + if (props.type) return props.type; + let tag = props.as ?? "button"; + if (typeof tag === "string" && tag.toLowerCase() === "button") return "button"; + if (ref instanceof HTMLButtonElement) return "button"; + return undefined; +}