Skip to content

Commit

Permalink
next(breaking): remove controlled* props for Function bindings (#1034)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Jan 3, 2025
1 parent 6916bd5 commit 7592757
Show file tree
Hide file tree
Showing 120 changed files with 217 additions and 1,317 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-icons-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": patch
---

breaking: remove `controlled<State>` props in favor of Svelte's [Function Bindings](https://svelte.dev/docs/svelte/bind#Function-bindings)
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
onValueChange = noop,
loop = true,
orientation = "vertical",
controlledValue = false,
...restProps
}: AccordionRootProps = $props();
Expand All @@ -27,14 +26,9 @@
value: box.with(
() => value!,
(v) => {
if (controlledValue) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
} else {
value = v;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
}
value = v;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
}
) as WritableBox<string> | WritableBox<string[]>,
id: box.with(() => id),
Expand Down
10 changes: 0 additions & 10 deletions packages/bits-ui/src/lib/bits/accordion/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,6 @@ export type BaseAccordionRootPropsWithoutHTML = {
* @defaultValue "vertical"
*/
orientation?: Orientation;

/**
* Whether the value of the accordion is controlled or not.
* If `true`, the accordion will not update the value internally, instead
* it will call `onValueChange` when it would have otherwise, and it is up to you
* to update the `value` prop.
*
* @defaultValue false
*/
controlledValue?: boolean;
};

