Skip to content

Commit

Permalink
add box helper
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte committed Apr 13, 2024
1 parent 567f406 commit 41a0458
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { getContext, setContext } from "svelte";
import {
type Box,
type EventCallback,
type OnChangeFn,
box,
composeHandlers,
dataDisabledAttrs,
generateId,
Expand Down Expand Up @@ -49,50 +51,54 @@ class AccordionBaseState {
*/

interface AccordionSingleStateProps extends AccordionBaseStateProps {
value?: string;
value?: Box<string>;
onValueChange?: OnChangeFn<string>;
id?: string | null;
}

export class AccordionSingleState extends AccordionBaseState {
value: string = $state("");
onValueChange: OnChangeFn<string> = () => {};
#value = box(() => "");
isMulti = false as const;

constructor(props: AccordionSingleStateProps) {
super(props);

this.value = props.value ?? this.value;
this.onValueChange = props.onValueChange ?? this.onValueChange;
this.#value = props.value ?? this.#value;
}

$effect.pre(() => {
this.onValueChange?.(this.value);
});
get value() {
return this.#value.value;
}

set value(v: string) {
this.#value.value = v;
}
}

/**
* MULTIPLE
*/
interface AccordionMultiStateProps extends AccordionBaseStateProps {
value?: string[];
onValueChange?: OnChangeFn<string[]>;
value?: Box<string[]>;
}

export class AccordionMultiState extends AccordionBaseState {
value: string[] = $state([]);
#value = box<string[]>(() => []);
onValueChange: OnChangeFn<string[]> = () => {};
isMulti = true as const;

constructor(props: AccordionMultiStateProps) {
super(props);

this.value = props.value ?? this.value;
this.onValueChange = props.onValueChange ?? this.onValueChange;
this.#value = props.value ?? this.#value;
}

$effect.pre(() => {
this.onValueChange?.(this.value);
});
get value() {
return this.#value.value;
}

set value(v: string[]) {
this.#value.value = v;
}
}

Expand Down Expand Up @@ -138,7 +144,7 @@ export class AccordionItemState {
if (this.root.value.includes(this.value)) {
this.root.value = this.root.value.filter((v) => v !== this.value);
} else {
this.root.value.push(this.value);
this.root.value = [...this.root.value, this.value];
}
} else {
if (this.root.value === this.value) {
Expand Down Expand Up @@ -276,7 +282,7 @@ class AccordionTriggerState {
*/

class AccordionContentState {
item: AccordionItemState = $state() as AccordionItemState;
item = undefined as unknown as AccordionItemState;
attrs: Record<string, unknown> = $derived({
"data-state": openClosedAttrs(this.item.isSelected),
"data-disabled": dataDisabledAttrs(this.item.root.disabled || this.item.disabled),
Expand Down Expand Up @@ -304,7 +310,7 @@ type AccordionState = AccordionSingleState | AccordionMultiState;

type InitAccordionProps = {
type: "single" | "multiple";
value?: string | string[];
value: Box<string> | Box<string[]>;
id?: string | null;
onValueChange?: OnChangeFn<string> | OnChangeFn<string[]>;
};
Expand All @@ -313,14 +319,12 @@ export function setAccordionRootState(props: InitAccordionProps) {
const rootState =
props.type === "single"
? new AccordionSingleState({
value: props.value as string,
value: props.value as Box<string>,
id: props.id,
onValueChange: props.onValueChange as OnChangeFn<string>,
})
: new AccordionMultiState({
value: props.value as string[],
value: props.value as Box<string[]>,
id: props.id,
onValueChange: props.onValueChange as OnChangeFn<string[]>,
});
setContext(ACCORDION_ROOT_KEY, rootState);
return rootState;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { setAccordionRootState } from "../state.svelte.js";
import { setAccordionRootState } from "../accordion.svelte.js";
import type { AccordionRootProps } from "../types.js";
import { box } from "$lib/internal/box.svelte.js";
let {
disabled = false,
Expand All @@ -16,7 +17,24 @@
...restProps
}: AccordionRootProps = $props();
const rootState = setAccordionRootState({ type, value, id, onValueChange });
function createValueState() {
if (type === "single") {
value === undefined && (value = "");
return box(
() => value as string,
(v) => (value = v)
);
}
value === undefined && (value = []);
return box(
() => value as string[],
(v) => (value = v)
);
}
const valueState = createValueState();
const rootState = setAccordionRootState({ type, value: valueState, id, onValueChange });
$effect.pre(() => {
if (value !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion packages/bits-ui/src/lib/internal/box.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ export class Box<T> {
}
}

export function box<T>(get: Getter<T>, set: Setter<T>) {
export function box<T>(get: Getter<T>, set: Setter<T> = () => {}) {
return new Box(get, set);
}

0 comments on commit 41a0458

Please sign in to comment.