Skip to content

Commit c1a9f81

Browse files
authored
next: remove controlled* props in favor of Function Bindings (#1595)
1 parent aed255b commit c1a9f81

23 files changed

+195
-1635
lines changed

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
"devDependencies": {
3939
"@changesets/cli": "^2.27.1",
4040
"@eslint/js": "^9.12.0",
41-
"@huntabyte/eslint-config": "^0.3.2",
4241
"@typescript-eslint/eslint-plugin": "^8.10.0",
4342
"@typescript-eslint/scope-manager": "^8.10.0",
4443
"@typescript-eslint/utils": "^8.10.0",
@@ -47,7 +46,7 @@
4746
"eslint-plugin-svelte": "^2.44.1",
4847
"globals": "^15.11.0",
4948
"prettier": "^3.3.3",
50-
"prettier-plugin-svelte": "^3.2.7",
49+
"prettier-plugin-svelte": "^3.3.2",
5150
"prettier-plugin-tailwindcss": "^0.6.8",
5251
"pretty-quick": "^4.0.0",
5352
"svelte": "^5.16.0",

pnpm-lock.yaml

+145-1,555
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sites/docs/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"acorn": "^8.13.0",
4444
"acorn-typescript": "^1.4.13",
4545
"autoprefixer": "^10.4.19",
46-
"bits-ui": "1.0.0-next.76",
46+
"bits-ui": "^1.0.0-next.77",
4747
"clsx": "^2.1.1",
4848
"concurrently": "^9.0.1",
4949
"d3-scale": "^4.0.2",
@@ -69,8 +69,8 @@
6969
"remark-gfm": "^4.0.0",
7070
"rimraf": "^4.4.1",
7171
"shiki": "^1.2.1",
72-
"svelte": "^5.16.0",
73-
"svelte-check": "^4.0.5",
72+
"svelte": "^5.16.1",
73+
"svelte-check": "^4.1.1",
7474
"svelte-local-storage-store": "^0.6.4",
7575
"svelte-persisted-store": "^0.11.0",
7676
"svelte-sonner": "^0.3.25",
@@ -79,7 +79,7 @@
7979
"tailwind-variants": "^0.2.1",
8080
"tailwindcss": "^3.4.4",
8181
"tailwindcss-animate": "^1.0.7",
82-
"ts-blank-space": "^0.4.1",
82+
"ts-blank-space": "^0.4.4",
8383
"tslib": "^2.6.3",
8484
"tsx": "^4.16.2",
8585
"typescript": "~5.5.3",

sites/docs/scripts/transformers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ function stripMarkupTypes(): PreprocessorGroup {
9898
ms.update(start, end, stripped);
9999

100100
this.skip();
101-
} else if ("expression" in node) {
101+
} else if ("expression" in node && typeof node.expression === "object") {
102102
// @ts-expect-error trust me
103103
const { start, end } = node.expression;
104104

sites/docs/src/content/components/data-table.md

+4-7
Original file line numberDiff line numberDiff line change
@@ -793,9 +793,8 @@ Adding column visibility is fairly simple using `@tanstack/table-core` visibilit
793793
.filter((col) => col.getCanHide()) as column (column.id)}
794794
<DropdownMenu.CheckboxItem
795795
class="capitalize"
796-
controlledChecked
797-
checked={column.getIsVisible()}
798-
onCheckedChange={(value) => column.toggleVisibility(!!value)}
796+
bind:checked={() => column.getIsVisible(),
797+
(v) => column.toggleVisibility(!!v)}
799798
>
800799
{column.id}
801800
</DropdownMenu.CheckboxItem>
@@ -830,12 +829,12 @@ We'll start by defining the checkbox component in our `data-table-checkbox.svelt
830829
831830
let {
832831
checked = false,
833-
controlledChecked = true,
832+
onCheckedChange = (v) => (checked = v),
834833
...restProps
835834
}: ComponentProps<typeof Checkbox> = $props();
836835
</script>
837836
838-
<Checkbox {checked} {controlledChecked} {...restProps} />
837+
<Checkbox bind:checked={() => checked, onCheckedChange} {...restProps} />
839838
```
840839

841840
### Update columns definition
@@ -861,14 +860,12 @@ export const columns: ColumnDef<Payment>[] = [
861860
table.getIsSomePageRowsSelected() &&
862861
!table.getIsAllPageRowsSelected(),
863862
onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value),
864-
controlledChecked: true,
865863
"aria-label": "Select all",
866864
}),
867865
cell: ({ row }) =>
868866
renderComponent(Checkbox, {
869867
checked: row.getIsSelected(),
870868
onCheckedChange: (value) => row.toggleSelected(!!value),
871-
controlledChecked: true,
872869
"aria-label": "Select row",
873870
}),
874871
enableSorting: false,

sites/docs/src/content/components/sidebar.md

+7-12
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,10 @@ The `Sidebar.Provider` component is used to provide the sidebar context to the `
300300

301301
### Props
302302

303-
| Name | Type | Description |
304-
| ---------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
305-
| `open` | `boolean` | Open state of the sidebar (bindable). |
306-
| `controlledOpen` | `boolean` | Whether the sidebar state will be controlled by you. |
307-
| `onOpenChange` | `(open: boolean) => void` | A callback fired _after_ the open state of the sidebar changes if uncontrolled, and _before_ the sidebar opens or closes if controlled. |
303+
| Name | Type | Description |
304+
| -------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
305+
| `open` | `boolean` | Open state of the sidebar (bindable). |
306+
| `onOpenChange` | `(open: boolean) => void` | A callback fired _after_ the open state of the sidebar changes if uncontrolled, and _before_ the sidebar opens or closes if controlled. |
308307

309308
### Width
310309

@@ -915,7 +914,7 @@ The `Sidebar.Rail` component is used to render a rail within a `Sidebar.Root`. T
915914

916915
## Controlled Sidebar
917916

918-
Use the `open`, `onOpenChange` and `controlledOpen` props or `bind:open` to control the sidebar state.
917+
Use Svelte's [Function Binding](https://svelte.dev/docs/svelte/bind#Function-bindings) to control the sidebar state.
919918

920919
<DocsFigure caption="A controlled sidebar.">
921920
<ComponentPreviewManual name="demo-sidebar-controlled" title="Sidebar" type="block" class="w-full" />
@@ -925,14 +924,10 @@ Use the `open`, `onOpenChange` and `controlledOpen` props or `bind:open` to cont
925924
<script lang="ts">
926925
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
927926
928-
let open = $state(true);
927+
let myOpen = $state(true);
929928
</script>
930929
931-
<Sidebar.Provider
932-
{open}
933-
controlledOpen
934-
onOpenChange={(value) => (open = value)}
935-
>
930+
<Sidebar.Provider bind:open={() => myOpen, (newOpen) => (myOpen = newOpen)}>
936931
<Sidebar.Root />
937932
</Sidebar.Provider>
938933

sites/docs/src/lib/components/docs/style-switcher.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@
2121

2222
<Select.Root
2323
type="single"
24-
controlledValue
25-
{value}
26-
onValueChange={(v) => {
24+
bind:value={() => value,
25+
(v) => {
2726
if (!isStyle(v)) return;
2827
value = v;
2928
}}

sites/docs/src/lib/registry/default/block/demo-sidebar-controlled.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
let open = $state(true);
4141
</script>
4242

43-
<Sidebar.Provider {open} controlledOpen onOpenChange={(value) => (open = value)}>
43+
<Sidebar.Provider bind:open={() => open, (v) => (open = v)}>
4444
<Sidebar.Root>
4545
<Sidebar.Content>
4646
<Sidebar.Group>

sites/docs/src/lib/registry/default/example/cards/data-table.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,8 @@
239239
{#each table.getAllColumns().filter((col) => col.getCanHide()) as column}
240240
<DropdownMenu.CheckboxItem
241241
class="capitalize"
242-
controlledChecked
243-
checked={column.getIsVisible()}
244-
onCheckedChange={(value) => column.toggleVisibility(!!value)}
242+
bind:checked={() => column.getIsVisible(),
243+
(v) => column.toggleVisibility(!!v)}
245244
>
246245
{column.id}
247246
</DropdownMenu.CheckboxItem>

sites/docs/src/lib/registry/default/example/data-table-demo.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,8 @@
245245
{#each table.getAllColumns().filter((col) => col.getCanHide()) as column}
246246
<DropdownMenu.CheckboxItem
247247
class="capitalize"
248-
controlledChecked
249-
checked={column.getIsVisible()}
250-
onCheckedChange={(value) => column.toggleVisibility(!!value)}
248+
bind:checked={() => column.getIsVisible(),
249+
(v) => column.toggleVisibility(!!v)}
251250
>
252251
{column.id}
253252
</DropdownMenu.CheckboxItem>

sites/docs/src/lib/registry/default/example/data-table/data-table-checkbox.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
55
let {
66
checked = false,
7-
controlledChecked = true,
7+
onCheckedChange = (v) => (checked = v),
88
...restProps
99
}: ComponentProps<typeof Checkbox> = $props();
1010
</script>
1111

12-
<Checkbox {checked} {controlledChecked} {...restProps} />
12+
<Checkbox bind:checked={() => checked, onCheckedChange} {...restProps} />

sites/docs/src/lib/registry/default/example/date-picker-with-presets.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@
4343
<Popover.Content class="flex w-auto flex-col space-y-2 p-2">
4444
<Select.Root
4545
type="single"
46-
value={valueString}
47-
controlledValue
48-
onValueChange={(v) => {
46+
bind:value={() => valueString,
47+
(v) => {
4948
if (!v) return;
5049
value = today(getLocalTimeZone()).add({ days: Number.parseInt(v) });
5150
}}

sites/docs/src/lib/registry/default/ui/sidebar/sidebar-provider.svelte

+2-8
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,20 @@
1515
ref = $bindable(null),
1616
open = $bindable(true),
1717
onOpenChange = () => {},
18-
controlledOpen = false,
1918
class: className,
2019
style,
2120
children,
2221
...restProps
2322
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
2423
open?: boolean;
2524
onOpenChange?: (open: boolean) => void;
26-
controlledOpen?: boolean;
2725
} = $props();
2826
2927
const sidebar = setSidebar({
3028
open: () => open,
3129
setOpen: (value: boolean) => {
32-
if (controlledOpen) {
33-
onOpenChange(value);
34-
} else {
35-
open = value;
36-
onOpenChange(value);
37-
}
30+
open = value;
31+
onOpenChange(value);
3832
3933
// This sets the cookie to keep the sidebar state.
4034
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;

sites/docs/src/lib/registry/default/ui/sidebar/sidebar.svelte

+1-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@
3636
</div>
3737
{:else if sidebar.isMobile}
3838
<Sheet.Root
39-
controlledOpen
40-
open={sidebar.openMobile}
41-
onOpenChange={sidebar.setOpenMobile}
39+
bind:open={() => sidebar.openMobile, (v) => sidebar.setOpenMobile(v)}
4240
{...restProps}
4341
>
4442
<Sheet.Content

sites/docs/src/lib/registry/new-york/block/demo-sidebar-controlled.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
let open = $state(true);
4141
</script>
4242

43-
<Sidebar.Provider {open} controlledOpen onOpenChange={(value) => (open = value)}>
43+
<Sidebar.Provider bind:open={() => open, (v) => (open = v)}>
4444
<Sidebar.Root>
4545
<Sidebar.Content>
4646
<Sidebar.Group>

sites/docs/src/lib/registry/new-york/example/cards/data-table.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,8 @@
239239
{#each table.getAllColumns().filter((col) => col.getCanHide()) as column}
240240
<DropdownMenu.CheckboxItem
241241
class="capitalize"
242-
controlledChecked
243-
checked={column.getIsVisible()}
244-
onCheckedChange={(value) => column.toggleVisibility(!!value)}
242+
bind:checked={() => column.getIsVisible(),
243+
(v) => column.toggleVisibility(!!v)}
245244
>
246245
{column.id}
247246
</DropdownMenu.CheckboxItem>

sites/docs/src/lib/registry/new-york/example/data-table-demo.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,8 @@
245245
{#each table.getAllColumns().filter((col) => col.getCanHide()) as column}
246246
<DropdownMenu.CheckboxItem
247247
class="capitalize"
248-
controlledChecked
249-
checked={column.getIsVisible()}
250-
onCheckedChange={(value) => column.toggleVisibility(!!value)}
248+
bind:checked={() => column.getIsVisible(),
249+
(v) => column.toggleVisibility(!!v)}
251250
>
252251
{column.id}
253252
</DropdownMenu.CheckboxItem>

sites/docs/src/lib/registry/new-york/example/data-table/data-table-checkbox.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
55
let {
66
checked = false,
7-
controlledChecked = true,
7+
onCheckedChange = (v) => (checked = v),
88
...restProps
99
}: ComponentProps<typeof Checkbox> = $props();
1010
</script>
1111

12-
<Checkbox {checked} {controlledChecked} {...restProps} />
12+
<Checkbox bind:checked={() => checked, onCheckedChange} {...restProps} />

sites/docs/src/lib/registry/new-york/example/date-picker-with-presets.svelte

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@
4343
<Popover.Content class="flex w-auto flex-col space-y-2 p-2">
4444
<Select.Root
4545
type="single"
46-
value={valueString}
47-
controlledValue
48-
onValueChange={(v) => {
46+
bind:value={() => valueString,
47+
(v) => {
4948
if (!v) return;
5049
value = today(getLocalTimeZone()).add({ days: Number.parseInt(v) });
5150
}}

sites/docs/src/lib/registry/new-york/ui/sidebar/sidebar-provider.svelte

+2-8
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,20 @@
1515
ref = $bindable(null),
1616
open = $bindable(true),
1717
onOpenChange = () => {},
18-
controlledOpen = false,
1918
class: className,
2019
style,
2120
children,
2221
...restProps
2322
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
2423
open?: boolean;
2524
onOpenChange?: (open: boolean) => void;
26-
controlledOpen?: boolean;
2725
} = $props();
2826
2927
const sidebar = setSidebar({
3028
open: () => open,
3129
setOpen: (value: boolean) => {
32-
if (controlledOpen) {
33-
onOpenChange(value);
34-
} else {
35-
open = value;
36-
onOpenChange(value);
37-
}
30+
open = value;
31+
onOpenChange(value);
3832
3933
// This sets the cookie to keep the sidebar state.
4034
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;

sites/docs/src/lib/registry/new-york/ui/sidebar/sidebar.svelte

+1-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@
3636
</div>
3737
{:else if sidebar.isMobile}
3838
<Sheet.Root
39-
controlledOpen
40-
open={sidebar.openMobile}
41-
onOpenChange={sidebar.setOpenMobile}
39+
bind:open={() => sidebar.openMobile, (v) => sidebar.setOpenMobile(v)}
4240
{...restProps}
4341
>
4442
<Sheet.Content

sites/docs/src/routes/(app)/examples/tasks/(components)/data-table-checkbox.svelte

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
import type { Checkbox as CheckboxPrimitive, WithoutChildrenOrChild } from "bits-ui";
33
import { Checkbox } from "$lib/registry/new-york/ui/checkbox/index.js";
44
5-
let { checked, ...restProps }: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
5+
let {
6+
checked = false,
7+
onCheckedChange = (v) => (checked = v),
8+
...restProps
9+
}: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
610
</script>
711

8-
<Checkbox {checked} controlledChecked {...restProps} />
12+
<Checkbox bind:checked={() => checked, onCheckedChange} {...restProps} />

sites/docs/src/routes/(app)/examples/tasks/(components)/data-table-view-options.svelte

+1-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
.getAllColumns()
3131
.filter((col) => typeof col.accessorFn !== "undefined" && col.getCanHide()) as column}
3232
<DropdownMenu.CheckboxItem
33-
controlledChecked
34-
checked={column.getIsVisible()}
35-
onCheckedChange={(v) => column.toggleVisibility(!!v)}
33+
bind:checked={() => column.getIsVisible(), (v) => column.toggleVisibility(!!v)}
3634
class="capitalize"
3735
>
3836
{column.id}

0 commit comments

Comments
 (0)