Skip to content

Commit

Permalink
next: Toolbar (#505)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Apr 23, 2024
1 parent 2435111 commit f31c289
Show file tree
Hide file tree
Showing 11 changed files with 572 additions and 312 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getAriaPressed,
getDataDisabled,
getDataOrientation,
getDisabledAttr,
} from "$lib/internal/attrs.js";
import {
type Box,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { getCtx } from "../ctx.js";
import type { ButtonEvents, ButtonProps } from "../index.js";
import { createDispatcher } from "$lib/internal/events.js";
import type { ButtonProps } from "../index.js";
import { setToolbarButtonState } from "../toolbar.svelte.js";
import { useId } from "$lib/internal/use-id.svelte.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/merge-props.js";
type $$Props = ButtonProps;
type $$Events = ButtonEvents;
let {
asChild,
child,
children,
disabled = false,
type = "button",
id = useId(),
el = $bindable(),
...restProps
}: ButtonProps = $props();
export let asChild: $$Props["asChild"] = false;
export let el: $$Props["el"] = undefined;
const state = setToolbarButtonState({
id: readonlyBox(() => id),
disabled: readonlyBox(() => disabled),
});
const {
elements: { button },
getAttrs,
} = getCtx();
const dispatch = createDispatcher();
const attrs = getAttrs("button");
$: builder = $button;
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props, { type }));
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<button
bind:this={el}
use:melt={builder}
type="button"
{...$$restProps}
on:click
on:m-keydown={dispatch}
>
<slot {builder} />
<button bind:this={el} {...mergedProps}>
{@render children?.()}
</button>
{/if}
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { getGroupCtx } from "../ctx.js";
import type { GroupItemEvents, GroupItemProps } from "../index.js";
import { createDispatcher, disabledAttrs } from "$lib/internal/index.js";
import type { GroupItemProps } from "../index.js";
import { setToolbarGroupItemState } from "../toolbar.svelte.js";
import { useId } from "$lib/internal/use-id.svelte.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/merge-props.js";
type $$Props = GroupItemProps;
type $$Events = GroupItemEvents;
let {
asChild,
child,
children,
value,
disabled = false,
type = "button",
id = useId(),
el = $bindable(),
...restProps
}: GroupItemProps = $props();
export let value: $$Props["value"];
export let disabled: $$Props["disabled"] = false;
export let asChild: $$Props["asChild"] = false;
export let el: $$Props["el"] = undefined;
const state = setToolbarGroupItemState({
id: readonlyBox(() => id),
value: readonlyBox(() => value),
disabled: readonlyBox(() => disabled),
});
const {
elements: { item },
getAttrs,
} = getGroupCtx();
const dispatch = createDispatcher();
$: attrs = { ...getAttrs("group-item"), ...disabledAttrs(disabled) };
$: builder = $item({ value, disabled });
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props, { type }));
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<button
bind:this={el}
use:melt={builder}
{...$$restProps}
on:m-click={dispatch}
on:m-keydown={dispatch}
>
<slot {builder} />
<button bind:this={el} {...mergedProps}>
{@render children?.()}
</button>
{/if}
Original file line number Diff line number Diff line change
@@ -1,62 +1,45 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { setGroupCtx } from "../ctx.js";
import type { GroupProps } from "../index.js";
import { arraysAreEqual } from "$lib/internal/arrays.js";
type T = $$Generic<"single" | "multiple">;
type $$Props = GroupProps<T>;
import { setToolbarGroupState } from "../toolbar.svelte.js";
import { useId } from "$lib/internal/use-id.svelte.js";
import { Box, box, readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/merge-props.js";
let {
asChild,
child,
children,
el = $bindable(),
id = useId(),
value = $bindable(),
onValueChange,
type,
disabled = false,
...restProps
}: GroupProps = $props();
export let type: $$Props["type"] = "single" as T;
export let disabled: $$Props["disabled"] = undefined;
export let value: $$Props["value"] = undefined;
export let onValueChange: $$Props["onValueChange"] = undefined;
export let asChild: $$Props["asChild"] = false;
export let el: $$Props["el"] = undefined;
value === undefined && (value = type === "single" ? "" : []);
const {
elements: { group },
states: { value: localValue },
updateOption,
getAttrs,
} = setGroupCtx<T>({
disabled,
const state = setToolbarGroupState({
id: readonlyBox(() => id),
disabled: readonlyBox(() => disabled),
type,
defaultValue: value,
onValueChange: (({ next }: { next: $$Props["value"] }) => {
if (Array.isArray(next)) {
if (!Array.isArray(value) || !arraysAreEqual(value, next)) {
onValueChange?.(next);
value = next;
return next;
}
return next;
}
if (value !== next) {
onValueChange?.(next);
value = next;
value: box(
() => value!,
(v) => {
value = v;
onValueChange?.(v as any);
}
return next;
}) as any,
) as Box<string> | Box<string[]>,
});
const attrs = getAttrs("group");
$: value !== undefined &&
localValue.set(Array.isArray(value) ? ([...value] as $$Props["value"]) : (value as any));
$: updateOption("disabled", disabled);
$: updateOption("type", type);
$: builder = $group;
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props));
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<div bind:this={el} use:melt={builder} {...$$restProps}>
<slot {builder} />
<div bind:this={el} {...mergedProps}>
{@render children?.()}
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -1,39 +1,31 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { getCtx } from "../ctx.js";
import type { LinkEvents, LinkProps } from "../index.js";
import { createDispatcher } from "$lib/internal/events.js";
import { setToolbarLinkState } from "../toolbar.svelte.js";
import type { LinkProps } from "../index.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/merge-props.js";
import { useId } from "$lib/internal/use-id.svelte.js";
type $$Props = LinkProps;
type $$Events = LinkEvents;
let {
asChild,
children,
href,
child,
el = $bindable(),
id = useId(),
...restProps
}: LinkProps = $props();
export let asChild: $$Props["asChild"] = false;
export let el: $$Props["el"] = undefined;
const state = setToolbarLinkState({
id: readonlyBox(() => id),
});
const {
elements: { link },
getAttrs,
} = getCtx();
const dispatch = createDispatcher();
const attrs = getAttrs("link");
$: builder = $link;
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props));
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<svelte:element
this={"a"}
bind:this={el}
use:melt={builder}
{...$$restProps}
on:click
on:m-keydown={dispatch}
>
<slot {builder} />
</svelte:element>
<a {href} {...mergedProps} bind:this={el}>
{@render children?.()}
</a>
{/if}
52 changes: 25 additions & 27 deletions packages/bits-ui/src/lib/bits/toolbar/components/toolbar.svelte
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { setCtx } from "../ctx.js";
import type { Props } from "../index.js";
import type { RootProps } from "../index.js";
import { setToolbarRootState } from "../toolbar.svelte.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/merge-props.js";
import { useId } from "$lib/internal/use-id.svelte.js";
type $$Props = Props;
let {
asChild,
child,
children,
el = $bindable(),
id = useId(),
orientation = "horizontal",
loop = true,
...restProps
}: RootProps = $props()
export let loop: $$Props["loop"] = true;
export let orientation: $$Props["orientation"] = undefined;
export let asChild: $$Props["asChild"] = false;
export let el: $$Props["el"] = undefined;
const state = setToolbarRootState({
id: readonlyBox(() => id),
orientation: readonlyBox(() => orientation),
loop: readonlyBox(() => loop),
})
const {
elements: { root },
updateOption,
getAttrs,
} = setCtx({
loop,
orientation,
});
const mergedProps = $derived(mergeProps(restProps, state.props))
const attrs = getAttrs("root");
$: updateOption("loop", loop);
$: updateOption("orientation", orientation);
$: builder = $root;
$: Object.assign(builder, attrs);
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<div bind:this={el} use:melt={builder} {...$$restProps}>
<slot {builder} />
<div {...mergedProps} bind:this={el}>
{@render children?.()}
</div>
{/if}
{/if}
Loading

0 comments on commit f31c289

Please sign in to comment.