From f31c289ba5828de7fa1402969a1fde8fca5388b8 Mon Sep 17 00:00:00 2001 From: Hunter Johnston <64506580+huntabyte@users.noreply.github.com> Date: Tue, 23 Apr 2024 13:31:04 -0400 Subject: [PATCH] next: Toolbar (#505) --- .../bits/toggle-group/toggle-group.svelte.ts | 2 + .../toolbar/components/toolbar-button.svelte | 51 +-- .../components/toolbar-group-item.svelte | 54 ++- .../toolbar/components/toolbar-group.svelte | 79 ++-- .../toolbar/components/toolbar-link.svelte | 52 +-- .../bits/toolbar/components/toolbar.svelte | 52 ++- packages/bits-ui/src/lib/bits/toolbar/ctx.ts | 56 --- .../bits-ui/src/lib/bits/toolbar/index.ts | 5 +- .../src/lib/bits/toolbar/toolbar.svelte.ts | 404 ++++++++++++++++++ .../bits-ui/src/lib/bits/toolbar/types.ts | 127 ++---- packages/bits-ui/src/lib/internal/types.ts | 2 + 11 files changed, 572 insertions(+), 312 deletions(-) delete mode 100644 packages/bits-ui/src/lib/bits/toolbar/ctx.ts create mode 100644 packages/bits-ui/src/lib/bits/toolbar/toolbar.svelte.ts diff --git a/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts b/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts index 673f48e8d..f3d9e9224 100644 --- a/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts +++ b/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts @@ -4,6 +4,7 @@ import { getAriaPressed, getDataDisabled, getDataOrientation, + getDisabledAttr, } from "$lib/internal/attrs.js"; import { type Box, @@ -207,6 +208,7 @@ class ToggleGroupItemState { "data-value": this.#value.value, "aria-pressed": this.#ariaPressed, "aria-checked": this.#ariaChecked, + disabled: getDisabledAttr(this.#isDisabled), [ITEM_ATTR]: "", // onclick: this.#onclick, diff --git a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-button.svelte b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-button.svelte index 74a40b07d..916c201ae 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-button.svelte +++ b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-button.svelte @@ -1,38 +1,33 @@ {#if asChild} - + {@render child?.({ props: mergedProps })} {:else} - {/if} diff --git a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group-item.svelte b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group-item.svelte index b192ba72e..a4c999e5a 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group-item.svelte +++ b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group-item.svelte @@ -1,39 +1,35 @@ {#if asChild} - + {@render child?.({ props: mergedProps })} {:else} - {/if} diff --git a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group.svelte b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group.svelte index 56755dbd1..6b41ab50a 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group.svelte +++ b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-group.svelte @@ -1,62 +1,45 @@ {#if asChild} - + {@render child?.({ props: mergedProps })} {:else} -
- +
+ {@render children?.()}
{/if} diff --git a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-link.svelte b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-link.svelte index 183bcccad..ccb98d38d 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-link.svelte +++ b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar-link.svelte @@ -1,39 +1,31 @@ {#if asChild} - + {@render child?.({ props: mergedProps })} {:else} - - - - + + {@render children?.()} + {/if} diff --git a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar.svelte b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar.svelte index de98dd1a5..112d8c010 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/components/toolbar.svelte +++ b/packages/bits-ui/src/lib/bits/toolbar/components/toolbar.svelte @@ -1,37 +1,35 @@ {#if asChild} - + {@render child?.({ props: mergedProps })} {:else} -
- +
+ {@render children?.()}
-{/if} +{/if} \ No newline at end of file diff --git a/packages/bits-ui/src/lib/bits/toolbar/ctx.ts b/packages/bits-ui/src/lib/bits/toolbar/ctx.ts deleted file mode 100644 index a0d596fb3..000000000 --- a/packages/bits-ui/src/lib/bits/toolbar/ctx.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - type CreateToolbarGroupProps as ToolbarGroupProps, - type CreateToolbarProps as ToolbarProps, - createToolbar, -} from "@melt-ui/svelte"; -import { getContext, setContext } from "svelte"; -import { createBitAttrs, getOptionUpdater, removeUndefined } from "$lib/internal/index.js"; - -function getToolbarData() { - const NAME = "toolbar" as const; - const GROUP_NAME = "toolbar-group"; - const PARTS = ["root", "button", "link", "group", "group-item"] as const; - return { - NAME, - GROUP_NAME, - PARTS, - }; -} - -type GetReturn = Omit, "updateOption">; -type GetGroupReturn = Omit, "updateOption">; - -export function setCtx(props: ToolbarProps) { - const { NAME, PARTS } = getToolbarData(); - const getAttrs = createBitAttrs(NAME, PARTS); - const toolbar = { ...createToolbar(removeUndefined(props)), getAttrs }; - setContext(NAME, toolbar); - return { - ...toolbar, - updateOption: getOptionUpdater(toolbar.options), - }; -} - -export function setGroupCtx(props: ToolbarGroupProps) { - const { - builders: { createToolbarGroup }, - getAttrs, - } = getCtx(); - const group = { ...createToolbarGroup(removeUndefined(props)), getAttrs }; - const { GROUP_NAME } = getToolbarData(); - setContext(GROUP_NAME, group); - return { - ...group, - updateOption: getOptionUpdater(group.options), - }; -} - -export function getCtx() { - const { NAME } = getToolbarData(); - return getContext(NAME); -} - -export function getGroupCtx() { - const { GROUP_NAME } = getToolbarData(); - return getContext(GROUP_NAME); -} diff --git a/packages/bits-ui/src/lib/bits/toolbar/index.ts b/packages/bits-ui/src/lib/bits/toolbar/index.ts index ac2a585ae..f4fd2b71a 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/index.ts +++ b/packages/bits-ui/src/lib/bits/toolbar/index.ts @@ -5,12 +5,9 @@ export { default as Group } from "./components/toolbar-group.svelte"; export { default as GroupItem } from "./components/toolbar-group-item.svelte"; export type { - ToolbarProps as Props, + ToolbarRootProps as RootProps, ToolbarButtonProps as ButtonProps, ToolbarLinkProps as LinkProps, ToolbarGroupProps as GroupProps, ToolbarGroupItemProps as GroupItemProps, - ToolbarButtonEvents as ButtonEvents, - ToolbarLinkEvents as LinkEvents, - ToolbarGroupItemEvents as GroupItemEvents, } from "./types.js"; diff --git a/packages/bits-ui/src/lib/bits/toolbar/toolbar.svelte.ts b/packages/bits-ui/src/lib/bits/toolbar/toolbar.svelte.ts new file mode 100644 index 000000000..bde2041c1 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/toolbar/toolbar.svelte.ts @@ -0,0 +1,404 @@ +import { getContext, setContext } from "svelte"; +import { + getAriaChecked, + getAriaPressed, + getDataDisabled, + getDataOrientation, + getDisabledAttr, +} from "$lib/internal/attrs.js"; +import { + type Box, + type BoxedValues, + type ReadonlyBoxedValues, + boxedState, +} from "$lib/internal/box.svelte.js"; +import { verifyContextDeps } from "$lib/internal/context.js"; +import { kbd } from "$lib/internal/kbd.js"; +import { useNodeById } from "$lib/internal/use-node-by-id.svelte.js"; +import { + type UseRovingFocusReturn, + useRovingFocus, +} from "$lib/internal/use-roving-focus.svelte.js"; +import type { Orientation } from "$lib/shared/index.js"; + +const ROOT_ATTR = "data-toolbar-root"; +// all links, buttons, and items must have the ITEM_ATTR for roving focus +const ITEM_ATTR = "data-toolbar-item"; +const GROUP_ATTR = "data-toolbar-group"; +const GROUP_ITEM_ATTR = "data-toolbar-group-item"; +const LINK_ATTR = "data-toolbar-link"; +const BUTTON_ATTR = "data-toolbar-button"; + +type ToolbarRootStateProps = ReadonlyBoxedValues<{ + orientation: Orientation; + loop: boolean; + id: string; +}>; + +class ToolbarRootState { + #id = undefined as unknown as ToolbarRootStateProps["id"]; + orientation = undefined as unknown as ToolbarRootStateProps["orientation"]; + #loop = undefined as unknown as ToolbarRootStateProps["loop"]; + #node = boxedState(null); + rovingFocusGroup = undefined as unknown as UseRovingFocusReturn; + + constructor(props: ToolbarRootStateProps) { + this.#id = props.id; + this.orientation = props.orientation; + this.#loop = props.loop; + this.#node = useNodeById(this.#id); + this.rovingFocusGroup = useRovingFocus({ + orientation: this.orientation, + loop: this.#loop, + rootNode: this.#node, + candidateSelector: ITEM_ATTR, + }); + } + + createGroup(props: InitToolbarGroupProps) { + const { type, ...rest } = props; + const groupState = + type === "single" + ? new ToolbarGroupSingleState(rest as ToolbarGroupSingleStateProps, this) + : new ToolbarGroupMultipleState(rest as ToolbarGroupMultipleStateProps, this); + return groupState; + } + + createLink(props: ToolbarLinkStateProps) { + return new ToolbarLinkState(props, this); + } + + createButton(props: ToolbarButtonStateProps) { + return new ToolbarButtonState(props, this); + } + + props = $derived({ + id: this.#id.value, + role: "toolbar", + "data-orientation": this.orientation.value, + [ROOT_ATTR]: "", + } as const); +} + +type ToolbarGroupBaseStateProps = ReadonlyBoxedValues<{ + id: string; + disabled: boolean; +}>; + +class ToolbarGroupBaseState { + id = undefined as unknown as ToolbarGroupBaseStateProps["id"]; + node = boxedState(null); + disabled = undefined as unknown as ToolbarGroupBaseStateProps["disabled"]; + root = undefined as unknown as ToolbarRootState; + + constructor(props: ToolbarGroupBaseStateProps, root: ToolbarRootState) { + this.id = props.id; + this.node = useNodeById(this.id); + this.disabled = props.disabled; + this.root = root; + } + + props = $derived({ + id: this.id.value, + [GROUP_ATTR]: "", + role: "group", + "data-orientation": getDataOrientation(this.root.orientation.value), + "data-disabled": getDataDisabled(this.disabled.value), + } as const); +} + +// +// SINGLE +// + +type ToolbarGroupSingleStateProps = ToolbarGroupBaseStateProps & + BoxedValues<{ + value: string; + }>; + +class ToolbarGroupSingleState extends ToolbarGroupBaseState { + #value = undefined as unknown as ToolbarGroupSingleStateProps["value"]; + isMulti = false; + anyPressed = $derived(this.#value.value !== ""); + + constructor(props: ToolbarGroupSingleStateProps, root: ToolbarRootState) { + super(props, root); + this.#value = props.value; + } + + createItem(props: ToolbarGroupItemStateProps) { + return new ToolbarGroupItemState(props, this, this.root); + } + + includesItem(item: string) { + return this.#value.value === item; + } + + toggleItem(item: string) { + if (this.includesItem(item)) { + this.#value.value = ""; + } else { + this.#value.value = item; + } + } +} + +// +// MULTIPLE +// + +type ToolbarGroupMultipleStateProps = ToolbarGroupBaseStateProps & + BoxedValues<{ + value: string[]; + }>; + +class ToolbarGroupMultipleState extends ToolbarGroupBaseState { + #value = undefined as unknown as ToolbarGroupMultipleStateProps["value"]; + isMulti = true; + anyPressed = $derived(this.#value.value.length > 0); + + constructor(props: ToolbarGroupMultipleStateProps, root: ToolbarRootState) { + super(props, root); + this.#value = props.value; + } + + createItem(props: ToolbarGroupItemStateProps) { + return new ToolbarGroupItemState(props, this, this.root); + } + + includesItem(item: string) { + return this.#value.value.includes(item); + } + + toggleItem(item: string) { + if (this.includesItem(item)) { + this.#value.value = this.#value.value.filter((v) => v !== item); + } else { + this.#value.value = [...this.#value.value, item]; + } + } +} + +type ToolbarGroupState = ToolbarGroupSingleState | ToolbarGroupMultipleState; + +// +// ITEM +// + +type ToolbarGroupItemStateProps = ReadonlyBoxedValues<{ + id: string; + value: string; + disabled: boolean; +}>; + +class ToolbarGroupItemState { + #id = undefined as unknown as ToolbarGroupItemStateProps["id"]; + #group = undefined as unknown as ToolbarGroupState; + #root = undefined as unknown as ToolbarRootState; + #value = undefined as unknown as ToolbarGroupItemStateProps["value"]; + #node = boxedState(null); + #disabled = undefined as unknown as ToolbarGroupItemStateProps["disabled"]; + #isDisabled = $derived(this.#disabled.value || this.#group.disabled.value); + + constructor( + props: ToolbarGroupItemStateProps, + group: ToolbarGroupState, + root: ToolbarRootState + ) { + this.#value = props.value; + this.#disabled = props.disabled; + this.#group = group; + this.#root = root; + this.#id = props.id; + this.#node = useNodeById(this.#id); + } + + toggleItem() { + if (this.#isDisabled) return; + this.#group.toggleItem(this.#value.value); + } + + #onclick = () => { + this.toggleItem(); + }; + + #onkeydown = (e: KeyboardEvent) => { + if (this.#isDisabled) return; + if (e.key === kbd.ENTER || e.key === kbd.SPACE) { + e.preventDefault(); + this.toggleItem(); + return; + } + + this.#root.rovingFocusGroup.handleKeydown(this.#node.value, e); + }; + + #isPressed = $derived(this.#group.includesItem(this.#value.value)); + + #ariaChecked = $derived.by(() => { + return this.#group.isMulti ? undefined : getAriaChecked(this.#isPressed); + }); + + #ariaPressed = $derived.by(() => { + return this.#group.isMulti ? undefined : getAriaPressed(this.#isPressed); + }); + + #tabIndex = $derived(this.#root.rovingFocusGroup.getTabIndex(this.#node.value).value); + + props = $derived({ + id: this.#id.value, + role: this.#group.isMulti ? undefined : "radio", + tabindex: this.#tabIndex, + "data-orientation": getDataOrientation(this.#root.orientation.value), + "data-disabled": getDataDisabled(this.#isDisabled), + "data-state": getToggleItemDataState(this.#isPressed), + "data-value": this.#value.value, + "aria-pressed": this.#ariaPressed, + "aria-checked": this.#ariaChecked, + [ITEM_ATTR]: "", + [GROUP_ITEM_ATTR]: "", + disabled: getDisabledAttr(this.#isDisabled), + // + onclick: this.#onclick, + onkeydown: this.#onkeydown, + }); +} + +type ToolbarLinkStateProps = ReadonlyBoxedValues<{ + id: string; +}>; + +class ToolbarLinkState { + #id = undefined as unknown as ToolbarLinkStateProps["id"]; + #node = boxedState(null); + #root = undefined as unknown as ToolbarRootState; + + constructor(props: ToolbarLinkStateProps, root: ToolbarRootState) { + this.#root = root; + this.#id = props.id; + this.#node = useNodeById(this.#id); + } + + #onkeydown = (e: KeyboardEvent) => { + this.#root.rovingFocusGroup.handleKeydown(this.#node.value, e); + }; + + #role = $derived.by(() => { + if (!this.#node.value) return undefined; + const tagName = this.#node.value.tagName.toLowerCase(); + if (tagName !== "a") return "link" as const; + return undefined; + }); + + #tabIndex = $derived(this.#root.rovingFocusGroup.getTabIndex(this.#node.value).value); + + props = $derived({ + id: this.#id.value, + [LINK_ATTR]: "", + [ITEM_ATTR]: "", + role: this.#role, + tabindex: this.#tabIndex, + "data-orientation": getDataOrientation(this.#root.orientation.value), + // + onkeydown: this.#onkeydown, + }); +} + +type ToolbarButtonStateProps = ReadonlyBoxedValues<{ + id: string; + disabled: boolean; +}>; + +class ToolbarButtonState { + #id = undefined as unknown as ToolbarButtonStateProps["id"]; + #root = undefined as unknown as ToolbarRootState; + #node = boxedState(null); + #disabled = undefined as unknown as ToolbarButtonStateProps["disabled"]; + + constructor(props: ToolbarButtonStateProps, root: ToolbarRootState) { + this.#id = props.id; + this.#root = root; + this.#node = useNodeById(this.#id); + this.#disabled = props.disabled; + } + + #onkeydown = (e: KeyboardEvent) => { + this.#root.rovingFocusGroup.handleKeydown(this.#node.value, e); + }; + + #tabIndex = $derived(this.#root.rovingFocusGroup.getTabIndex(this.#node.value).value); + + #role = $derived.by(() => { + if (!this.#node.value) return undefined; + const tagName = this.#node.value.tagName.toLowerCase(); + if (tagName !== "button") return "button" as const; + return undefined; + }); + + props = $derived({ + id: this.#id.value, + [ITEM_ATTR]: "", + [BUTTON_ATTR]: "", + role: this.#role, + tabindex: this.#tabIndex, + "data-disabled": getDataDisabled(this.#disabled.value), + "data-orientation": getDataOrientation(this.#root.orientation.value), + disabled: getDisabledAttr(this.#disabled.value), + // + onkeydown: this.#onkeydown, + }); +} + +// +// HELPERS +// + +function getToggleItemDataState(condition: boolean) { + return condition ? "on" : "off"; +} + +// +// CONTEXT METHODS +// + +const TOOLBAR_ROOT_KEY = Symbol("Toolbar.Root"); +const TOOLBAR_GROUP_KEY = Symbol("Toolbar.Group"); + +export function setToolbarRootState(props: ToolbarRootStateProps) { + return setContext(TOOLBAR_ROOT_KEY, new ToolbarRootState(props)); +} + +export function getToolbarRootState(): ToolbarRootState { + verifyContextDeps(TOOLBAR_ROOT_KEY); + return getContext(TOOLBAR_ROOT_KEY); +} + +type InitToolbarGroupProps = { + type: "single" | "multiple"; + value: Box | Box; +} & ReadonlyBoxedValues<{ + id: string; + disabled: boolean; +}>; + +export function setToolbarGroupState(props: InitToolbarGroupProps) { + const groupState = getToolbarRootState().createGroup(props); + return setContext(TOOLBAR_GROUP_KEY, groupState); +} + +export function getToolbarGroupState(): ToolbarGroupState { + verifyContextDeps(TOOLBAR_GROUP_KEY); + return getContext(TOOLBAR_GROUP_KEY); +} + +export function setToolbarGroupItemState(props: ToolbarGroupItemStateProps) { + return getToolbarGroupState().createItem(props); +} + +export function setToolbarButtonState(props: ToolbarButtonStateProps) { + return getToolbarRootState().createButton(props); +} + +export function setToolbarLinkState(props: ToolbarLinkStateProps) { + return getToolbarRootState().createLink(props); +} diff --git a/packages/bits-ui/src/lib/bits/toolbar/types.ts b/packages/bits-ui/src/lib/bits/toolbar/types.ts index 7ba710a09..8f360d169 100644 --- a/packages/bits-ui/src/lib/bits/toolbar/types.ts +++ b/packages/bits-ui/src/lib/bits/toolbar/types.ts @@ -1,100 +1,47 @@ -import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements"; import type { - CreateToolbarGroupProps as MeltToolbarGroupProps, - CreateToolbarProps as MeltToolbarProps, -} from "@melt-ui/svelte"; + ToggleGroupItemProps, + ToggleGroupItemPropsWithoutHTML, + ToggleGroupRootPropsWithoutHTML, +} from "../toggle-group/types.js"; +import type { Orientation } from "$lib/shared/index.js"; import type { - DOMElement, - Expand, - HTMLDivAttributes, - OmitValue, - OnChangeFn, -} from "$lib/internal/index.js"; -import type { CustomEventHandler } from "$lib/index.js"; - -export type ToolbarPropsWithoutHTML = Expand; - -export type ToolbarButtonPropsWithoutHTML = DOMElement; - -export type ToolbarLinkPropsWithoutHTML = DOMElement; - -export type ToolbarGroupPropsWithoutHTML = Expand< - OmitValue> & { - /** - * The value of the toolbar toggle group, which is a string or an array of strings, - * depending on the type of the toolbar toggle group. - * - * You can bind to this to programmatically control the value. - */ - value?: MeltToolbarGroupProps["defaultValue"]; - - /** - * A callback function called when the value changes. - */ - onValueChange?: OnChangeFn["defaultValue"]>; - - /** - * The type of the toolbar toggle group. - * - * If the type is `"single"`, the toolbar toggle group allows only one item to be selected - * at a time. If the type is `"multiple"`, the toolbar toggle group allows multiple items - * to be selected at a time. - */ - type?: T; - } & DOMElement + PrimitiveAnchorAttributes, + PrimitiveButtonAttributes, + PrimitiveDivAttributes, + WithAsChild, +} from "$lib/internal/types.js"; +import type { EventCallback } from "$lib/internal/events.js"; + +export type ToolbarRootPropsWithoutHTML = WithAsChild<{ + orientation?: Orientation; + loop?: boolean; +}>; + +export type ToolbarRootProps = ToolbarRootPropsWithoutHTML & PrimitiveDivAttributes; + +export type ToolbarGroupPropsWithoutHTML = Omit< + ToggleGroupRootPropsWithoutHTML, + "orientation" | "loop" | "rovingFocus" >; -export type ToolbarGroupItemPropsWithoutHTML = Expand< - { - /** - * The value of the toolbar toggle group item. When the toolbar toggle group item is selected, - * the toolbar toggle group's value will be set to this value if in `"single"` mode, - * or this value will be pushed to the toolbar toggle group's array value if in `"multiple"` mode. - * - * @required - */ - value: string; - - /** - * Whether the toolbar toggle group item is disabled. - * - * @defaultValue false - */ - disabled?: boolean; - } & DOMElement ->; - -// - -export type ToolbarProps = ToolbarPropsWithoutHTML & HTMLDivAttributes; - -export type ToolbarButtonProps = ToolbarButtonPropsWithoutHTML & HTMLButtonAttributes; - -export type ToolbarLinkProps = ToolbarLinkPropsWithoutHTML & HTMLAnchorAttributes; +export type ToolbarGroupProps = ToolbarGroupPropsWithoutHTML & + Omit; -export type ToolbarGroupProps = ToolbarGroupPropsWithoutHTML & - HTMLDivAttributes; +export type ToolbarGroupItemPropsWithoutHTML = ToggleGroupItemPropsWithoutHTML; -export type ToolbarGroupItemProps = ToolbarGroupItemPropsWithoutHTML & HTMLButtonAttributes; +export type ToolbarGroupItemProps = ToggleGroupItemProps; -/** - * Events - */ -type HTMLEventHandler = T & { - currentTarget: EventTarget & E; -}; +export type ToolbarButtonPropsWithoutHTML = WithAsChild<{ + disabled?: boolean; + onkeydown?: EventCallback; +}>; -export type ToolbarButtonEvents = { - click: HTMLEventHandler; - keydown: CustomEventHandler; -}; +export type ToolbarButtonProps = ToolbarButtonPropsWithoutHTML & + Omit; -export type ToolbarLinkEvents = { - click: HTMLEventHandler; - keydown: CustomEventHandler; -}; +export type ToolbarLinkPropsWithoutHTML = WithAsChild<{ + onkeydown?: EventCallback; +}>; -export type ToolbarGroupItemEvents = { - click: CustomEventHandler; - keydown: CustomEventHandler; -}; +export type ToolbarLinkProps = ToolbarLinkPropsWithoutHTML & + Omit; diff --git a/packages/bits-ui/src/lib/internal/types.ts b/packages/bits-ui/src/lib/internal/types.ts index 171aab929..33e45ab04 100644 --- a/packages/bits-ui/src/lib/internal/types.ts +++ b/packages/bits-ui/src/lib/internal/types.ts @@ -1,6 +1,7 @@ import type { Snippet } from "svelte"; import type { Action } from "svelte/action"; import type { + HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes, HTMLImgAttributes, @@ -130,6 +131,7 @@ export type PrimitiveImgAttributes = Primitive; export type PrimitiveHeadingAttributes = Primitive; export type PrimitiveLabelAttributes = Primitive; export type PrimitiveSVGAttributes = Primitive>; +export type PrimitiveAnchorAttributes = Primitive; export type AsChildProps = { child: Snippet<[SnippetProps & { props: Record }]>;