export type AccordionRootSinglePropsWithoutHTML = BaseAccordionRootPropsWithoutHTML & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,15 @@
import { noop } from "$lib/internal/noop.js";
import { useDialogRoot } from "$lib/bits/dialog/dialog.svelte.js";
let {
open = $bindable(false),
onOpenChange = noop,
controlledOpen = false,
children,
}: AlertDialogRootProps = $props();
let { open = $bindable(false), onOpenChange = noop, children }: AlertDialogRootProps = $props();
useDialogRoot({
variant: box.with(() => "alert-dialog"),
open: box.with(
() => open,
(v) => {
if (controlledOpen) {
onOpenChange(v);
} else {
open = v;
onOpenChange(v);
}
open = v;
onOpenChange(v);
}
),
});
Expand Down
39 changes: 8 additions & 31 deletions packages/bits-ui/src/lib/bits/calendar/components/calendar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
type,
disableDaysOutsideMonth = true,
initialFocus = false,
controlledValue = false,
controlledPlaceholder = false,
...restProps
}: CalendarRootProps = $props();
Expand All @@ -43,27 +41,15 @@
defaultPlaceholder: undefined,
defaultValue: value,
});
if (controlledPlaceholder) {
onPlaceholderChange(defaultPlaceholder);
} else {
placeholder = defaultPlaceholder;
}
placeholder = defaultPlaceholder;
}
if (value === undefined) {
const defaultValue = type === "single" ? "" : [];
if (controlledValue) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(defaultValue as any);
} else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value = defaultValue as any;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value = defaultValue as any;
}
value === undefined && (value = type === "single" ? undefined : []);
const rootState = useCalendarRoot({
id: box.with(() => id),
ref: box.with(
Expand All @@ -88,26 +74,17 @@
placeholder: box.with(
() => placeholder as DateValue,
(v) => {
if (controlledPlaceholder) {
onPlaceholderChange(v as DateValue);
} else {
placeholder = v;
onPlaceholderChange(v as DateValue);
}
placeholder = v;
onPlaceholderChange(v as DateValue);
}
),
preventDeselect: box.with(() => preventDeselect),
value: box.with(
() => value,
(v) => {
if (controlledValue) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
} else {
value = v;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
}
value = v;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
}
),
type: box.with(() => type),
Expand Down
20 changes: 0 additions & 20 deletions packages/bits-ui/src/lib/bits/calendar/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,26 +188,6 @@ type CalendarBaseRootPropsWithoutHTML = {
* @defaultValue false
*/
disableDaysOutsideMonth?: boolean;

/**
* Whether or not the calendar is controlled or not. If `true`, the calendar will not update
* the value internally, instead it will call `onValueChange` when it would have otherwise,
* and it is up to you to update the `value` prop that is passed to the `Calendar.Root`
* component.
*
* @defaultValue false
*/
controlledValue?: boolean;

/**
* Whether or not the calendar placeholder is controlled or not. If `true`, the calendar will
* not update the placeholder internally, instead it will call `onPlaceholderChange` when it
* would have otherwise, and it is up to you to update the `placeholder` prop that is passed to the
* component.
*
* @defaultValue false
*/
controlledPlaceholder?: boolean;
};

export type CalendarSingleRootPropsWithoutHTML = {
Expand Down
18 changes: 4 additions & 14 deletions packages/bits-ui/src/lib/bits/checkbox/components/checkbox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
name = undefined,
value = "on",
id = useId(),
controlledChecked = false,
indeterminate = $bindable(false),
controlledIndeterminate = false,
onIndeterminateChange,
child,
type = "button",
Expand All @@ -28,12 +26,8 @@
checked: box.with(
() => checked,
(v) => {
if (controlledChecked) {
onCheckedChange?.(v);
} else {
checked = v;
onCheckedChange?.(v);
}
checked = v;
onCheckedChange?.(v);
}
),
disabled: box.with(() => disabled ?? false),
Expand All @@ -48,12 +42,8 @@
indeterminate: box.with(
() => indeterminate,
(v) => {
if (controlledIndeterminate) {
onIndeterminateChange?.(v);
} else {
indeterminate = v;
onIndeterminateChange?.(v);
}
indeterminate = v;
onIndeterminateChange?.(v);
}
),
type: box.with(() => type),
Expand Down
30 changes: 0 additions & 30 deletions packages/bits-ui/src/lib/bits/checkbox/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,6 @@ export type CheckboxRootPropsWithoutHTML = WithChild<
*/
onCheckedChange?: OnChangeFn<boolean>;

/**
* Whether or not the checkbox is controlled or not. If `true`, the checkbox will not update
* the checked state internally, instead it will call `onCheckedChange` when it would have
* otherwise, and it is up to you to update the `checked` prop that is passed to the
* component.
*
* @defaultValue false
*/
controlledChecked?: boolean;

/**
* Whether the checkbox is in an indeterminate state or not.
*
Expand All @@ -76,16 +66,6 @@ export type CheckboxRootPropsWithoutHTML = WithChild<
* A callback function called when the indeterminate state changes.
*/
onIndeterminateChange?: OnChangeFn<boolean>;

/**
* Whether the indeterminate state is controlled or not. If `true`, the checkbox will
* not update the indeterminate state internally, instead it will call
* `onIndeterminateChange` when it would have otherwise, and it is up to you to update
* the `indeterminate` prop that is passed to the component.
*
* @defaultValue false
*/
controlledIndeterminate?: boolean;
},
CheckboxRootSnippetProps
>;
Expand Down Expand Up @@ -133,16 +113,6 @@ export type CheckboxGroupPropsWithoutHTML = WithChild<{
* A callback function called when the value changes.
*/
onValueChange?: OnChangeFn<string[]>;

/**
* Whether or not the checkbox group value is controlled or not. If `true`, the
* checkbox group will not update the value internally, instead it will call
* `onValueChange` when it would have otherwise, and it is up to you to update
* the `value` prop that is passed to the component.
*
* @defaultValue false
*/
controlledValue?: boolean;
}>;

export type CheckboxGroupProps = CheckboxGroupPropsWithoutHTML &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
ref = $bindable(null),
open = $bindable(false),
disabled = false,
controlledOpen = false,
onOpenChange = noop,
...restProps
}: CollapsibleRootProps = $props();
Expand All @@ -21,12 +20,8 @@
open: box.with(
() => open,
(v) => {
if (controlledOpen) {
onOpenChange(v);
} else {
open = v;
onOpenChange(v);
}
open = v;
onOpenChange(v);
}
),
disabled: box.with(() => disabled),
Expand Down
9 changes: 0 additions & 9 deletions packages/bits-ui/src/lib/bits/collapsible/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,6 @@ export type CollapsibleRootPropsWithoutHTML = WithChild<{
* A callback function called when the open state changes.
*/
onOpenChange?: OnChangeFn<boolean>;

/**
* Whether or not the collapsible is controlled or not. If `true`, the collapsible will not
* update the open state internally, instead it will call `onOpenChange` when it would have
* otherwise, and it is up to you to update the `value` prop that is passed to the component.
*
* @defaultValue false
*/
controlledOpen?: boolean;
}>;

export type CollapsibleRootProps = CollapsibleRootPropsWithoutHTML &
Expand Down
28 changes: 6 additions & 22 deletions packages/bits-ui/src/lib/bits/combobox/components/combobox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,33 @@
loop = false,
scrollAlignment = "nearest",
required = false,
controlledOpen = false,
controlledValue = false,
items = [],
allowDeselect = true,
children,
}: ComboboxRootProps = $props();
if (value === undefined) {
const defaultValue = type === "single" ? "" : [];
if (controlledValue) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(defaultValue as any);
} else {
value = defaultValue;
}
value = defaultValue;
}
const rootState = useSelectRoot({
type,
value: box.with(
() => value!,
(v) => {
if (controlledValue) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
} else {
value = v;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onValueChange(v as any);
}
value = v;
// @ts-expect-error - we know
onValueChange(v);
}
) as WritableBox<string> | WritableBox<string[]>,
disabled: box.with(() => disabled),
required: box.with(() => required),
open: box.with(
() => open,
(v) => {
if (controlledOpen) {
onOpenChange(v);
} else {
open = v;
onOpenChange(v);
}
open = v;
onOpenChange(v);
}
),
loop: box.with(() => loop),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
label = "",
vimBindings = true,
disablePointerSelection = false,
controlledValue = false,
children,
child,
...restProps
Expand All @@ -36,12 +35,8 @@
value: box.with(
() => value,
(v) => {
if (controlledValue) {
onValueChange(v);
} else {
value = v;
onValueChange(v);
}
value = v;
onValueChange(v);
}
),
vimBindings: box.with(() => vimBindings),
Expand Down
Loading

0 comments on commit 7592757

Please sign in to comment.