|
5 | 5 | import { buttonToggleGroup } from "./theme"; |
6 | 6 | import { getTheme } from "$lib/theme/themeUtils"; |
7 | 7 |
|
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(); |
9 | 9 |
|
10 | 10 | const theme = getTheme("buttonToggleGroup"); |
11 | 11 |
|
12 | 12 | const base = $derived(buttonToggleGroup({ roundedSize, class: clsx(theme, className) })); |
13 | 13 | type SelectedValue = string | null | string[]; |
14 | 14 |
|
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()); |
16 | 40 |
|
17 | 41 | interface ButtonToggleContext { |
18 | 42 | toggleSelected: (toggleValue: string) => void; |
19 | 43 | isSelected: (toggleValue: string) => boolean; |
20 | 44 | } |
21 | 45 |
|
22 | | - $effect(() => { |
23 | | - value = selectedValues; |
24 | | - onSelect(selectedValues); |
25 | | - }); |
26 | | -
|
27 | 46 | function toggleSelected(toggleValue: string) { |
28 | 47 | if (multiSelect) { |
29 | | - // Handle multi-select mode |
30 | 48 | const currentSelected = [...(selectedValues as string[])]; |
31 | 49 | const index = currentSelected.indexOf(toggleValue); |
32 | 50 |
|
|
37 | 55 | selectedValues = currentSelected; |
38 | 56 | } |
39 | 57 | } else { |
40 | | - // Handle single-select mode |
41 | 58 | selectedValues = toggleValue === selectedValues ? null : toggleValue; |
42 | 59 | } |
| 60 | + onSelect(selectedValues); // ✅ ADD THIS LINE - call onSelect here |
43 | 61 | } |
44 | 62 |
|
45 | 63 | function isSelected(toggleValue: string): boolean { |
|
0 commit comments