diff --git a/packages/bits-ui/package.json b/packages/bits-ui/package.json index 072ae50c1..1bc2a30c4 100644 --- a/packages/bits-ui/package.json +++ b/packages/bits-ui/package.json @@ -63,6 +63,7 @@ "clsx": "^2.1.0", "esm-env": "^1.0.0", "nanoid": "^5.0.5", + "runed": "^0.1.0", "scule": "^1.3.0", "style-object-to-css-string": "^1.1.3", "style-to-object": "^1.0.6" diff --git a/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts b/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts index 1cb98203f..565700e52 100644 --- a/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts +++ b/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts @@ -1,9 +1,8 @@ -import { getContext, setContext } from "svelte"; +import type { WritableBox } from "runed"; import { type Box, - type BoxedValues, - type ReadonlyBox, - type ReadonlyBoxedValues, + type ReadableBoxedValues, + type WritableBoxedValues, afterTick, getAriaDisabled, getAriaExpanded, @@ -13,7 +12,6 @@ import { getDataOrientation, kbd, useNodeById, - verifyContextDeps, } from "$lib/internal/index.js"; import { type UseRovingFocusReturn, useRovingFocus } from "$lib/internal/useRovingFocus.svelte.js"; import type { Orientation } from "$lib/shared/index.js"; @@ -29,7 +27,7 @@ const HEADER_ATTR = "accordion-header"; // BASE // -type AccordionBaseStateProps = ReadonlyBoxedValues<{ +type AccordionBaseStateProps = ReadableBoxedValues<{ id: string; disabled: boolean; orientation: Orientation; @@ -37,9 +35,9 @@ type AccordionBaseStateProps = ReadonlyBoxedValues<{ }>; class AccordionBaseState { - id = undefined as unknown as ReadonlyBox; - node: Box; - disabled = undefined as unknown as ReadonlyBox; + id = undefined as unknown as AccordionBaseStateProps["id"]; + node: WritableBox; + disabled = undefined as unknown as AccordionBaseStateProps["disabled"]; #loop = undefined as unknown as AccordionBaseStateProps["loop"]; orientation = undefined as unknown as AccordionBaseStateProps["orientation"]; rovingFocusGroup = undefined as unknown as UseRovingFocusReturn; @@ -71,10 +69,10 @@ class AccordionBaseState { // SINGLE // -type AccordionSingleStateProps = AccordionBaseStateProps & BoxedValues<{ value: string }>; +type AccordionSingleStateProps = AccordionBaseStateProps & WritableBoxedValues<{ value: string }>; export class AccordionSingleState extends AccordionBaseState { - #value: Box; + #value: AccordionSingleStateProps["value"]; isMulti = false as const; constructor(props: AccordionSingleStateProps) { @@ -95,10 +93,10 @@ export class AccordionSingleState extends AccordionBaseState { // MULTIPLE // -type AccordionMultiStateProps = AccordionBaseStateProps & BoxedValues<{ value: string[] }>; +type AccordionMultiStateProps = AccordionBaseStateProps & WritableBoxedValues<{ value: string[] }>; export class AccordionMultiState extends AccordionBaseState { - #value: Box; + #value: AccordionMultiStateProps["value"]; isMulti = true as const; constructor(props: AccordionMultiStateProps) { @@ -123,7 +121,7 @@ export class AccordionMultiState extends AccordionBaseState { // ITEM // -type AccordionItemStateProps = ReadonlyBoxedValues<{ +type AccordionItemStateProps = ReadableBoxedValues<{ value: string; disabled: boolean; }> & { @@ -131,8 +129,8 @@ type AccordionItemStateProps = ReadonlyBoxedValues<{ }; export class AccordionItemState { - value = undefined as unknown as ReadonlyBox; - disabled = undefined as unknown as ReadonlyBox; + value = undefined as unknown as AccordionItemStateProps["value"]; + disabled = undefined as unknown as AccordionItemStateProps["disabled"]; root = undefined as unknown as AccordionState; isSelected = $derived(this.root.includesItem(this.value.value)); isDisabled = $derived(this.disabled.value || this.root.disabled.value); @@ -170,14 +168,14 @@ export class AccordionItemState { // TRIGGER // -type AccordionTriggerStateProps = ReadonlyBoxedValues<{ +type AccordionTriggerStateProps = ReadableBoxedValues<{ disabled: boolean; id: string; }>; class AccordionTriggerState { - #disabled = undefined as unknown as ReadonlyBox; - #id = undefined as unknown as ReadonlyBox; + #disabled = undefined as unknown as AccordionTriggerStateProps["disabled"]; + #id = undefined as unknown as AccordionTriggerStateProps["id"]; #node: Box; #root = undefined as unknown as AccordionState; #itemState = undefined as unknown as AccordionItemState; @@ -229,20 +227,20 @@ class AccordionTriggerState { // CONTENT // -type AccordionContentStateProps = ReadonlyBoxedValues<{ +type AccordionContentStateProps = ReadableBoxedValues<{ forceMount: boolean; id: string; }>; class AccordionContentState { item = undefined as unknown as AccordionItemState; - node: Box; - #id = undefined as unknown as ReadonlyBox; + node: WritableBox; + #id = undefined as unknown as AccordionContentStateProps["id"]; #originalStyles: { transitionDuration: string; animationName: string } | undefined = undefined; #isMountAnimationPrevented = false; #width = $state(0); #height = $state(0); - #forceMount = undefined as unknown as ReadonlyBox; + #forceMount = undefined as unknown as AccordionContentStateProps["forceMount"]; present = $derived(this.#forceMount.value || this.item.isSelected); @@ -309,7 +307,7 @@ class AccordionContentState { } as const); } -type AccordionHeaderStateProps = ReadonlyBoxedValues<{ +type AccordionHeaderStateProps = ReadableBoxedValues<{ level: 1 | 2 | 3 | 4 | 5 | 6; }>; @@ -340,7 +338,7 @@ type AccordionState = AccordionSingleState | AccordionMultiState; type InitAccordionProps = { type: "single" | "multiple"; value: Box | Box; -} & ReadonlyBoxedValues<{ +} & ReadableBoxedValues<{ id: string; disabled: boolean; orientation: Orientation; diff --git a/packages/bits-ui/src/lib/bits/accordion/components/accordion-content.svelte b/packages/bits-ui/src/lib/bits/accordion/components/accordion-content.svelte index 5343998c5..6b4e583bc 100644 --- a/packages/bits-ui/src/lib/bits/accordion/components/accordion-content.svelte +++ b/packages/bits-ui/src/lib/bits/accordion/components/accordion-content.svelte @@ -1,8 +1,9 @@ diff --git a/packages/bits-ui/src/lib/bits/accordion/components/accordion-header.svelte b/packages/bits-ui/src/lib/bits/accordion/components/accordion-header.svelte index 52db61597..74719a9ff 100644 --- a/packages/bits-ui/src/lib/bits/accordion/components/accordion-header.svelte +++ b/packages/bits-ui/src/lib/bits/accordion/components/accordion-header.svelte @@ -1,8 +1,8 @@ diff --git a/packages/bits-ui/src/lib/bits/collapsible/components/collapsible.svelte b/packages/bits-ui/src/lib/bits/collapsible/components/collapsible.svelte index e46333d00..b061a7d49 100644 --- a/packages/bits-ui/src/lib/bits/collapsible/components/collapsible.svelte +++ b/packages/bits-ui/src/lib/bits/collapsible/components/collapsible.svelte @@ -1,7 +1,7 @@ diff --git a/packages/bits-ui/src/lib/bits/popover/components/popover-trigger.svelte b/packages/bits-ui/src/lib/bits/popover/components/popover-trigger.svelte index b89e8918d..77896f0da 100644 --- a/packages/bits-ui/src/lib/bits/popover/components/popover-trigger.svelte +++ b/packages/bits-ui/src/lib/bits/popover/components/popover-trigger.svelte @@ -1,7 +1,8 @@ diff --git a/packages/bits-ui/src/lib/bits/utilities/dismissable-layer/useDismissableLayer.svelte.ts b/packages/bits-ui/src/lib/bits/utilities/dismissable-layer/useDismissableLayer.svelte.ts index 8375c5327..302f883ba 100644 --- a/packages/bits-ui/src/lib/bits/utilities/dismissable-layer/useDismissableLayer.svelte.ts +++ b/packages/bits-ui/src/lib/bits/utilities/dismissable-layer/useDismissableLayer.svelte.ts @@ -1,4 +1,5 @@ import { untrack } from "svelte"; +import type { ReadableBox } from "runed"; import type { DismissableLayerImplProps, DismissableLayerProps, @@ -9,8 +10,7 @@ import type { import { type Box, type EventCallback, - type ReadonlyBox, - type ReadonlyBoxedValues, + type ReadableBoxedValues, addEventListener, composeHandlers, debounce, @@ -22,7 +22,7 @@ import { useNodeById, } from "$lib/internal/index.js"; -const layers = new Map>(); +const layers = new Map>(); const interactOutsideStartEvents = [ "pointerdown", @@ -36,14 +36,14 @@ const interactOutsideEndEvents = [ "click", ] satisfies InteractOutsideInterceptEventType[]; -type DismissableLayerStateProps = ReadonlyBoxedValues< +type DismissableLayerStateProps = ReadableBoxedValues< Required> >; export class DismissableLayerState { - #interactOutsideStartProp: ReadonlyBox>; - #interactOutsideProp: ReadonlyBox>; - #behaviorType: ReadonlyBox; + #interactOutsideStartProp: ReadableBox>; + #interactOutsideProp: ReadableBox>; + #behaviorType: ReadableBox; #interceptedEvents: Record = { pointerdown: false, pointerup: false, @@ -57,7 +57,7 @@ export class DismissableLayerState { #isResponsibleLayer = false; node: Box; #documentObj = undefined as unknown as Document; - #present: ReadonlyBox; + #present: ReadableBox; constructor(props: DismissableLayerStateProps) { this.node = useNodeById(props.id); diff --git a/packages/bits-ui/src/lib/bits/utilities/escape-layer/escape-layer.svelte b/packages/bits-ui/src/lib/bits/utilities/escape-layer/escape-layer.svelte index 56cb8c6d8..69e38aad1 100644 --- a/packages/bits-ui/src/lib/bits/utilities/escape-layer/escape-layer.svelte +++ b/packages/bits-ui/src/lib/bits/utilities/escape-layer/escape-layer.svelte @@ -1,7 +1,8 @@ diff --git a/packages/bits-ui/src/lib/bits/utilities/escape-layer/useEscapeLayer.svelte.ts b/packages/bits-ui/src/lib/bits/utilities/escape-layer/useEscapeLayer.svelte.ts index 71395df82..a9511e365 100644 --- a/packages/bits-ui/src/lib/bits/utilities/escape-layer/useEscapeLayer.svelte.ts +++ b/packages/bits-ui/src/lib/bits/utilities/escape-layer/useEscapeLayer.svelte.ts @@ -1,18 +1,19 @@ import { untrack } from "svelte"; +import type { ReadableBox } from "runed"; import type { EscapeBehaviorType, EscapeLayerImplProps } from "./types.js"; -import type { ReadonlyBox, ReadonlyBoxedValues } from "$lib/internal/box.svelte.js"; +import type { ReadableBoxedValues } from "$lib/internal/box.svelte.js"; import { type EventCallback, addEventListener } from "$lib/internal/events.js"; import { kbd } from "$lib/internal/kbd.js"; import { noop } from "$lib/internal/callbacks.js"; -const layers = new Map>(); +const layers = new Map>(); -type EscapeLayerStateProps = ReadonlyBoxedValues>>; +type EscapeLayerStateProps = ReadableBoxedValues>>; export class EscapeLayerState { - #onEscapeProp: ReadonlyBox>; - #behaviorType: ReadonlyBox; - #present: ReadonlyBox; + #onEscapeProp: ReadableBox>; + #behaviorType: ReadableBox; + #present: ReadableBox; constructor(props: EscapeLayerStateProps) { this.#behaviorType = props.behaviorType; diff --git a/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-anchor.svelte b/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-anchor.svelte index 0f70e1cff..dbae6eed7 100644 --- a/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-anchor.svelte +++ b/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-anchor.svelte @@ -1,11 +1,11 @@ {@render children?.()} diff --git a/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-arrow.svelte b/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-arrow.svelte index 21207094e..40a49bdc3 100644 --- a/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-arrow.svelte +++ b/packages/bits-ui/src/lib/bits/utilities/floating-layer/components/floating-layer-arrow.svelte @@ -1,12 +1,13 @@ diff --git a/packages/bits-ui/src/lib/bits/utilities/focus-scope/useFocusScope.svelte.ts b/packages/bits-ui/src/lib/bits/utilities/focus-scope/useFocusScope.svelte.ts index f3ba1b416..188e062d4 100644 --- a/packages/bits-ui/src/lib/bits/utilities/focus-scope/useFocusScope.svelte.ts +++ b/packages/bits-ui/src/lib/bits/utilities/focus-scope/useFocusScope.svelte.ts @@ -13,7 +13,7 @@ import { getTabbableCandidates, getTabbableEdges, } from "./utils.js"; -import { type ReadonlyBoxedValues, boxedState } from "$lib/internal/box.svelte.js"; +import type { ReadableBoxedValues } from "$lib/internal/box.svelte.js"; import { type EventCallback, addEventListener } from "$lib/internal/events.js"; import { useNodeById } from "$lib/internal/useNodeById.svelte.js"; import { isHTMLElement } from "$lib/internal/is.js"; @@ -21,7 +21,7 @@ import { executeCallbacks } from "$lib/internal/callbacks.js"; import { kbd } from "$lib/internal/kbd.js"; import { afterTick } from "$lib/internal/after-tick.js"; -type UseFocusScopeProps = ReadonlyBoxedValues<{ +type UseFocusScopeProps = ReadableBoxedValues<{ /** * ID of the focus scope container node. */ diff --git a/packages/bits-ui/src/lib/bits/utilities/presence-layer/presence-layer.svelte b/packages/bits-ui/src/lib/bits/utilities/presence-layer/presence-layer.svelte index dc39a2be4..2d613da02 100644 --- a/packages/bits-ui/src/lib/bits/utilities/presence-layer/presence-layer.svelte +++ b/packages/bits-ui/src/lib/bits/utilities/presence-layer/presence-layer.svelte @@ -1,13 +1,13 @@ diff --git a/packages/bits-ui/src/lib/bits/utilities/presence-layer/usePresence.svelte.ts b/packages/bits-ui/src/lib/bits/utilities/presence-layer/usePresence.svelte.ts index 0ded3a091..f8dcc9e23 100644 --- a/packages/bits-ui/src/lib/bits/utilities/presence-layer/usePresence.svelte.ts +++ b/packages/bits-ui/src/lib/bits/utilities/presence-layer/usePresence.svelte.ts @@ -1,10 +1,11 @@ import { onDestroy } from "svelte"; -import { type Box, type ReadonlyBox, boxedState, watch } from "../../../internal/box.svelte.js"; +import { type ReadableBox, type WritableBox, box } from "runed"; +import { watch } from "$lib/internal/box.svelte.js"; import { afterTick, useStateMachine } from "$lib/internal/index.js"; -export function usePresence(present: ReadonlyBox, id: ReadonlyBox) { - const styles = boxedState({}) as unknown as Box; - const prevAnimationNameState = boxedState("none"); +export function usePresence(present: ReadableBox, id: ReadableBox) { + const styles = box({}) as unknown as WritableBox; + const prevAnimationNameState = box("none"); const initialState = present.value ? "mounted" : "unmounted"; let node = $state(null); diff --git a/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/text-selection-layer.svelte b/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/text-selection-layer.svelte index 881bfebea..cf75d7fe4 100644 --- a/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/text-selection-layer.svelte +++ b/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/text-selection-layer.svelte @@ -1,7 +1,8 @@ diff --git a/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/useTextSelectionLayer.svelte.ts b/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/useTextSelectionLayer.svelte.ts index 77494d4fe..6fd334d6c 100644 --- a/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/useTextSelectionLayer.svelte.ts +++ b/packages/bits-ui/src/lib/bits/utilities/text-selection-layer/useTextSelectionLayer.svelte.ts @@ -1,10 +1,9 @@ import { untrack } from "svelte"; +import type { ReadableBox, WritableBox } from "runed"; import type { TextSelectionLayerImplProps, TextSelectionLayerProps } from "./types.js"; import { - type Box, type EventCallback, - type ReadonlyBox, - type ReadonlyBoxedValues, + type ReadableBoxedValues, addEventListener, composeHandlers, executeCallbacks, @@ -14,17 +13,17 @@ import { useNodeById, } from "$lib/internal/index.js"; -type StateProps = ReadonlyBoxedValues>>; +type StateProps = ReadableBoxedValues>>; -const layers = new Map>(); +const layers = new Map>(); export class TextSelectionLayerState { - #onPointerDownProp: ReadonlyBox>; - #onPointerUpProp: ReadonlyBox>; - #enabled: ReadonlyBox; + #onPointerDownProp: ReadableBox>; + #onPointerUpProp: ReadableBox>; + #enabled: ReadableBox; #unsubSelectionLock = noop; - #node: Box; - #present: ReadonlyBox; + #node: WritableBox; + #present: ReadableBox; constructor(props: StateProps) { this.#node = useNodeById(props.id); diff --git a/packages/bits-ui/src/lib/internal/box.svelte.ts b/packages/bits-ui/src/lib/internal/box.svelte.ts index bef7b36b7..fcb8bab31 100644 --- a/packages/bits-ui/src/lib/internal/box.svelte.ts +++ b/packages/bits-ui/src/lib/internal/box.svelte.ts @@ -1,4 +1,7 @@ import { untrack } from "svelte"; +import type { ReadableBox, WritableBox } from "runed"; + +export type Box = ReadableBox | WritableBox; export type Setter = (value: T) => void; export type Getter = () => T; @@ -20,41 +23,7 @@ type WatchOptions = { once?: boolean; }; -export class ReadonlyBox { - #get: Getter = $state() as Getter; - - constructor(get: Getter) { - this.#get = get; - } - - get value() { - return this.#get(); - } -} - -export class Box { - #set = $state() as Setter; - #get = $state() as Getter; - - constructor(get: Getter, set: Setter) { - this.#set = set; - this.#get = get; - } - - get value() { - return this.#get(); - } - - set value(value: T) { - this.#set(value); - } -} - -export function watch( - box: ReadonlyBox | Box, - callback: WatcherCallback, - options: WatchOptions = {} -) { +export function watch(box: Box, callback: WatcherCallback, options: WatchOptions = {}) { let prev = $state(box.value); let ranOnce = false; @@ -85,31 +54,10 @@ export function watch( return watchEffect; } -export function box(get: Getter, set: Setter) { - return new Box(get, set); -} - -export function readonlyBox(get: Getter) { - return new ReadonlyBox(get); -} - -export function boxedState(initialValue: T) { - let state = $state(initialValue); - return box( - () => state, - (value) => (state = value) - ); -} - -export function readonlyBoxedState(initialValue: T) { - let state = $state(initialValue); - return readonlyBox(() => state); -} - -export type BoxedValues = { - [K in keyof T]: Box; +export type WritableBoxedValues = { + [K in keyof T]: WritableBox; }; -export type ReadonlyBoxedValues = { - [K in keyof T]: ReadonlyBox; +export type ReadableBoxedValues = { + [K in keyof T]: ReadableBox; }; diff --git a/packages/bits-ui/src/lib/internal/floating-svelte/arrow.ts b/packages/bits-ui/src/lib/internal/floating-svelte/arrow.ts index 345988e67..0643dcb72 100644 --- a/packages/bits-ui/src/lib/internal/floating-svelte/arrow.ts +++ b/packages/bits-ui/src/lib/internal/floating-svelte/arrow.ts @@ -1,7 +1,7 @@ import type { Derivable, Middleware, Padding } from "@floating-ui/dom"; import { arrow as arrowCore } from "@floating-ui/dom"; import type { MiddlewareState } from "@floating-ui/core"; -import type { Box } from "../box.svelte.js"; +import { type WritableBox, box } from "runed"; import { isElement } from "../is.js"; export type ArrowOptions = { @@ -9,7 +9,7 @@ export type ArrowOptions = { * The arrow element to be positioned. * @default undefined */ - element: Box | Element | null; + element: WritableBox | Element | null; /** * The padding between the arrow element and the floating element edges. @@ -28,17 +28,13 @@ export type ArrowOptions = { */ export function arrow(options: ArrowOptions | Derivable): Middleware { - function isBox(value: unknown): value is Box { - return {}.hasOwnProperty.call(value, "value"); - } - return { name: "arrow", options, fn(state: MiddlewareState) { const { element, padding } = typeof options === "function" ? options(state) : options; - if (element && isBox(element)) { + if (element && box.isBox(element)) { if (element.value !== null) { return arrowCore({ element: element.value, padding }).fn(state); } diff --git a/packages/bits-ui/src/lib/internal/floating-svelte/types.ts b/packages/bits-ui/src/lib/internal/floating-svelte/types.ts index b78c4a3a1..918fd6348 100644 --- a/packages/bits-ui/src/lib/internal/floating-svelte/types.ts +++ b/packages/bits-ui/src/lib/internal/floating-svelte/types.ts @@ -7,7 +7,7 @@ import type { Strategy, } from "@floating-ui/dom"; import type { VirtualElement } from "@floating-ui/core"; -import type { Box } from "../box.svelte.js"; +import type { WritableBox } from "runed"; type ValueOrGetValue = T | (() => T); @@ -45,7 +45,7 @@ export type UseFloatingOptions = { /** * Reference / Anchor element to position the floating element relative to */ - reference: Box; + reference: WritableBox; /** * Callback to handle mounting/unmounting of the elements. @@ -62,11 +62,11 @@ export type UseFloatingReturn = { /** * The action used to obtain the reference element. */ - reference: Box; + reference: WritableBox; /** * The action used to obtain the floating element. */ - floating: Box; + floating: WritableBox; /** * The stateful placement, which can be different from the initial `placement` passed as options. */ diff --git a/packages/bits-ui/src/lib/internal/floating-svelte/useFloating.svelte.ts b/packages/bits-ui/src/lib/internal/floating-svelte/useFloating.svelte.ts index 697d95f7a..17df01697 100644 --- a/packages/bits-ui/src/lib/internal/floating-svelte/useFloating.svelte.ts +++ b/packages/bits-ui/src/lib/internal/floating-svelte/useFloating.svelte.ts @@ -1,5 +1,5 @@ import { computePosition } from "@floating-ui/dom"; -import { boxedState } from "../box.svelte.js"; +import { box } from "runed"; import type { UseFloatingOptions, UseFloatingReturn } from "./types.js"; import { get, getDPR, roundByDPR } from "./utils.js"; @@ -17,7 +17,7 @@ export function useFloating(options: UseFloatingOptions): UseFloatingReturn { let x = $state(0); let y = $state(0); - const floating = boxedState(null); + const floating = box(null); let strategy = $state(strategyOption); let placement = $state(placementOption); diff --git a/packages/bits-ui/src/lib/internal/useBodyScrollLock.svelte.ts b/packages/bits-ui/src/lib/internal/useBodyScrollLock.svelte.ts index 0191ea1e7..51d83917b 100644 --- a/packages/bits-ui/src/lib/internal/useBodyScrollLock.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useBodyScrollLock.svelte.ts @@ -1,8 +1,9 @@ import { Map } from "svelte/reactivity"; import { onDestroy } from "svelte"; +import { box } from "runed"; import type { Fn } from "./types.js"; import { isBrowser, isIOS } from "./is.js"; -import { box, readonlyBox, watch } from "./box.svelte.js"; +import { watch } from "./box.svelte.js"; import { addEventListener } from "./events.js"; import { afterTick } from "./after-tick.js"; import { useId } from "./useId.svelte.js"; @@ -39,7 +40,7 @@ const useBodyLockStackCount = createSharedHook(() => { } watch( - readonlyBox(() => locked), + box.with(() => locked), (curr, prev) => { if (!curr) { if (prev) { @@ -104,7 +105,7 @@ export function useBodyScrollLock(initialState?: boolean | undefined) { map.set(id, initialState ?? false); - const locked = box( + const locked = box.with( () => map.get(id) ?? false, (v) => map.set(id, v) ); diff --git a/packages/bits-ui/src/lib/internal/useId.svelte.ts b/packages/bits-ui/src/lib/internal/useId.svelte.ts index 8619252f3..b3090ac22 100644 --- a/packages/bits-ui/src/lib/internal/useId.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useId.svelte.ts @@ -1,5 +1,6 @@ class Counter { - value = $state(0); + value = 0; + constructor(initialValue: number = 0) { this.value = initialValue; } diff --git a/packages/bits-ui/src/lib/internal/useNodeById.svelte.ts b/packages/bits-ui/src/lib/internal/useNodeById.svelte.ts index 27f11d0b9..12ce4b7a3 100644 --- a/packages/bits-ui/src/lib/internal/useNodeById.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useNodeById.svelte.ts @@ -1,4 +1,4 @@ -import { type Box, type ReadonlyBox, boxedState } from "./box.svelte.js"; +import { type ReadableBox, type WritableBox, box } from "runed"; import { afterTick } from "./after-tick.js"; /** @@ -8,8 +8,8 @@ import { afterTick } from "./after-tick.js"; * * @param id The boxed ID of the node to find. */ -export function useNodeById(id: ReadonlyBox | Box) { - const node = boxedState(null); +export function useNodeById(id: ReadableBox | WritableBox) { + const node = box(null); $effect.pre(() => { // eslint-disable-next-line no-unused-expressions diff --git a/packages/bits-ui/src/lib/internal/useRovingFocus.svelte.ts b/packages/bits-ui/src/lib/internal/useRovingFocus.svelte.ts index 409d56764..067fb70fa 100644 --- a/packages/bits-ui/src/lib/internal/useRovingFocus.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useRovingFocus.svelte.ts @@ -1,4 +1,4 @@ -import { type Box, type ReadonlyBox, box, boxedState } from "./box.svelte.js"; +import type { ReadableBox, WritableBox } from "runed"; import { getElemDirection } from "./locale.js"; import { getDirectionalKeys } from "./getDirectionalKeys.js"; import { kbd } from "./kbd.js"; @@ -13,18 +13,18 @@ type UseRovingFocusProps = { /** * The root node which contains the focusable candidates. */ - rootNode: Box; + rootNode: WritableBox; /** * Whether to loop through the candidates when reaching the end. */ - loop: ReadonlyBox; + loop: ReadableBox; /** * The orientation of the roving focus group. Used * to determine how keyboard navigation should work. */ - orientation: ReadonlyBox; + orientation: ReadableBox; /** * A callback function called when a candidate is focused. diff --git a/packages/bits-ui/src/lib/internal/useSize.svelte.ts b/packages/bits-ui/src/lib/internal/useSize.svelte.ts index 8e8cd720f..03274402b 100644 --- a/packages/bits-ui/src/lib/internal/useSize.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useSize.svelte.ts @@ -1,10 +1,10 @@ /// import { untrack } from "svelte"; -import type { Box } from "./box.svelte.js"; +import type { WritableBox } from "runed"; import { afterTick } from "./after-tick.js"; -export function useSize(node: Box) { +export function useSize(node: WritableBox) { let size = $state<{ width: number; height: number } | undefined>(undefined); $effect(() => { diff --git a/packages/bits-ui/src/lib/internal/useStateMachine.svelte.ts b/packages/bits-ui/src/lib/internal/useStateMachine.svelte.ts index dfd3351ec..7b7b7083d 100644 --- a/packages/bits-ui/src/lib/internal/useStateMachine.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useStateMachine.svelte.ts @@ -1,4 +1,4 @@ -import { boxedState } from "./box.svelte.js"; +import { box } from "runed"; interface Machine { [k: string]: { [k: string]: S }; @@ -30,7 +30,7 @@ export function useStateMachine( initialState: MachineState, machine: M & Machine> ) { - const state = boxedState(initialState); + const state = box(initialState); function reducer(event: MachineEvent) { // @ts-expect-error state.value is keyof M diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b2b2af8a..28dd40319 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ importers: nanoid: specifier: ^5.0.5 version: 5.0.6 + runed: + specifier: ^0.1.0 + version: 0.1.0(svelte@5.0.0-next.113) scule: specifier: ^1.3.0 version: 1.3.0 @@ -8392,6 +8395,15 @@ packages: queue-microtask: 1.2.3 dev: true + /runed@0.1.0(svelte@5.0.0-next.113): + resolution: {integrity: sha512-AoTFTD02SDLBic5eHenztQ37RS1/7az9v75N9Eosd8IzWs4aT28E6/fUbfkfGY5FrnzzRMWjCEOqN3AChrZ2xg==} + peerDependencies: + svelte: ^5.0.0 + dependencies: + nanoid: 5.0.6 + svelte: 5.0.0-next.113 + dev: false + /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: