Skip to content

Commit d0e6b41

Browse files
authored
fix: respect initial value prop in ButtonToggleGroup (#1796)
* fix: respect initial value prop in ButtonToggleGroup Previously the value prop was ignored during initialization. Now properly initializes selectedValues from the value prop, handling type mismatches between single/multi-select modes. * fix: clone arrays in getInitialValue to prevent aliasing Prevents external array mutations from affecting internal state. * fix: onSelect type update * fix: add type guards ensure type safety
1 parent 00114a7 commit d0e6b41

File tree

13 files changed

+120
-39
lines changed

13 files changed

+120
-39
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -855,4 +855,4 @@
855855
},
856856
"./package.json": "./package.json"
857857
}
858-
}
858+
}

src/lib/forms/button-toggle/ButtonToggleGroup.svelte

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,46 @@
55
import { buttonToggleGroup } from "./theme";
66
import { getTheme } from "$lib/theme/themeUtils";
77
8-
let { multiSelect = false, name = "toggle-group", value = multiSelect ? [] : null, color, size = "md", roundedSize = "md", onSelect = (val: any) => {}, children, ctxIconClass, ctxBtnClass, class: className, ...restProps }: ButtonToggleGroupProps = $props();
8+
let { multiSelect = false, name = "toggle-group", value = multiSelect ? [] : null, color, size = "md", roundedSize = "md", onSelect = () => {}, children, ctxIconClass, ctxBtnClass, class: className, ...restProps }: ButtonToggleGroupProps = $props();
99
1010
const theme = getTheme("buttonToggleGroup");
1111
1212
const base = $derived(buttonToggleGroup({ roundedSize, class: clsx(theme, className) }));
1313
type SelectedValue = string | null | string[];
1414
15-
let selectedValues = $state<SelectedValue>(multiSelect ? [] : null);
15+
// Normalize incoming prop `value` to internal SelectedValue
16+
// Clones arrays to prevent external mutations affecting internal state
17+
function getInitialValue(): SelectedValue {
18+
if (multiSelect) {
19+
// Multi-select mode expects array
20+
if (Array.isArray(value)) {
21+
return [...value]; // Clone to prevent aliasing
22+
} else if (value === null || value === undefined) {
23+
return [];
24+
} else {
25+
// Single string passed but multiSelect is true - wrap in array
26+
return [value as string];
27+
}
28+
} else {
29+
// Single-select mode expects string or null
30+
if (Array.isArray(value)) {
31+
// Array passed but multiSelect is false - take first item
32+
return value[0] ?? null;
33+
} else {
34+
return value;
35+
}
36+
}
37+
}
38+
39+
let selectedValues = $state<SelectedValue>(getInitialValue());
1640
1741
interface ButtonToggleContext {
1842
toggleSelected: (toggleValue: string) => void;
1943
isSelected: (toggleValue: string) => boolean;
2044
}
2145
22-
$effect(() => {
23-
value = selectedValues;
24-
onSelect(selectedValues);
25-
});
26-
2746
function toggleSelected(toggleValue: string) {
2847
if (multiSelect) {
29-
// Handle multi-select mode
3048
const currentSelected = [...(selectedValues as string[])];
3149
const index = currentSelected.indexOf(toggleValue);
3250
@@ -37,9 +55,9 @@
3755
selectedValues = currentSelected;
3856
}
3957
} else {
40-
// Handle single-select mode
4158
selectedValues = toggleValue === selectedValues ? null : toggleValue;
4259
}
60+
onSelect(selectedValues); // ✅ ADD THIS LINE - call onSelect here
4361
}
4462
4563
function isSelected(toggleValue: string): boolean {

src/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ export type ButtonToggleGroupProps = HTMLAttributes<HTMLDivElement> & {
327327
color?: ButtonToggleVariants["color"];
328328
size?: ButtonToggleVariants["size"];
329329
roundedSize?: ButtonToggleVariants["roundedSize"];
330-
onSelect?: (val: any) => void;
330+
onSelect?: (val: string | null | string[]) => void;
331331
children: Snippet;
332332
ctxIconClass?: ClassValue;
333333
ctxBtnClass?: ClassValue;

src/lib/typography/hr/Hr.svelte

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
innerDivClass: "content"
1616
}
1717
);
18-
const styling = $derived(classes ?? {
19-
div: divClass,
20-
content: innerDivClass
21-
});
18+
const styling = $derived(
19+
classes ?? {
20+
div: divClass,
21+
content: innerDivClass
22+
}
23+
);
2224
2325
const theme = getTheme("hr");
2426
const bg = classes?.bg ?? "bg-gray-200 dark:bg-gray-700";

src/routes/docs-examples/extend/button-toggle/ButtonColor.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
let singleValue = $state<string | null>(null);
55
let multiValues = $state<string[]>([]);
66
7-
function handleSingleSelect(value: string | null) {
8-
singleValue = value;
9-
console.log("Single selection:", value);
7+
function handleSingleSelect(value: string | null | string[]) {
8+
if (typeof value === "string" || value === null) {
9+
singleValue = value;
10+
console.log("Single selection:", value);
11+
}
1012
}
1113
</script>
1214

src/routes/docs-examples/extend/button-toggle/Ctx.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
44
let singleValue = $state<string | null>(null);
55
6-
function handleSingleSelect(value: string | null) {
7-
singleValue = value;
8-
console.log("Single selection:", value);
6+
function handleSingleSelect(value: string | null | string[]) {
7+
if (typeof value === "string" || value === null) {
8+
singleValue = value;
9+
console.log("Single selection:", value);
10+
}
911
}
1012
</script>
1113

src/routes/docs-examples/extend/button-toggle/Custom.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
55
let singleValue = $state<string | null>(null);
66
7-
function handleSingleSelect(value: string | null) {
8-
singleValue = value;
9-
console.log("Single selection:", value);
7+
function handleSingleSelect(value: string | null | string[]) {
8+
if (typeof value === "string" || value === null) {
9+
singleValue = value;
10+
console.log("Single selection:", value);
11+
}
1012
}
1113
</script>
1214

src/routes/docs-examples/extend/button-toggle/Default.svelte

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
let singleValue = $state<string | null>(null);
55
let multiValues = $state<string[]>([]);
66
7-
function handleSingleSelect(value: string | null) {
8-
singleValue = value;
9-
console.log("Single selection:", value);
7+
function handleSingleSelect(value: string | null | string[]) {
8+
if (typeof value === "string" || value === null) {
9+
singleValue = value;
10+
console.log("Single selection:", value);
11+
}
1012
}
1113
12-
function handleMultiSelect(values: string[]) {
13-
multiValues = values;
14-
console.log("Multi selection:", values);
14+
function handleMultiSelect(values: string | null | string[]) {
15+
if (Array.isArray(values)) {
16+
multiValues = values;
17+
console.log("Multi selection:", values);
18+
}
1519
}
1620
</script>
1721

src/routes/docs-examples/extend/button-toggle/Disabled.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
44
let singleValue = $state<string | null>(null);
55
6-
function handleSingleSelect(value: string | null) {
7-
singleValue = value;
8-
console.log("Single selection:", value);
6+
function handleSingleSelect(value: string | null | string[]) {
7+
if (typeof value === "string" || value === null) {
8+
singleValue = value;
9+
console.log("Single selection:", value);
10+
}
911
}
1012
</script>
1113

src/routes/docs-examples/extend/button-toggle/GroupColor.svelte

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
44
let singleValue = $state<string | null>(null);
55
6-
function handleSingleSelect(value: string | null) {
7-
singleValue = value;
8-
console.log("Single selection:", value);
6+
function handleSingleSelect(value: string | null | string[]) {
7+
if (typeof value === "string" || value === null) {
8+
singleValue = value;
9+
console.log("Single selection:", value);
10+
}
911
}
1012
</script>
1113

0 commit comments

Comments
 (0)